脱壳技术

壳加载过程

保存各寄存器->执行外壳->恢复各寄存器->跳到原程序执行

通常采用pushad/popadpushfd/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 处。

  1. 选择菜单的选项->调试选项->异常,勾选所有的忽略异常
  2. 按下ALT+M,打开内存镜像,找到程序的第一个.rsrc,按 F2 下断点,然后按SHIFT+F9运行到断点
  3. 再按ALT+M,打开内存镜像,找到程序的第一个.rsrc上面的.text,按 F2 下断点。然后按SHIFT+F9(或者是在没异常情况下按 F9),运行程序断在OEP

最后一次异常法

原理是程序在自解压或自解密过程中,可能会触发无数次的异常。如果能定位到最后一次程序异常的位置,可能就会很接近自动脱壳完成位置。可以利用Ollydbg的异常计数器插件,先记录异常数目,重新载入,自动停在最后一次异常处。

  1. 点击选项->调试选项—>异常,把里面的√全部去掉!按下CTRL+F2重载下程序
  2. 开始程序就是一个跳转,在这里我们按SHIFT+F9,直到程序运行,记下从开始按SHIFT+F9到程序运行的次数m
  3. CTRL+F2重载程序,按SHIFT+F9(这次按的次数为程序运行的次数m-1次)
  4. 在 OD 的右下角我们看见有一个 “SE 句柄“,这时我们按CTRL+G,输入SE 句柄前的地址
  5. 按 F2 下断点,然后按SHIFT+F9来到断点处,F8单步跟踪

SFX法

Ollydbg自带的OEP寻找功能,可以选择直接让程序停在OD找到的OEP处。

  1. 设置OD,忽略所有异常,也就是说异常选项卡里面都打上勾
  2. 切换到 SFX 选项卡,选择”字节模式跟踪实际入口 (速度非常慢)”,确定
  3. 重载程序(如果跳出是否 “压缩代码?”,选择 “否”,OD 直接到达 OEP)

Dump及IAT(Import Address Table)重建

ImportREC自动查找
  1. 在OEP处,右键选择用OllyDump脱壳调试进程(或者使用LoadPE来dump),取消勾选重建输入表
  2. 打开ImportREC,选择一个正在运行的OD调试原版进程(EIP正处在OEP位置,在用Ollydump之后不要关闭)
  3. IAT Infos Needed中填入OEP(如0049C25C,减去镜像基址00400000,填入0009C25C),点AutoSearch,然后点Get Imports
  4. 点击Fix Dump,然后打开先前使用OllyDump插件转储出来的文件,生成恢复导入表的exe
手工查找
  1. 右键点击OEP,选择查找->所有模块间的调用,显示出调用的函数列表,双击其中的某个程序函数(非系统函数)
  2. 来到了函数调用处,右键点击跟随,进入函数,再右键点击数据窗口中跟随->内存地址,来到IAT区域,在数据窗口点击右键选择长型->地址,就可以显示函数名
  3. 要向上翻到 IAT 表的起始位置,向下找到最后一个函数,计算一下整个 IAT 表的大小,在 OD 的最下方有显示。打开ImportREC,选择我们正在调试的这个程序,然后分别输入OEP,RVA(起始位置),SIZE,然后点击Get Imports
DLL文件脱壳

LordPE打开dll文件,特征值点击...,取消勾选DLL标志,保存后,系统就会将该文件视作一个可执行文件。采用手工查找IAT,并用ImportREC重建后,用LordPE恢复dll标志即可。