壳加载过程
保存各寄存器->执行外壳->恢复各寄存器->跳到原程序执行
通常采用pushad/popad
、pushfd/popfd
来保存和恢复寄存器现场。
跳回入口点之前,一般会恢复填写原PE文件输入表(IAT),并处理好重定位项(DLL文件)。因为加壳时外壳自己构造了一个输入表,因此这里需要重新对每个DLL引入的函数重新获取地址,并填写到IAT表中。
单步跟踪法
- 从程序载入不远处一个近call用
F7
步入。 - 遇到大循环,尽量满足向下的跳转,用
F4
跳过,对于向上的跳转不予实现。 - 跳转幅度大的jmp指令, 都极有可能是跳转到了原程序入口点 (OEP,Original Entry Point)
ESP定律法(常用)
pushad后,对 ESP 寄存器设硬件断点,右击寄存器窗口里面ESP
的值,选择HW break[ESP]
后,按下F9
运行程序,程序会在触发断点时断下,一般为popad位置。
搜popad法
ctrl+f
查找popad,循环ctrl+l
查找下一个,直到找到大jmp
内存镜像法
原理在于对于程序资源段和代码段下断点,一般程序自解压或者自解密时,会首先访问资源段获取所需资源,然后在自动脱壳完成后,转回程序代码段。这时候下内存一次性断点,程序就会停在 OEP 处。
- 选择菜单的
选项->调试选项->异常
,勾选所有的忽略异常 - 按下
ALT+M
,打开内存镜像,找到程序的第一个.rsrc
,按 F2 下断点,然后按SHIFT+F9
运行到断点 - 再按
ALT+M
,打开内存镜像,找到程序的第一个.rsrc
上面的.text
,按 F2 下断点。然后按SHIFT+F9
(或者是在没异常情况下按 F9),运行程序断在OEP
最后一次异常法
原理是程序在自解压或自解密过程中,可能会触发无数次的异常。如果能定位到最后一次程序异常的位置,可能就会很接近自动脱壳完成位置。可以利用Ollydbg的异常计数器插件,先记录异常数目,重新载入,自动停在最后一次异常处。
- 点击
选项->调试选项—>异常
,把里面的√全部去掉!按下CTRL+F2
重载下程序 - 开始程序就是一个跳转,在这里我们按
SHIFT+F9
,直到程序运行,记下从开始按SHIFT+F9
到程序运行的次数m
! CTRL+F2
重载程序,按SHIFT+F9
(这次按的次数为程序运行的次数m-1
次)- 在 OD 的右下角我们看见有一个 “
SE 句柄
“,这时我们按CTRL+G
,输入SE 句柄
前的地址 - 按 F2 下断点,然后按
SHIFT+F9
来到断点处,F8单步跟踪
SFX法
Ollydbg自带的OEP寻找功能,可以选择直接让程序停在OD找到的OEP处。
- 设置OD,忽略所有异常,也就是说异常选项卡里面都打上勾
- 切换到 SFX 选项卡,选择”字节模式跟踪实际入口 (速度非常慢)”,确定
- 重载程序(如果跳出是否 “压缩代码?”,选择 “否”,OD 直接到达 OEP)
Dump及IAT(Import Address Table)重建
ImportREC自动查找
- 在OEP处,右键选择
用OllyDump脱壳调试进程
(或者使用LoadPE来dump),取消勾选重建输入表
- 打开
ImportREC
,选择一个正在运行的OD调试原版进程(EIP
正处在OEP
位置,在用Ollydump
之后不要关闭) IAT Infos Needed
中填入OEP(如0049C25C,减去镜像基址00400000,填入0009C25C),点AutoSearch
,然后点Get Imports
- 点击
Fix Dump
,然后打开先前使用OllyDump
插件转储出来的文件,生成恢复导入表的exe
手工查找
- 右键点击OEP,选择
查找->所有模块间的调用
,显示出调用的函数列表,双击其中的某个程序函数(非系统函数) - 来到了函数调用处,右键点击
跟随
,进入函数,再右键点击数据窗口中跟随->内存地址
,来到IAT区域,在数据窗口点击右键选择长型->地址
,就可以显示函数名 - 要向上翻到 IAT 表的起始位置,向下找到最后一个函数,计算一下整个 IAT 表的大小,在 OD 的最下方有显示。打开
ImportREC
,选择我们正在调试的这个程序,然后分别输入OEP,RVA(起始位置),SIZE
,然后点击Get Imports
DLL文件脱壳
用LordPE
打开dll文件,特征值点击...
,取消勾选DLL
标志,保存后,系统就会将该文件视作一个可执行文件。采用手工查找IAT,并用ImportREC重建后,用LordPE恢复dll标志即可。