逆向-手动脱壳
手动脱壳
单步跟踪法
单步跟踪法的原理就是通过单步(F8)、单步进入(F7)和运行到(F4)功能,完整走过程序的自脱壳过程,跳过一些循环恢复代码的片段,并用单步进入确保程序不会略过OEP。这样可以在软件自动脱壳模块运行完毕后,到达OEP,并dump程序。
ESP定律法
ESP定律法是脱壳的利器,是应用频率最高的脱壳方法之一。
ESP定律的原理在于程序中堆栈平衡的合理利用。由于在程序自解密或者自解压过程中,不少壳会先将当前寄存器内容压栈,如使用pushad,在解压结束后,会将之前的寄存器值出栈,如使用popad。因此在寄存器出栈时,往往程序代码被自动恢复,此时硬件断点触发。然后在程序当前位置,只需要少许单步跟踪,就很容易到达正确的OEP位置。
内存镜像法(二次断点法)
内存镜像法是在加壳程序被加载时,通过OD的ALT+M快捷键,进入到程序虚拟内存区段。然后通过加两次内存一次性断点,到达程序正确OEP的位置。
内存镜像法的原理在于对于程序资源段和代码段下断点,一般程序自解压或者自解密时,会首先访问资源段获取所需资源,然后在自动脱壳完成后,转回程序代码段。这时候下内存一次性断点,程序就会停在OEP处。
一步到达OEP
所谓的一步到达OEP的脱壳方法,是根据所脱壳的特征,寻找其距离OEP最近的一处汇编指令,然后下int3断点,在程序走到OEP的时候dump程序。如一些压缩壳往往popad指令距离OEP或者Magic Jump特别近,因此使用Ollydbg的搜索功能,可以搜索壳的特征汇编代码,达到一步断点到达OEP的效果。
最后一次异常法
最后一次异常法的原理是,程序在自解压或自解密过程中,可能会触发无数次的异常。如果能定位到最后一次程序异常的位置,可能就会很接近自动脱壳完成位置。现在最后一次异常法脱壳可以利用Ollydbg的异常计数器插件,先记录异常数目,然后重新载入,自动停在最后一次异常处。
模拟跟踪法
模拟跟踪法的原理就是使用Ollydbg下条件断点,SFX相当于是一个自解压段,在自解压段结束时(eip的值转到代码段时),已经距离OEP很近,但是这种跟踪方法会比较耗时。
“SFX”法
“SFX”法利用了Ollydbg自带的OEP寻找功能,可以选择直接让程序停在OD找到的OEP处,此时自解压已经完成,可以直接dump程序。
链接
原创] 借助 x64dbg 的 UPX 手工脱壳-加壳脱壳-看雪
文章 - Windows逆向之脱壳-IAT修复 - 先知社区
PE格式:手工实现各种脱壳后的修复 - lyshark - 博客园
实例
查壳,UPX壳,64位
试着运行一下
用x64dbg打开,打开断点查看,可以看到x64dbg自动为我们设置了几个断点,其中第三个断点是我们的入口断点
我们可以删除前两个断点,只保留入口断点
然后直接按F9
运行,到push rbx
断点处,此时栈顶RSP D8EA8FFB88
接着按F8
步过,把rbx
压入栈,栈顶RBP D8EAFFB80
在RSP
处下硬件断点,因为是64位程序,所以选4字节
按F9
运行到硬件断点,可以发现已经pop rbx
,当前面出现了一点麻烦,因为前面有一个回跳,不知道要执行多少次
接着可以,按F8
运行到cmp
处,在jne
下面一行下一个断点,选中那一行,按F4
运行到选区,即可解决回跳
此时,前面又有一个Jmp
,但发现是一个大跳转(一般小跳转左边会显示跳转到哪的虚线,如前面那个回跳)
但一般出现大跳转,那么一般就是程序的入口了(OEP),但不一定,也许是后面出现的大跳转,具体是怎么回事之后在弄清楚
接着按F7
步入jmp
,选择x64dbg自带的插件-scylla,可惜的是我的没有自带,于是到github下了一个,注意改好OEP,直接dump就行
dump后的程序可能不能直接运行,需要修复IAT(导入表),但可以用IDA反编译
- UPX加壳之前的样子,再用
upx -d
之后打开也是原样
- UPX加壳后手动脱壳的样子(没有修复导入表IAT)