编程语言
首页 > 编程语言> > 《逆向工程核心原理》第14.15章——运行时压缩、调试UPX压缩的notepad.ex程序

《逆向工程核心原理》第14.15章——运行时压缩、调试UPX压缩的notepad.ex程序

作者:互联网

运行时压缩


数据压缩

无损压缩(Lossless Data Compression):压缩的文件能够100%恢复。如Run-Length、Lempel-Ziv、Huffman。

有损压缩(Loss Data Compression):压缩的文件不能恢复原状,会损失一定信息,常用于多媒体文件。


运行时压缩器

运行时压缩器是针对PE文件而言的,可执行文件内部含有解压缩代码,文件在运行瞬间于内存中解压缩后执行。
运行时压缩文件也是PE文件,内部含有原PE文件与解码程序。在程序中的EP代码中执行解码程序,同时在内存中解压缩后执行。

把普通PE文件创建成运行时压缩文件的实用程序称为“压缩器(packer)”,经反逆向技术特别处理的压缩器称为保护器(protecter)

压缩器

PE压缩器大致可分为两类:一类是单纯用于压缩普通PE文件的压缩器:UPX、ASPack等,另一类是对源文件进行较大变形、严重破坏PE头、意图稍显不纯的压缩器,指专门用于恶意程序(如:Virtus、Trojan、Worm等)的压缩器:Upack、PESpin、NSAnti等。

保护器

保护PE文件免受代码逆向分析的实用程序,它应用了多种反逆向技术(反调试、反模拟、代码混乱、多态代码、垃圾代码、调试器监视等),这类PE文件尺寸反而比源文件大一些,调试起来非常困难。 开始调试时必须先转到OEP处才行。

这类保护器大量运用与对破解很敏感的安全程序,另一方面,常见的恶性代码中也大量使用保护器防止杀毒软件的检测。


运行时压缩测试——notepad.exe为例

运行upx:在这里插入图片描述
进行文件压缩:
在这里插入图片描述
查看文件压缩前后的属性,可以看到文件尺寸明显减少(67584→48128)。

对notepad_upx.exe文件分析:
在这里插入图片描述可以看到第一个节区的RawDataSize=0,但是VirtualSize=00010000H,即文件中的大小为0,虚拟内存中大小变为10000H。这就是说,程序运行前,解压缩代码与压缩的源代码都在第二个节区。文件运行时首先执行解压缩代码,把处于压缩状态的源代码解压到第一个节区,解压过程结束后即运行源文件的EP代码。

另外可以看到EP代码位于压缩后文件的第二个节区(原文件在第一个)。资源节区大小几乎没有变化。PE头大小也一样。


调试UPX压缩的notepad.exe程序

01 notepad.exe的EP代码

首先查看原notepad.exe的EP代码:
在这里插入图片描述
可以看到在EP处调用了GetModuleHandleA()API,获取程序的ImageBase(01000000)。然后又进行了MZ、PE签名的比较。

02 notepad_upx.exe的EP代码

使用OD打开时弹出警告消息框,调试器判断文件为压缩文件。
在这里插入图片描述
点击“是”开始调试。

EP地址为01015330,即位于第二个节区的末端部分。
查看代码开始部分:
PUSHAD命令将EAX~EDI寄存器的值保存到栈中,然后分别把第二个节区的起始地址(01011000)与第一个节区的起始地址(01001000)设置到ESI与EDI寄存器中。UPX文件第一节区仅存在于内存,该处即是解压后保存源文件代码的地方
在这里插入图片描述:调试时像这样同时设置ESI和EDI,就能预见从ESI(Source)所指的缓冲区到EDI(Destination)所指的缓冲区的内存发生了复制。

03 跟踪UPX文件

遇到循环时,先了解作用再跳出。

循环1

在EP处执行Ctrl+F8开始跟踪,遇到第一个短循环。
在这里插入图片描述
功能是从EDX中读取一个字节写入EDI中(此处EDI=EDX+1),EDX初始值为01001000,该区域均为NULL,因此该段循环没有什么实际意义,跳出(010153E6处F2下断点,F9跳出循环)。

循环2

继续执行看到第二个循环:解压缩循环
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在01015402处设置断点,F9跳出循环。

循环3

该循环代码用于恢复源代码的CALL/JMP指令(操作码E8/E9)的desitination地址。
在这里插入图片描述

循环4

该循环用于恢复IAT。
在这里插入图片描述
设置EDI=01014000,它指向存储着源文件调用的API函数名称的字符串,如下图。,
UPX压缩源文件时,会分析其IAT,提取程序中调用的API名称列表,形成API名称字符串。因此在恢复时,就需要用这些API名称字符串调用GetProcAddress()函数,获得API起始地址,再将起始地址输入IAT区域。

全部解压缩完成后,程序的控制会返回OEP处。
在这里插入图片描述
POPAD与PUSHAD对应。最终跳转到0100739D处,即为原notepad.exe的EP。
在这里插入图片描述

快速查找UPX OEP的方法——在栈中设置硬件断点

UPX压缩器的特征之一是:其EP代码被包含在PUSHAD/POPAD指令之间,并且跳转到EOP的JMP指令紧接着出现在POPAD指令之后。

在栈中设置硬件断点的方法利用了UPX的上述特性。
在执行PUSHAD指令后,查看栈。可以看到EAX~EDI寄存器的值依此入栈。
在这里插入图片描述
在Dump中定位0006FF6C,右键-BreakPoint-Hardware,on access-Byte设置硬件断点。
在这里插入图片描述
执行程序,可以看到运行完POPAD处停止(设置硬件断点的指令执行完毕后才暂停调试),可以看到它的下方就是跳转到OEP的JMP指令。
在这里插入图片描述

脱壳

接下来参考博客尝试脱壳,博客链接:https://www.cnblogs.com/dliv3/p/6119505.html
在OEP处右键-Dump debugged process(52pojie OD中为“用Ollydump脱壳调试进程”)
这里可能会遇到问题,我的的实验是在Win7 32位虚拟机中进行的,在OD的Plugin目录下我可以查看到对应插件,但是右键却查找不到。
在这里插入图片描述
解决方法:
OD-上面一栏Options-Appearance重新配置Plugin地址。
在这里插入图片描述点击确定,重启OD,即可看到所有插件。
在这里插入图片描述

点击用Ollydump脱壳调试进程,修改OEP为EP。
在这里插入图片描述

点击脱壳,另存为notepad_dump.exe。程序可以正常运行且OD打开后可以看到处于EP处。
在这里插入图片描述

总结一下

UPX解压缩过程一共经过四个循环。其中第二个循环为主要的解压缩循环,第三个循环用于恢复CALL/JMP指令,第四个循环用来恢复IAT。

根据UPX压缩器的基本特征可以通过在栈中设置硬件断点的方式找到OEP。

恢复文件IAT处的循环,可以通过反复调用GetProcAddress()函数知道。

标签:代码,压缩,notepad,14.15,压缩器,UPX,EP,循环
来源: https://blog.csdn.net/diamond_biu/article/details/111162827