逆向技术:脱壳

初级 - 手工脱壳(压缩壳)
思路其实很统一:通过壳函数的执行来确定OEP(找到大跳,下断点,然后单步直到OEP / ESP定律),OD脱壳插件/LordPE dump出解压后的数据,Import REC修复IAT表和导入表(几个例子都这样的)

压缩壳比较通杀的ESP定律:push后(当只有ESP和EIP变红的时候)根据寄存器ESP的值在数据窗口跟随(命令:dd [ESP] / 右键->Follow In Dump/HW Breakpoint),在左下窗口处:断点—>硬件访问—>Word(命令:hr [ESP] )—>运行—>删除硬件断点—>F8到OEP。在单步的过程中,可能会遇到retn指令,有些retn指令如果F8跟进后会导致跑飞,则将它改为nop。

ASPack手工脱壳

拿到了一个程序,查壳是ASPack壳

拖进IDA里面看了一下,的确是加过壳:左边的流程框图可以看见就两个代码块,而且这两个代码块和右边的没有任何联系,但这两个块的代码在进行操作之后是通过一定的方式跳转到有右边的块

这里先拖进OD里面,按F8单步一次来到pusha指令,根据程序执行的顺序,这个壳的函数在运行完之后一定会开辟新的内存空间用于储存原程序的指令,根据EBP、EIP、ESP的定义,这个函数开辟的内存空间会跟在这个函数内存空间之后,也就是壳函数的ESP就是存放原程序所有指令的内存空间的EBP。这里就在右边的窗口选中ESP下一个硬件断点,然后运行

当运行后,程序会断在ESP处,现在能看到程序已经停下来了,这里能看见指令jnz short....直接跳转到push u01.0041DDAC,这就说明程序的OEP(Original Entry Point,原始入口点)是1DDAC(减去40000加载基址)

几次F8的单步执行来到地址0041DDAC,右键点击选择脱壳调试进程


入口点地址修正为1DDAC,然后点击脱壳把原程序的所有东西dump出来(保存为00.exe),不要关掉OD也不要停止调试进程,下一步的修复IAT表和导入表需要用到OD当前正在进行调试的进程

跟着这里需要修复IAT表,打开Import REC,选择OD当前正在调试的进程,之后修改OEP为1DDAC,点击IAT AutoSearch修复IAT表,再点击Get Import修复导入表,最后点击Fix Dump,选择刚才dump出来的00.exe文件,Import REC会保存修复之后的文件为00_.exe

再次查壳,显示无壳

UPX手工脱壳

查壳是UPX壳

OD里面进行动态调试,发现一进去就是pusha指令

按一次F8单步,直到右边窗口只有ESP和EIP是红色的时候,给ESP下一个硬件断点

设置完硬件断点后,按F9运行,会在上一步设置的断点处停下来,观察这里有个指令是个大跳(跳到0041DDAC),也就说明壳执行完之后就会跳到那里,很大可能是放着原程序指令的内存块的头地址,也就是OEP。点击选中这个大跳,按F2下一个断点,按F9直到运行到这个断点处

在运行到上面设置的断点之后,按F8直到内存执行到041DDAC,右键选择脱壳调试进程,把入口地址修正为1DDAC(减去400000加载基址),按脱壳dump出数据,保存为00.exe



这一步是修复IAT表和导入表:打开Import REC,选中OD的调试进程,把OEP改成1DDAC,点击IAT AutoSearch,再点击Get Imports,最后点击Fix Dump,选中在OD脱壳得到的00.exe,会自动保存成00_.exe

最后查壳:压缩器显示 无可用信息,脱壳完成

NsPack手工脱壳

查壳是NsPack壳

拖入OD进行动态调试,发现右侧的寄存器一片红

按一次F8单步之后发现只有EIP和ESP红了,在ESP处下硬件断点,按F9运行至断点处


运行到断点处之后,发现一个大跳,这里应该是原程序的OEP,按F8单步一次

单步完毕之后,发现没有大跳了,判断已经到了OEP,右键打开菜单点击脱壳调试进程,修改入口地址,脱壳保存成文件(这里文件保存成00.exe)


打开Import REC进行修复IAT表和导入表:选中当前OD调试进程,修改OPE,点击IAT AutoSearch,再点击Get Imports,最后点击Fix Dump,选中上一步保存的00.exe文件(程序会把上一步到处的exe文件00.exe修复后保存成00_.exe)

检查脱壳后的文件:压缩器显示无可用信息

FSG手工脱壳

查壳:FSG 2.0

FSG 2.0 -> bart/xt

拖进OD进行动态调试

这里先直接贴出OEP

FSG壳寻找OEP需要一定的方法,方法有些不一样,如下:
方法一:单步跟踪
使程序只执行向下跳转,不让向上跳,直到运行到三个连续跳转处,其中jmp(无条件跳转)跳转之后即为OEP
遇到往回跳转就选中下一条指令,右键选择运行到此处(F4)


重复重复在再重复。。。。。。
然后一直到这里,F8之后就是OEP

方法二:ESP定律法
push后根据寄存器ESP的值在数据窗口跟随(命令:dd [ESP] )
断点—>硬件访问—>Word(命令:hr [ESP] )—>运行—>删除硬件断点—>F8到OEP
运行到push后的一条指令,命令处输入dd 0012ffc0,回车执行


右键选中下边窗口高亮的一行,右键->断点->硬件访问->字

F9运行(这里已经可以看见三个连续的跳转了)

删除硬件断点(最后按照上一个方法跳转到jmp处,F8之后即为OEP)

方法三:FSG 2.0 专用ESP定律法
当执行到popad后一条代码时,查看堆栈窗口,第四条的数值即为OEP地址,反汇编窗口跟随,设置硬件断点,运行即可到OEP

