第二章 代码分析技术
1、认识PE格式
Win16平台上可执行文件是NE格式
Win32平台(包括Windows 95/98/ME/NT/2000/XP/CE)上,可执行文件是PE格式。
PE文件以区块(Section)来组织,每个快都有它自己在内存中的一套属性,比如:这个块是否包含代码、是否只读或可读写等。常见的区块有:
.text:在编译或汇编结束时产生的一种块,其内容全是指令代码;
.rdata:运行期只读数据;
.data:初始化的数据块;
.idata:包含其他外来DLL的函数及数据信息,即输入表;
.rsrc:包含模块的全部资源,如图标、菜单、位图等。
PE文件不是作为单一内存映射文件装入内存的,而是由Windows加载器遍历PE文件并决定文件的哪一部分被映射。PE文件的数据结构在磁盘和内存中是一样的。
几个PE名词概念:
(1)入口点(Entry Point):执行入口点,即执行时第一行代码的地址。
(2)文件偏移地址(File Offset):PE文件存储在磁盘上时,各数据的地址,从PE文件第一个字节开始计数,起始值为0。
(3)虚拟地址(Virtual Address,VA):保护模式下程序访问存储器所使用的逻辑地址,又称为内存偏移地址(Memory Offset)。虚地址如果写成“段:偏移量”的形式(例如,0167:00401000),这里的0167是指段选择子(其数据保存在CS段选择器里,一般不关心),00401000便是内存的虚拟地址(一般来说,同一程序的同一条指令在不同系统环境下,此值相同)。
(4)基地址(ImageBase):文件执行时将被映射到指定内存地址中,这个初始内存地址称为基地址,这个值由PE文件本身设定。用Visual C++建立的EXE文件默认的文件基地址是0x00400000,DLL文件基地址是0x10000000,在链接应用时使用/BASE选项可以改变这个地址。
(5)相对虚拟地址(Relative Virtual Address,RVA):内存中相对于PE文件装入地址(基地址)的偏移量。
公式: RVA(相对虚拟地址) = VA(虚拟地址) – ImageBase(基地址)
文件偏移地址(File Offset)和虚拟地址(VA)的转换
换算原理:
△K(差值)=RVA(虚拟偏移量,相对虚拟地址)-Raw Offset(文件偏移量)
File Offset(文件偏移地址)= VA(虚拟地址)– ImageBase(基地址)- △K(差值)
实际应用中可以使用RVA-Offset之类的转换工具,例如LordPE软件中,打开对象PE文件后,点击FLC(File Location Calculator,文件位址计算器),即可进行VA,RVA和File Offset之间的转换。
2、代码指令
转移指令机器码的计算(实际操作可使用机器码计算工具,如oPcodeR):
(1) 短转移(Short jump):两个字节,转移范围-128到+127字节。
计算公式:
位移量 = 目的地址 – 起始地址 – 跳转指令本身的长度
转移指令机器码 = “转移类别机器码”+ “位移量”
(2)长转移(Long jump):无条件转移5字节,条件转移6字节。公式与(1)类似。
(3)子程序调用(call):一类类似于长转移,另一类的参数涉及到寄存器、堆栈等,比较复杂,例如,call dword ptr[eax *edx+2]。
条件设置指令的形式是:SETcc r/m8,其中r/m8表示8位寄存器。
条件设置指令可以用来消除程序中的转移指令。
指令修改技巧参照29页表,很多指令针对eax做了优化,所以尽量多用eax。
浮点数据格式由符号为S、指数部分E和尾数部分M三部分组成
浮点格式数据和实数表达格式之间的转换(组成原理课本)
浮点寄存器主要是8个通用数据寄存器(FPU),编号为ST0~ST7,另外还有状态寄存器、控制寄存器和标记寄存器。
3、逆向分析技术(重在实践)
逆向分析技术是指通过分析反汇编代码来理解其代码功能(如各接口的数据结构等),然后用高级语言重新描述这段代码,逆向推出源软件的思路。
逆向分析的一个好习惯是给代码加注释。
分析的重点应放在函数上。并进而分析循环、控制语句、初始化语句等。
全局变量作用于整个程序,放在全局变量的内存区(常数一般放在全局变量中);而局部变量则存在于函数的堆栈区。