阅读须知:
探索者安全团队 技术文章仅供参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作,由于传播、利用本公众号所提供的技术和信息而造成的任何直接或者间接的后果及损失,均由使用者 本人负责,作者不为此承担任何责任,如有侵权烦请告知,我们会立即删除并致歉,创作不易转载请标明出处.感谢!
壳的认识
- 壳就是给文件穿上了一件衣服,使你看不见他原本的样子,其实程序在计算机上实际上就是一段 二进制数据 ,而壳就是对这段 二进制数据 进行了加密操作,在学习PE文件时可以对可执行程序有更深的了解这里不过多介绍。但是加壳后的程序本身的运行却不受影响,是因为在执行真正的程序前会执行一段"解壳"的代码,来恢复原本的程序,手动脱壳就是要将"解壳"后的 真实程序dump 下来为己所用。
- 从上面看来,壳似乎对动态调试程序影响不大,因为无论是否加壳程序依旧可以运行,所以壳大部分只会对静态分析程序的原本代码造成印象。
工具脱壳
- 其实关于许多常见的壳,例如upx壳已已经有现成的工具来脱壳,但是对于一些加密壳,修改壳和目前没有脱壳工具的壳,就必须手动脱壳了。
手动脱壳的原理
- 手动脱壳的而原理,依赖于壳在执行前会将主程序所用到的寄存器(ax,bx,cx)等,会压栈(pushab)保存,在壳执行完成后再出栈(popab)。
- 手动脱壳的目的就是,就是在执行完"壳程序"后,找到正真程序并将其保存(dump)。
- 在实行程序前,壳程序会优先获得程序的控制,将程序恢复并加载进入内存。
实际操作
- 例题为:[HZNUCTF 2023 final]signin,只就手动脱壳进行操作,不关心题目本身!
- 工具为x64dbg/x32dbg,大家壳自行下载。
- 首先将程序拖入x64dbg,中。
- 单步F8步过,或者直接F9,找到pushab指令,如果没有Pushab指令,则继续单步调试,直到仅有 Esp寄存器爆红 (证明可以使用栈平衡脱壳):
- 此时,寄存器的值已经入栈,通过观察 栈的窗口 或 内存窗口 两者均显示了压栈的寄存器的值,可以看见,ax,bx,cx,dx寄存器的值均一入栈:
- 此时在栈上地址为006ff908处(此处保存了寄存器ax的值)打上硬件访问断点(1,2,4字节无所谓),这样在壳程序执行完成后 寄存器出栈时会自动暂停,一定时硬件访问断点(级别比写入断点更高,只要 访问 这个内存位置就会停下来)。
- 接下来,直接F9到刚才打的断点处,可以惊喜的发现,梦寐以求的pushab指令正在此处:
- 此时,实际上已经脱壳完毕,但是一直单步步过会发现,一直在一个向上跳转的循环里,观察这股循环可以发现循环的作用是一直在压栈,并与ax寄存器里的值进行比较,直到相同才退出,push的值一直是0,推测这个循环的作用是将堆栈中的值清零,这样也解释了前面在进入壳程序时为什么要进行压栈操作,ax其保存了壳程序使用的栈空间(栈低相差80*2个字节),在退出壳程序后需要清空。在跳转指令后面打上断点后F9即可跳出循环。
- 到jmp指令这里可以发现esp栈指针已近已经到了进入壳程序前的位置。
- 插件栏,使用Scylla插件(先清楚掉之前打的断点),将文件dump下来:
- 脱壳完成直接拉入ida进行静态分析,此时ida可以进行静态分析,虽然程序无法执行:
- 脱壳前拉入ida时并没有这么多函数,ida无法反汇编分析:
总结:
- 手动脱壳时时刻关注esp寄存器,来找到正真程序的入口。
感谢大师傅波克比QWQ的精彩投稿,对于小白的小编来讲,又能学到好多好多东西,喜欢的小伙伴可以点点赞哦!