命令处输入bp 0041ddac,回车后出现异常断点对话框,点击“是”

右键选中这个地址之后,选择断点->运行止此处(F4),即为OEP,程序的数据也都解压出来了

找到OEP之后就开始脱壳,右键OEP,打开菜单点击脱壳调试进程,修改入口地址,重建输入表选择第二个,脱壳,保存为00.exe

使用Import REC修复00.exe的IAT表和输入表,运行程序发现出错

手动修复IAT表和输入表
同样的,FSG壳不仅OEP寻找要用方法,而且IAT表和输入表也是要手动修复的(其实对比前面的例子和这里的例子,能发现在当前的例子中,点击Import REC的‘获取输入表’后,输入表只出现了一行,以往的例子都是一大堆的),下面就来修复(注意,上面导出的00.exe已经不会再用到)
来到OD,命令输入dd [OEP的地址],回车,会看见左下内存窗口出现数据(其实就是各种API的调用,当然也包含了IAT表和输入表)

回到Import REC,点开输入表的函数,随便找一个函数,查看RVA,这里就选第一个,然后在OD的内存窗口找到这个函数(加上400000加载基址)

来到这里之后,往上拖动直到看见00000000的内存地址,这里的开始地址是00432000

然后往下拖动,直到kernel32的调用结束的内存地址(7FFFFFFF),这里的结束地址是004322BC

打开Lord PE,选择OD当前进程,右键,选择“修正镜像大小”,再次右键选择“完整转存”(默认dumped.exe)

回到Import REC,输入OEP后点击“IAT AutoSearch”,RVA处填入32000(减去400000加载基址),Size处填入700(也就是0x004322BC - 0x00432000,其实也可以填大点的,比如1000),点击“Get Imports”

然后点击“show invalid”标出无效的指针,右键,移除之

最后点击“Fix Dump”,选中dumped.exe,保存修复后的文件自动命名为dumped_.exe,运行成功

查壳显示无壳

PECompact 2.X手工脱壳

查壳:PECompact 2.X

拖入OD

这里使用ESP定律寻找OEP,有push就必有pop:在push之后的ESP上下断点,这里能看见push之后的指令是mov dword ptr fs:[0],esp。下完断点后按运行(F9)


运行到断点处程序会在这个给位置停下来,注意当前内存地址(00455CCC)

然后取消所有断点:菜单->Debug(调试)->Hardware Breakpoints(硬件断点):删除所有断点


这里需要往下看,先往下找到第一个跳转,这个跳转指令位于00455D78这个位置。再往下找到第二个跳转的指令jmp eax,位于00455D8E这个位置;第二个指令跳转的就是OEP

(注意:这里有个retn的指令,这里需要把它改成nop,要不然会直接跑飞崩溃,如果没有就忽略这一步。这是走了些弯路总结出来的)

F8开始单步跟踪,跟踪到第二个跳转之后就来到了OEP

用OD自带的脱壳插件进行脱壳:修改OEP,保存为00.exe

运行 + 查壳

KByS Packer手工脱壳

查壳:KByS Packer v0.28

拖入OD进行动态调试

寻找OEP
方法一: 单步追踪:一路F8,遇到回跳就选中下一条指令F4,直到没有各种密集的调用/跳转/运算 OR 看见空白,即为OEP,直接用OD的脱壳插件脱壳
(e.g.: 运行到00454E0F时,往回跳转,选中00454E0F,F4)

最后到达OEP

右键调用OD脱壳插件进行脱壳,保存为00.exe

查壳 + 运行

方法二: ESP定律(其实和方法一没有本质区别)
选中pushas指令,F4运行到这条指令,然后按一下F8单步到下一条指令:看到寄存器只有ESP和EIP红了

选中ESP,选择硬件断点

再来到左下角的窗口,右键->断点->硬件访问->字

F9运行后会中断

删除断点,剩下的就和方法一一样了,不多赘述。最后来到OEP,插件脱壳,保存为11.exe,查壳 + 运行

(Win)Upack手工脱壳

查壳:(Win)Upack 0.37-0.39

拖入OD

**ESP定律轻松秒杀:**F8单步一下,寄存器只有ESP和EIP红了,在ESP处进行跟随

在跟随处下一个硬件访问断点,F9运行到断点处 + 删除断点


F8单步,直接来到OEP

OD脱壳插件脱壳,保存为00.exe


查壳 + 运行

RLPack手工脱壳

查壳:RLPack 1.19 Basic Edition

拖入OD进行动态调试

通过观察,能发现pushad的下一条指令是个call,call的地址就在这条call指令的下面,所以这里在call的地方使用ESP定律直接秒杀:F8单步一下到这个call指令,发现右边只有ESP和EIP红了

ESP处内存跟随

跟随处下一个硬件断点:断点->硬件访问断点->字,然后F9运行

程序在断点处停了下来,发现这是个大跳,OPE就是这个大跳所跳转的地址

单步一下到OEP,用OD脱壳插件脱壳,保存成00.exe

查壳显示无壳,但运行发现崩溃

Import REC修复导入表和IAT表(修改OEP,这里好像不需要修改导入表的RAV,如果在获取导入表之后,上面的函数表只有很少的函数名,就需要用到Lord PE修正镜像大小 + 完整转存 + 手工修复IAT表和输入表,详见“FSG脱壳”部分),最后“Fix Dump”选择从OD脱壳dump出来的00.exe

查壳显示无壳但是还是运行崩溃,就需要采用
FSG手工脱壳的方法


继续:Lord PE修正镜像大小 + 完整转存,保存为默认的dumped.exe

Import REC修改OEP,搜索IAT表,获取输入表,“Fix Dump”选择上面的dumped.exe,最后得到dumped_.exe

查壳 + 运行:成功脱壳