二进制入门及静态分析基础
HACKing三部曲
- 理解系统
- 系统性的基础课程学习,深入理解计算机系统的运作机制
- 破坏系统
- 学习与创作漏洞挖掘与利用技巧
- 重构系统
- 设计与构建系统防护
《汇编语言》
《c++反汇编与逆向分析技术揭秘》》
《加密与解密4》?
《恶意代码分析实战》
《0day安全:软件漏洞分析技术》
《漏洞战争》
fuzz test 模糊测试
PE文件格式
PE文件(Portable Executable)
常见的可执行文件如.exe和.dll文件都是典型的PE文件
PE文件格式把可执行文件分成若干个数据节,不同的资源被放在不同的节中。
- .text 包含了CPU执行指令,所有其他节存储数据和支持性信息。一般来说这是唯一可以执行的节,也应该是唯一包含代码的节。
- .rdata通常包含导入与导出函数信息,与Dependency Walker和PEview工具所获得的信息是相同的,这个节中还可以存储程序所使用的其他只读函数。有些文件还会包含.idata和edata节来存储导入导出信息。
- .data 初始化的数据块,如宏定义,全局变量,静态变量
- .idata 可执行文件所使用的动态链接库等外来函数与文件的信息
- .rsrc 存放程序的资源,如图标菜单
- .reloc
- .edata
- .tls
- .rdata
内存
windows的内存被分为两个层面:物理内存和虚拟内存。其中,物理内存十分复杂,需要进入windows的内核级别ring0才可以看到。通常在用户模式下,我们用调试器看到的内存地址都是虚拟内存。
PE文件与虚拟内存之间的映射
-
静态反汇编工具看到的PE文件中某条指令的位置是相对于磁盘文件而言的,即所谓的文件偏移,我们可能还需要知道这条指令在内存中所处的位置,即虚拟内存地址。
-
反之,在调试时看到某条指令的地址是虚拟内存地址,我们也经常回到PE文件中找到这条指令对应的机器码。
-
文件偏移地址(File Offset):数据在PE文件中的地址叫文件偏移地址,这是文件在磁盘上存放时相对于文件开头的偏移。(文件地址)
-
装载地址(Image Base):PE装入内存时的基地址。默认情况下,EXE文件在内存中的基地址为0x00400000, DLL文件基地址为0x10000000,装载地址可以进行修改。
-
虚拟内存地址(VA):PE文件中指令被装入内存后的地址。
-
相对虚拟地址(RVA):相对虚拟地址是内存地址相对于映射基址的偏移量。RVA = VA - Image Base
几个注意事项
- 文件的偏移是相对于文件开始处0字节的偏移,RVA则是相对于转载地址0x00400000处的偏移。由于操作系统在进行装载时基本上保持PE中的各种数据结构,所以文件偏移地址和RVA有很大的一致性
- 之所以说基本一致,是因为还有一些细微的差异。
- PE文件中的数据以0x200字节为基本单位,因此PE数据节的大小永远是0x200的倍数。
- 当代码装入内存中,将按照内存数据标准存放,并以0x1000字节为基本单位。故内存中的节总是0x1000的整数倍。
- 我们把这种存储单位差异引起的节基址称作节偏移。
- 节偏移 = 相对虚拟偏移量RVA-文件偏移量
- 文件偏移地址 = RVA - 节偏移 = VA - Image Base -节偏移
- DLL动态链接库文件
- EXE可执行文件
静态分析基础
网络扫描
上传至virustotal等网站,调用多个反病毒引擎进行扫描
通过计算哈希值,确定恶意代码的指纹
windows中有md5deep、winmd5等工具
查找字符串
在字符串中进行搜索存在的字符
- window函数名通常以大写字母开始的一个词开头,后面的每个词也以大写字母开始
加壳和混淆恶意代码
- 混淆程序是恶意代码编写者尝试去隐藏其执行过程的代码
- 加壳程序则是混淆程序中的一类,加壳后的恶意程序会被压缩,并且难以分析。
- 至少包含LoadLibrary和GetProcAddress函数,用来加载和使用其他函数功能的。
- 加壳程序运行时,会首先运行一小段脱壳代码,来解压加壳的文件,然后再运行脱壳后的文件
- 当静态分析加壳程序时,只有脱壳代码可以被解析,如下图所示:
- PEid工具:减策加壳器的类型,或者用来连接应用程序的编译器类型,
连接方式
- 静态链接
- 运行时链接
- 动态链接
- 静态链接再windows平台不常用,但在unix和linux是常用的,当一个库被静态链接到可执行程序时,所有这个库中的代码都会被复制到可执行程序中,这会让可执行程序增大很多,而在分析代码时,很难区分静态链接的代码与可执行程序自身代码,因为PE文件头中没有迹象表明这个文件包含有链接代码。
- 使用运行时链接的可执行程序,只有当需要使用函数时,才链接到库,而不是像动态连接模式那样在程序启动时就会链接。
- LoadLirary和GetProcAddress允许一个程序访问系统上任何库的任何函数,这意味着当这些函数被使用时,你无法静态分析出可以样本程序中会链接哪些函数
- 动态链接是最常见的,在装载时搜索库函数
导出函数
- 与导入函数类似,DLL和EXE的导出函数,是用来与其他程序和代码进行交互时所使用的,通常一个DLL会实现一个或多个功能函数,然后将他们导出,使得别的程序可以导入并使用这些函数。
- DLL文件本身就是实现一些导出函数然后被EXE可执行文件所使用的,因此导出函数在DLL文件中是最常见的
当你不知道一个函数有什么功能的时候,需要对其查询,可以在MSDN库中进行搜索
一个很老的编译时间意味着古老的攻击,反病毒软件就可能包含这个恶意代码的检测特征,而一个很新的编译时间意味的情况则正好相反。(IMAGE_FILE_HEADER中的TIME DATE STAMP)
但所有的Delphi程序都使用统一的编译时间,1992.6.19,如果是这个则很可能是Delphi程序
- IMAGE_OPTIONAL_HEADER部分包含几个重要信息:
- 子系统Subsystem描述指出是一个控制台程序还是图形界面程序
- 控制台的值为IMAGE_SUBSYSTEM_WINDOWS_CUI, 图形界面为GUI
- 当text分节在内存占有空间比在磁盘更大一些时,极有可能为加壳代码的存在