程序脱壳
- 1 视频也可以含恶意代码吗
- 2 Frida 入门
- 3 虚拟机保护
- 4 C#逆向入门
- 5 安卓刷机一点通
- 6 Z3-Solver教程
- 7 出题人的“恶意”
- 8 编译器为我做了什么
- 9 CSAPP Lab2 Note
- 10 Hash系列算法
- 11 程序脱壳 本文
- 12 安卓逆向介绍
- 13 IDA类型修复
- 14 IDA疑难杂症
- 15 花指令
- 16 反动态调试技术与应对手段
- 17 AES加密算法
- 18 如何解决魔改后的加密算法
- 19 常见加密算法识别与变种分析
- 20 TEA 加密算法
- 21 RC4 加密算法
- 22 Base64 编码
- 23 IDA Dynamic Debugging
- 24 IDA Usage With Reverse Basic
壳 (packer) 是一种程序压缩与保护手段,有时称为“可执行程序资源压缩”。加壳过的程序可以直接运行,但是不能查看源代码,要经过脱壳才可以查看。
加壳是利用特殊的算法,对EXE、DLL文件里的资源进行压缩、加密。压缩之后的文件可以独立运行,解压过程完全隐蔽,都在内存中完成。
原始程序代码在磁盘文件中一般是以加密后的形式存在的,只在执行时在内存中还原,这样就可以比较有效地防止破解者对程序文件的非法修改,同时也可以防止程序被静态反编译。当然,很多恶意软件为了“隐藏自己”免受安全软件的查杀,也会使用加壳器。
壳的类型通常分为压缩壳和加密壳两类。压缩壳的特点是减小软件体积大小,加密保护不是重点;加密壳种类比较多,不同的壳侧重点不同,一些壳单纯保护程序,另一些壳提供额外的功能,如提供注册机制、使用次数、时间限制等。但如今这两类壳的界限并不清晰,有的壳兼具压缩和加密功能。
壳的加载
- 保存入口参数
- 加壳程序初始化时保存各寄存器的值
- 外壳执行完毕,恢复各寄存器值
- 最后再跳到原程序执行
通常用 pushad / popad、pushfd / popfd 指令对来保存和恢复现场环境
- 获取所需函数 API
- 一般壳的输入表中只有
GetProcAddress、GetModuleHandle和LoadLibrary这几个 API 函数 - 如果需要其他 API 函数,则通过
LoadLibraryA(W)或LoadLibraryExA(W)将 DLL 文件映射到调用进程的地址空间中 - 如果 DLL 文件已被映射到调用进程的地址空间里,就可以调用
GetModuleHandleA(W)函数获得 DLL 模块句柄 - 一旦 DLL 模块被加载,就可以调用
GetProcAddress函数获取输入函数的地址
- 解密各区块数据
- 处于保护源程序代码和数据的目的,一般会加密源程序文件的各个区块。在程序执行时外壳将这些区块数据解密,以让程序正常运行
- 外壳一般按区块加密,按区块解密,并将解密的数据放回在合适的内存位置
- 跳转回原程序入口点
- 在跳转回入口点之前,一般会恢复填写原 PE 文件输入表 (IAT),并处理好重定位项(主要是 DLL 文件)
- 因为加壳时外壳自己构造了一个输入表,因此在这里需要重新对每一个 DLL 引入的所有函数重新获取地址,并填写到 IAT 表中
- 做完上述工作后,会跳转到原始入口点 (OEP),将控制权移交原程序,并继续执行
如何脱壳
脱壳分为机脱和手脱。
如果加壳器有对应的脱壳脚本且原程序未对加壳结果进行修改,那么机脱是最优雅且快捷的,比如 UPX 壳。脱 UPX 壳最好的办法就是 upx -d。1机脱我们不多做介绍,这更多考验搜索能力和 PY。
当然,有的壳是没有(完整的)脱壳机的,而有些谨慎的程序员也会给壳添油加醋,这时就不得不进行麻烦的手脱了。
UPX 部分手脱
UPX 作为入门最常见的壳,官方程序自带脱壳功能。然而,仅仅是 upx -d 实在没有技术含量,因此进阶一点的 UPX 题目就会再次修改 UPX 加壳后的程序,使得 upx -d 失效。
upx -d 脱壳主要利用加壳时候写到加壳程序里的 PE 信息,直接抹掉原始加壳的留下的 PE 头信息就无法直接 upx -d 脱壳了。
- 修改/删除特殊区段名
UPX 压缩过的程序有特殊区段名
UPX,十六进制表示为55 50 58。如果修改/删除区段名,那么upx -d就无法识别了,而程序仍然能运行。UPX区段保存着程序的压缩信息,在一定程度上可以验证程序的完整性。 UPX 压缩的程序还有一个区段.rsrc,这是程序的头部和部分资源数据段,有时是UPX2。 解决办法就是将修改的区段名恢复成UPX或.rsrc,一般来讲,程序中有 3 - 4 个 UPX 特征区段名,要看看它们是否全部修复。 另一个更强硬的手段就是直接删除 UPX 特定区段的字节,这样做甚至会损坏程序的运行。 总结起来,你需要的关注的地方有这些:1)UPX0、UPX1和.rsrc/UPX2;2)5.01 UPX! $,数字代表程序使用的 UPX 版本,UPX! $标志从此处开始解压原始程序。
手动脱壳常用方法
脱壳的主要目的是:找到 OEP,在 OEP 处设置硬件断点。如果想更近一步,就要输出脱壳后的程序到文件,并修复运行。
基本步骤:
PECompact 手脱
PECompact 是一种简单的压缩壳,手脱起来还是比较简单易懂的 ^-^
Footnotes
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!