第24章 加壳与脱壳(二):ASPack、FSG、压缩壳通用脱壳方法
上一章我们聊了UPK和北斗壳,算是给压缩壳开了个头。这一章,咱们继续深入,把ASPack和FSG这两个老牌压缩壳给收拾了。说实话,这两个壳在现在的恶意软件里已经不常见了,但在一些老旧的商业软件、游戏修改版里,你还能经常碰到它们。我个人的经验是,掌握了这两个壳的脱法,你基本就摸清了压缩壳的通用套路。
24.1 压缩壳的“三板斧”
压缩壳,说白了就是给PE文件“瘦身”。它把原始代码和数据压缩起来,运行时再解压到内存里执行。你想想看,它总得有个解压的入口点吧?总得把原始入口点(OEP)给恢复吧?这就是我们的突破口。
我总结了一下,压缩壳的脱壳流程,其实就是三板斧:
- 找OEP:找到程序真正的入口点。这是最关键的一步。
- Dump内存:把解压后的完整程序从内存里“倒”出来。
- 修复IAT:重建导入地址表,让Dump出来的程序能正常运行。
嗯,这里要注意,不同壳的OEP特征不一样,但思路是相通的。我们一个一个来看。
24.2 ASPack:经典的“Pushad/Popad”壳
ASPack是我早期逆向时经常遇到的壳。它的特征非常明显:入口点通常是一连串的pushad,然后是一堆花指令,最后用popad配合retn跳转到OEP。
为什么会这样?pushad保存了所有寄存器的状态,这是为了在解压过程中不破坏原始程序的寄存器环境。解压完成后,popad恢复现场,然后跳转。
脱ASPack,我习惯用ESP定律。这个方法简单粗暴,成功率极高。
ESP定律脱ASPack步骤:
- 用OD(OllyDbg)加载程序,停在入口点。你会看到类似
pushad的指令。 - 在命令行输入
hr esp,对ESP寄存器下硬件访问断点。 - 按F9运行,程序会断在某个
popad或retn指令附近。 - 单步跟踪几步,就能看到一个大跳转,跳到一个看起来像正常代码的地方。那就是OEP。
我曾经遇到过一个ASPack加壳的程序,它加了反调试,ESP定律失效了。后来我用了内存断点法,在代码段下断点,才找到OEP。所以,ESP定律不是万能的,但它是我们最趁手的武器。
24.3 FSG:更小巧,更隐蔽
FSG(Fast Small Good)是另一个经典的压缩壳。它比ASPack更小,代码更精简。它的入口点特征不像ASPack那么明显,但通常也是以pushad开头,不过后面的代码更短,跳转更直接。
FSG的脱壳方法,和ASPack大同小异。我个人更推荐用单步跟踪法。因为FSG的代码量少,单步跟踪很快就能找到OEP。
单步跟踪法技巧:
- 遇到
call指令,如果call后面跟着pop或add esp,这通常是花指令,直接F8跳过。 - 遇到
jmp或retn,如果跳转目标看起来像代码(有连续的push、mov等),那可能就是OEP。 - 注意观察堆栈窗口。当堆栈中出现返回地址,且该地址指向一个看起来像函数入口的地方,那很可能就是OEP。
我记得有一次,我脱一个FSG壳的程序,单步跟踪了半天,发现它在一个循环里打转。后来我仔细一看,原来它用了SEH(结构化异常处理)来混淆。我直接忽略了异常,继续跟踪,才找到真正的OEP。所以,遇到异常不要慌,先看看是不是壳在搞鬼。
24.4 通用脱壳方法:ESP定律与内存断点
其实,不管是ASPack还是FSG,甚至是其他压缩壳,它们的核心逻辑都是一样的。所以,我们可以总结出一套通用的脱壳方法。
我把它们整理成了下面的流程图,方便你理解:
你看,流程很清晰。先判断入口特征,然后选择合适的方法找到OEP,最后Dump和修复。这套流程,我用了十年,依然有效。
24.5 实战:脱一个ASPack壳的程序
光说不练假把式。我们拿一个实际例子来走一遍流程。
假设我们有一个名为 target.exe 的程序,被ASPack加壳了。
第一步:加载程序
用OD加载 target.exe。停在入口点:
00401001 > 60 pushad
00401002 0BC0 or eax,eax
00401004 74 68 je short 0040106E
00401006 E8 00000000 call 0040100B
...
嗯,看到了吧,经典的 pushad 开头。
第二步:使用ESP定律
在命令行输入 hr esp,然后按F9运行。程序会断在:
0040106E 5D pop ebp
0040106F 55 push ebp
00401070 C3 retn
第三步:找到OEP
单步跟踪,执行到 retn,程序会跳转到:
00401234 55 push ebp
00401235 8BEC mov ebp,esp
00401237 83C4 F0 add esp,-0x10
...
这个 push ebp; mov ebp,esp 就是典型的VC++入口特征。OEP找到了!
第四步:Dump内存
用OD的插件(如OllyDump)或LordPE,将当前进程的内存Dump出来。
第五步:修复IAT
用ImportREC工具,选择刚才Dump出来的文件,填入OEP地址(00001234),然后修复IAT。搞定!
注意事项:
- Dump时,要确保程序已经解压完成,且停在OEP处。
- 修复IAT时,如果ImportREC无法自动识别IAT,可以尝试手动搜索或使用其他工具(如Scylla)。
- 有些壳会修改PE头,导致Dump出来的文件无法运行。这时需要手动修复PE头。
24.6 避坑指南
最后,分享几个我踩过的坑:
- 反调试:有些壳会检测OD,导致断点失效。可以尝试用硬件断点、内存断点,或者使用隐藏OD插件。
- 多线程:有些壳会创建多个线程,干扰脱壳。可以在OD中暂停所有线程,只保留主线程。
- IAT加密:有些壳会对IAT进行加密,导致ImportREC无法修复。这时需要手动分析IAT的结构,或者使用更高级的修复工具。
我曾经遇到一个壳,它把IAT的地址给加密了,ImportREC怎么都修复不了。后来我手动跟踪了壳的解密代码,找到了真正的IAT地址,才修复成功。所以,遇到问题不要怕,多动动手,总能找到解决办法。
好了,这一章的内容就到这里。压缩壳的通用脱壳方法,你掌握了吗?