一、工具
1.查壳
Die
2.调试器
ida pro
xdbg
windbg
3.petools
ImportRE : 修复导入表
配置如下:

scylla : 用作
dump, xdbg自带,没有自动修复功能,工具栏的autotrace在源代码中实际上并没实现。:QQ_QQ-64: 使用默认配置即可。
二、准则
脱壳基本的2点:
通过一系列方法找到 OEP , 然后通过
dump工具dump下来。修复 IAT , 使用导入表修复工具(ImportRE等)修复先前
dump的pe文件。
脱壳成功的标志:
如果是exe,则程序必须能够正常运行。跑不起来的,要么壳没脱干净,要么导入表没修复好。
三、定位 OEP 的常用方法
1. esp 栈平衡法
适用对象:
加壳程序在初始化时(加壳后OEP附近)保存各寄存器的值: x86会有一条 pushad ,x86_64 会是几条 push rxx(寄存器) ,并且由于该方法必须用到硬件断点,加壳程序不能覆盖硬件断点寄存器(DR0 ~ DR3)。
具体步骤:
在 push 保存寄存器之后,设置 esp 硬件断点即可,接着F9 运行到硬件断点处即可,最后就 F8 找到大跳 的位置,就是OEP的位置。
示例:
这是一个经upx 压缩加壳的x86_64程序,加壳后跑起来可以看见明显的 push 保存寄存器的操作,在运行完所有push 之后,即可设置硬件断点于 RSP (快捷方式是右键寄存器窗口,激活出如同所示的菜单)

按下 F9 运行到硬件断点处,可以看到 00000001400664B1 有个明显的大跳 jmp steamtoolbox.14002CA20

跟过去发现,14002CA20基本符合 OEP 的特征

然后使用内置的scylla 即可完成 dump ,很好的是这里自动识别 IAT 没有无效的,不用再使用导入表修复工具了。

2.最后一次异常法
适应对象:
壳利用异常来检测调试器是否存在,并依赖 SEH 机制诸如 INT 3 断点异常、非法指令异常 (C000001D)、内存访问异常 (C0000005) 等来控制执行流。
具体步骤:
阶段一:摸底记数(寻找 M)
配置调试器: 设置异常选项,让调试器遇到异常时暂停(第一次机会),异常处理者设置为被调试对象。
载入程序并记数: 载入待脱壳程序,不断按
F9(忽略调试器处理,将异常传递给程序),同时记下按的次数。确定总数: 直到程序正常运行界面出现,或者程序跑飞、终止。记下按
F9的总次数,假设为M次。
阶段二:精准拦截(停在 M-1)
重新载入: 按
Ctrl+F2重新载入程序。来到最后一次异常: 连续按
F9,这次按M - 1次。此时,程序恰好停在即将抛出最后一次异常的指令处。
阶段三:接管 SEH
定位异常处理句柄: 打开调试器的 SEH 窗口,找到当前排在第一位的 SEH 句柄地址,右键“转到异常处理程序”,然后按
F4运行到光标处。单步寻踪找 OEP: 接下来开始按
F8单步往下跟,找到大跳位置。
示例:
这是一个由 tElock 0.98b1 加壳的 x86 程序(这壳用不了 esp栈平衡法,因为硬件断点寄存器会被覆盖)
x32dbg异常配置如下:

载入加壳程序后,按 F9 数次数,我是按了 17 下程序就跑起来了。然后重新载入,按 16 下之后:


跟过去在0044482D按 F4 运行到选区,然后一直单步 F8
0044482D | 8B6424 08 | mov esp,dword ptr ss:[esp+0x8] |
中途还出现了个回跳

最后发现是这里的大跳
004447E2 | FF6424 D0 | jmp dword ptr ss:[esp-0x30] |
跟过去是发现是 OEP 的特征

使用scylla dump

可以看到需要修复导入表,这里使用 ImportRE 进行修复(修复时一定要脱离调试状态):

修复之后,对于一些依旧无效的,可以右键反汇编查看具体代码,一般来说那些实际上是无效的空地址,直接右键cut 掉即可。

默认评论
Halo系统提供的评论