您的位置:首页 > 其它

Upack0.31 脱壳小试,附详细过程

2015-01-14 16:30 106 查看

一、Upack的加壳

Upack作为一种保护壳,独特的PE格式混淆与压缩是很让人惊叹的,很多PE分析器与自动脱壳软件脚本都被干掉了,dwing大神对PE装载器的理解之深入让人不得不佩服得五体投地。作为测试,先用一个自己写的C++小程序作为加壳对象进行加壳:



PEiD检测结果如下:



用百度到的第一个Upack0.31版本对原程序加壳,加壳后的程序PEID检测如下:



检测出了Upack加壳,运行后程序没有问题还能用。于是开始下一步——脱壳!

二、加壳后的分析

(1)根据之前对Upack压缩机制的了解,其加壳后程序运行的流程和其他壳大致相同:
1.利用PE加载器将文件映射为PE映像
2.加载Kernal32.dll和Ntdll.dll,只导入LoadLibraryA和GetProcAddress两个函数
3.对PE映像中的加密代码进行解密,之后重建IAT
4.跳回OEP,执行功能部分代码
毕竟还是PE文件,整个过程肯定是按照既有流程来的,并且Upack不是专业的保护壳没有那么多反调试的手段,所以按照正常的调试经验就可以调通。

(2)用Ollydbg载入,程序停在了现在的入口点处:



可以看到是一个保存环境的指令,这是一个典型的可以使用堆栈平衡的标识。第一次分析时不能轻易下结论,还是先跟着程序跑一跑看一下。



用F8刚运行没几步就出现了异常,看来是不能直接跟着跑的。必须在入口点下一个CALL指令处F7跟进。太麻烦了,于是还是利用堆栈平衡看看吧。
(2)利用堆栈平衡:
在入口点执行PUSH AD,会将寄存器值压入堆栈中,在此时栈顶处设置硬件断点:



(方式就是在ESP处右键,选在数据窗口中跟随。然后在地址0018FF6C处选中一个双字并右键,选择如下)



(3)挂着硬件断点运行F9,程序停在了0046D866处,此时指令为JMP至某处。



对这段代码的,应该注意的是:前一条指令POPAD一般用于指令解密完毕后恢复初始环境,而这附近的一堆条件跳转的代码根据我的追踪正是对代码段中加密后指令解密的代码。可以判断出这里正是解密代码的结束,即将前往OEP。

(4)根据上一条JMP指令,走到了刚解密完的代码段:



由于OD是不能实时分析代码的,于是选中该附近的代码段并Ctrl+A再次分析,就变成了一系列的跳转指令。



可以看出这是常用的代码段函数重定位手段,这能够说明Upack解密代码已经完全解密并完成了函数地址的重定位。这是再看程序的IAT表,仍旧是只要开始的那两个函数,因为其它函数的地址已经用过JMP方式获得并进行了相应的替换。

既然解密已经完成,说明离OEP已经不远了,应该就在这附近。
(5)跟随上面的第一个JMP,我们又到了一串刚解密后的指令处,仍旧是没有解析需要我们手动解析。解析后如下:



这里就是我们需要的OEP了!下面两个函数正是我们完成功能的具体函数。一开始我也不太确定,但是跟进运行了一下就很清楚了。具体的:第一个CALL函数内容为编译器编译时添加的初始化函数;第二个CALL具体实现我们的功能。

三、脱壳和修复

(1)既然找到了OEP,那就用OllyDump这个插件先把内存转储出来:



使用“获取EIP作为OEP”可以很轻松地设定OEP地址,关键在于一定要取消“重建输入表”选项。根据大神们的教导,这个时候的重建往往是不准确的!
把转储出来的文件保存为“dump.exe”,之后需要进行输入表的重建。
(2)重建输入表还是用大名鼎鼎的“ImportREC”方便一点,选则“附加一个活动进程”,选中已经调到OEP的加壳后的程序。



之后就是获取输入表,将OEP设为我们定位到的122D0,并进行自动搜索。这时会提示:



先忽略,确定后再点“获取输入表”,结果如下:



只有Kernel32.dll的,说明没有找到Upack解密时后来加入的重定位后地址。于是根据刚才提示将RVA、大小两项改为推荐的值,直接进行“获取输入表”,就得到了完整的IAT:



显然这样才对。之后就是点击“修复转存文件”,让后程序会自动修复"dump.exe"的导入表并另存为"dump_.exe",它就是我们所需要的脱壳后文件。运行结果如下:

可以看到脱壳成功,对Upack0.31的脱壳到此为止!~~~~~~~~~~~~~~~~~~~~~~~~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: