-
-
[原创]Armadillo(补充)及实例
-
发表于: 2025-2-11 22:11 1567
-
这篇文章作为上一篇的补充,并提供一个实例。如果觉得实例中有突兀奇怪的地方,可以参考上篇文章。
高级保护(补充)
① Enable Nanomites Processing(cc保护)
此壳被称为强壳,其关键在于CC保护。Armadillo 会抽取被保护程序中的一些 JCC 指令,并将判断逻辑移至主程序中。实现方式是将每个JCC指令的第一个字节替换为INT 3 指令。当子程序执行到INT 3 时,会触发断点异常(0x80000003)。主程序在接收到该异常后,会利用 GetThreadContext 函数获取标志寄存器的值,以判断是否进行跳转。最后,再通过SetThreadContext函数设置指令指针(EIP),以控制子程序的执行流。要过掉此保护,难点在于需要花费大量时间解析JCC指令与约定数字之间的映射关系,以及跳转地址的信息。有关详细的过程,可以参考这篇文章:ARMADILLO和NANOMITES。
② Enable Import Table Elimination(输入表乱序)
略
③ Enable Strategic Code Splicing(代码乱序拼接)
代码乱序拼接是通过提取程序中的某些代码片段,并对其进行混淆处理。当程序执行到被提取的代码部分时,会跳转到指定地址,执行完成后再返回继续执行。这样做的目的是为了防止程序被 dump(内存转储),从而增强保护机制。
在上图中可以迅速识别出,只有两条指令是有效的,分别是"mov ebx ,A"和"push esp"。
以下总结此壳指令混淆的一些特征:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | / / = = = = = = = = = = = 特征 1 : = = = = = = = = = = / / not reg1 ... ... ... not reg1 / / = = = = = = = = = = = 特征 2 : = = = = = = = = = = / / xchg reg1,reg2 ... ... ... xchg reg1,reg2 / / = = = = = = = = = = = 特征 3 : = = = = = = = = = = / / push reg1 ... ... ... pop reg1 / / = = = = = = = = = = = 特征 4 : = = = = = = = = = = / / bswap reg1 ... ... ... bswap reg1 / / = = = = = = = = = = 特征 5 : = = = = = = = = = = / / 地址 1 : jcc / jmp 地址 2 地址 2 : / / = = = = = = = = = = 特征 6 : = = = = = = = = = = / / 地址 1 : jcc 地址 3 地址 2 : 地址 3 : / / = = = = = 特征 7 (冗余指令): = = = = = / / xchg / mov reg1,reg1 |
特征1示例,如下图:
这些指令的混淆相对简单,因此还原起来也比较容易。如果想要增强混淆效果,可以先对整个函数进行静态分析,提取相应的指令,然后再进行混淆处理。假如处理得当,几乎可以达到无法还原的效果。即使程序被内存转储(dump),分析人员也只能通过补区段的方式进行处理,这将给他们带来极大的困扰。
④ Enable Memory-Patching Protections(防止内存补丁保护)
该保护有以下几项保护功能。
1. 内存完整性检查
该保护机制会定期检查程序的内存区域,以确保其未被篡改。通过计算和验证内存区域的校验和或哈希值,来检测是否有未经授权的修改。
2. 反调试技术
保护机制可能会使用反调试技术来检测和阻止调试器的附加。这可以防止攻击者在调试器中修改程序的内存。
3. 代码混淆和加密
通过混淆和加密关键代码段,使得即使攻击者能够访问内存,也难以理解和修改程序的逻辑。
4. 动态代码生成
在运行时动态生成和执行代码,以防止静态分析和内存补丁。动态生成的代码通常会在执行后立即被清除,以减少被捕获的风险。
5. 自我修复机制
如果检测到内存被篡改,程序可能会触发自我修复机制,恢复被修改的内存区域,或者直接终止程序运行。
6. 内存陷阱
在内存中设置陷阱或诱饵区域,诱导攻击者进行修改。一旦这些区域被修改,程序会立即检测到并采取相应措施。
Ball5(实例)
Ball5来自黑鹰 VIP 破解提高班第 46 课提供的资料。
简介
Ball5是一款桌面台球的作弊软件,有试用次数,主界面如下:
脱壳分析
经过Detect It Easy查看,是Armadillo壳。
再用Armadillo find protected工具查看,可以看到,开启了双进程保护。
因此,可以在WaitForDebugEvent设置断点,触发断点后,取消该断点。接着在WriteProcessMemory处设置断点,以收集回填到子进程代码区的数据。请注意,同一个区域的数据可能会被填写多次,只收集第一次的数据,其余都要忽略掉。这个其实就是绕过高级保护中Enable Memory-Patching Protections(防止内存补丁保护)的动态代码生成功能。在程序运行时,尽量点击所有按钮,以确保相关的代码区能够被解码并收集到。
对于OEP,当第一次接收到异常调试事件,且异常码为0x80000001时,产生异常的地址就是该程序的OEP地址,参考下图:
接下来,寻找IAT加密的部分。当收集到相关信息后,重新开始调试。这次,当第一次接收到异常码 0xC0000005 时,可以挂起子进程的所有线程,接着调用 DebugActiveProcessStop 函数以脱离子进程。然后附加子进程,并在 GetModuleHandleA 处设置硬件断点。恢复主线程后,按 Shift + F9 三次,观察堆栈变化(下图所示)。取消断点后,返回用户代码区。
在相隔不远位置,就能找到关键指令je 1FA612F,把此条指令改为jmp 1FA612F,就可以跳过IAT加密了。
注意,在执行上面操作时,再往下拉不是很远。在 jmp 246149 处设置软件断点后,再按 F9 运行。当断点触发后,取消该断点,然后将之前的 jmp 1FA612F 改回 je 1FA612F。这个其实就是绕过高级保护中Enable Memory-Patching Protections(防止内存补丁保护)的内存完整性检查功能。
最后,在 OEP 处设置硬件执行断点。当程序运行到 OEP 后,将收集到的代码区数据复制到相关区域,就可以使用 Scylla 工具进行脱壳了。需要注意的是,Scylla 有时无法准确识别 IAT 表数据的大小,此时需要手动填写IAT表的大小。对于无效的IAT地址,直接剪掉即可。
去框分析
运行Ball5时,弹出如下窗口,点击 "开始使用" 时,才会弹出主界面。现在需要去掉此窗口,以便在点击程序后直接就能进入主界面。
启动并调试Ball5,当程序运行弹出上述窗口时,在 DestroyWindow 处设置断点。点击“开始使用”后,该断点会被触发,然后返回到用户空间,回溯即可找到关键位置 0x45EDC5。将je指令修改为 jmp,即可去掉启动窗口。
附件
附件上传的是Ball5程序的安装压缩包。
[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!
赞赏
- m_nasm项目简介 1419
- [原创]Armadillo(补充)及实例 1568
- [原创]Armadillo_9.64加壳脱壳分析 11685
- [原创]Intel AVX512指令集 - 前缀浅析 8193
- [原创]密码学综合工具(更正v0003) 43678