notepad.exe的EP代码
<br />调试器判断该文件为压缩文件,在“是”与“否”中任选一个,显示出UPX EP代码,如图所示。<br /><br />Ep地址为01015330,该处即为第二个节区的末端部分。实际压缩的notepad源代码存在于EP地址(01015330)的上方。<br />代码的开始部分(01015330)。<br />![EGM4N_HP8UQJEDB]YC[
@$Y.png](https://cdn.nlark.com/yuque/0/2020/png/554486/1583397726904-66d12730-fbfe-45a8-97bf-600df1847855.png#align=left&display=inline&height=54&name=EGM4N_HP8UQJEDB%5DYC%5B%60%40%24Y.png&originHeight=54&originWidth=727&size=39538&status=done&style=none&width=727)
首先使用PUSHAD命令将EAX-EDI寄存器的值保存到栈,然后分别把第二个节区的起始地址(01011000)与第一个节区的起始地址(01001000)设置到ESI与EDI寄存器。UPX文件第一个节区仅存在于内存。该处即是解压缩后保存源文件代码的地方。
调试时像这样同时设置ESI与EDI,就能遇见从ESI所指缓冲区到EDI所指缓冲区的内存发生了复制。此时从Source(ESI)读取数据,解压缩后保存到Destination(EDI)。我们的目标是跟踪图15-3中全部UPX EP代码,并最终找到原notepad的EP代码如图15-1所示。
提示: 代码逆向分析称源文件的EP为OEP。
“跟踪”一词的含义是通过逐一分析代码进行跟踪。
实际的代码逆向分析中并不会逐一跟踪执行压缩代码,常使用自动化脚本、特殊技巧等找到OEP。
跟踪UPX文件
跟踪数量庞大的代码时,要遵循如下法则。
“遇到循环(loop)时,先了解作用再跳出。”
整个解压过程由无数循环组成。因此,只有适当跳出循环才能加快速度。
OD的跟踪命令
跟踪数量庞大的代码时,通常不会使用Step Into(F7)命令,而使用OD中另外提供的跟踪调试命令,如表所示。
除了画面显示的之外,Animate命令与跟踪命令是类似的,由于Animate命令要把跟踪过程显示在画面中,所以执行速度略微慢一些。而两者最大差别在于,跟踪命令会自动在事先设置的跟踪条件处停下来,并生成日志文件。在UPX文件跟踪中将使用Animate Over(Ctrl+F8)命令。
循环#1
在EP代码处执行Animate Over命令,开始跟踪代码。可以看到光标快速上下移动。
若想停止跟踪,执行Step Into(F7)命令即可。
开始跟踪代码不久后,会遇到一个短循环。暂停跟踪,仔细查看相应循环,如图15-4显示。

循环次数ECX=36B,循环内容为“从EDX(01001000)中读取一个字节写入EDI(01001001)”。EDI寄存器所
指的01001000地址是第一个节区(UPX0)的起始地址,仅存在于内存中的节区(反正内容全部为NULL)。
调试经过运行时压缩的文件时,遇到这样的循环应该跳出来。在010153E6地址处按F2键设置好断点后,按F9跳出循环。
循环#2
在断点处再次使用Animate Over(Ctrl+F8)命令继续跟踪代码,不久后遇到图示循环。
该循环是正式的解码循环(或称为解压缩循环)。
先从ESI所指的第二个节区(UPX1)地址中依次读取值,经过适当的运算解压缩后,将值写入EDI所指的第一个节区(UPX0)地址。该过程中使用的指令如下;
只要在01015402地址处设置好断点再运行,即可跳出得个循环,如图15-5所示。运行到01015402地址后,在转储窗口中可以看到解压缩后的代码已经被写入第一个节区(UPX0)区域(01007000),如图15-5中原来用NULL填充的区域。
循环#3
重新跟踪代码稍后会遇到图示的第三个循环。
该段循环代码用于恢复源代码的CALL/JMP指令(操作码:E8/E9)的destination地址。在01015436地址处设置断点运行后即可跳出循环。
提示:对于普通的运行时压缩文件,源文件代码、数据、资源解压缩后,先设置好IAT再转到OEP。
循环#4
重新跟踪代码,再稍微进行一段。
图15-7深色显示的部分即为设置IAT的循环。在01015436地址处设置EDI=01014000,它指向第二个节区(UPX1)区域,该区域中保存着原notepad.exe调用的API函数名称的字符串(参考图15-8)。
另外,010154AD地址处的POPAD命令与UPX代码的第一条PUSHAD命令对应,用来把当前寄存器恢复原状(参考图15-3)。
最终,使用010154BB地址处的JMP命令跳转到OEP处,要跳转到的目标地址为0100739D,它就是原notepad.exe的EP地址。
快速查找UPX OEP的方法
实际代码逆向分析中有一些更简单的方法可以找到OEP(以UPX压缩的文件为例)。
在POPAD指令后的JMP指令处设置断点
UPX压缩器的特征之一是,其EP代码被包含在PUSHAD/POPAD指令之间。并且跳转到OEP代码的JMP指令紧接着出现在POPAD指令之后。只要在JMP指令处设置好断点,运行后就能直接找到OEP。
提示: PUSHAD指令将8个通用寄存器(EAX~EDI)的值保存到栈。
POPAD指令把PUSHAD命令存储在栈的值再次恢复到各个寄存器。
在栈中设置硬件断点
该方法也利用UPX的PUSHAD/POPAD指令的特点。在图15-3中执行01015330地址处的PUSHAD命令后,查看栈,如图15-10所示。
![UW1)FMFUPM
FSU$@%C3}G.png
EAX到EDI寄存器的值依次被存储到栈。从OD的Dump窗口进入栈地址(006FFA4)。将鼠标光标准确定位到6FFA4地址,使用鼠标右键菜单设置硬件断点,如图15-11所示。
硬件断点是CPU支持的断点,最多可设置4个。与普通断点不同的是,设置断点的指令执行完成后才暂停调试。在这种状态下运行,程序就会边解压缩边执行代码,在执行POPAD的瞬间访问设置有硬件断点的0006FFA4地址,然后暂停调试。其下方即是跳转到OEP的JMP指令。