|
0x0 前言
最近在跟进一个APT组织的一次攻击,其中有一个样本使用了Arm加壳,所以花了差不多10多天的时间看看这方面的东西。并总结一下。
这篇文章主要参考了FLY和刹那恍惚两位大佬的文章。和录制的视频。以及jcyhlh大侠在2008年写下的总结帖。那时候我估计还在玩泥巴呢。这是我写这篇文章的主要参考来源。前人栽树后人乘凉。此外还看了看雪的知识库。基本看了3.x和4.x所有师傅的文章。
这篇文章的架构,文章架构主要参照了网上下载的视频教程的架构。并对此作出小小修改和注释以及归纳总结。更加方便我等小白学习成长。
由于文章主要脱去的是3.x和4.x的Arm,可能有一些伪大佬又要说都发了几百遍了还在发。。对此我的处理意见是,把其直接挂在文章起始部分。
这篇文章适合我等小白,所以伪大佬勿扰。真大佬可以daidaiwo
最后,加油吧,小伙伴们。
0x1 Armadillo
0x1.1 保护机制
Armadillo,中文名穿山甲,本意为犰狳,就是下面那个有点可爱的家伙。

Armadillo主要采用了Debug-Blocker,CopyMem-II, Enable Import Table Elimination,Enable Nanomites Processing,Enable Memory-Patching Protections保护手段。同时也有单双进程之分,造成了保护手段的多样性。
Debug-Blocker,称为阻止调试器,所谓反调试,基本只要开插件都可以过,所以这也是为什么大家脱穿山甲的时候打开IsProcessDebug去反调试选项和忽略异常的原因。
CopyMem-II:双进程保护,最常使用的是bp OpenMutexA,然后转到401000 patch代码。另外一种是修改相反跳转的方法。(脚本方法就是不说了)
Enable Import Table Elimination:IAT保护,修改Magic_Jmp。
Enable Nanomites Processing就是CC保护,也是Armadillo最强大的保护机制。原理就是就是将程序中的部分代码改写为int3或者向其中插入int3代码。
0x1.2 前期侦壳
知己知彼百战不殆,在脱壳最重要的就是侦壳。这里需要使用到的工具主要有:PEID(不推荐),exepeinfo,ArmaFP,任务管理器。
其中,exepeinfo是用于查壳的,任务管理器是用于判断是单进程还是双进程,如果是双进程就需要双转单。ArmaFP是用于判断其保护模式,是标准模式,还是全保护模式(专业模式)。
不过关于壳的版本,exepeinfo容易误报,所以可以使用这个方法:OD载入程序,下HE OutputDebugStringA断点。shift+F9中断后,看堆栈如果出现如下的,就是4.0以上的壳。这是由于Arm在4.0利用Od在调式保护格式串的消息时会奔溃而新增的反调试技术。

0x2 Armadillo单进程脱壳
0x2.1 标准单进程Armadillo 3.78 - 4.xx 脱壳
这是最简单的加密方法,只需要修改Magic_Jmp就可以了,因为这个版本单进程防护只是加密了IAT,(1)只需要绕过加密,(2)并让其解压压缩区段即可。
绕过IAT加密的方法就是修改Magic_Jmp,这是脱穿山甲壳必须使用的方法。步骤如下:
- step1:在GetModuleHandle下硬件断点,可以HE GetModuleHandle或者HE GetModuleHandle+5。
- Step2:然后Shift+F9,断下的时候,看堆栈窗口是否存在VirtualAlloc或者VirtualFree,只要出现这两个API函数,就表明快到了。

Step3:继续Shift+F9,只要堆栈出现kernel32.dll,但是不包含任何其他函数名称,表示到达了返回的时机。此时执行到返回ctrl+F9。如何判断之前执行到返回的时机是否正确呢,就是看是否存在LoadLibrary这个API函数。此时就是正确的。

Step4:因为外壳肯定需要将存储在某一区段的数据解压到text段,需要对该段进行访问,所以,在内存窗口的程序的text段下访问断点。然后shift+F9。中断在43468F,然后单步,在此代码段的最后一个call ecx处步入就是OEP。


0x2.2 单进程Armadillo v4.x脱壳
首先需要判断加壳版本是否是http://4.xxx。关于这点如何判断呢,主要下硬件断点 HE OutputDebugStringA 。在堆栈窗口出现%s%s%s%s的标志,说明这是4.X的壳。

关于Armadillo v4.x单进程脱壳把握两点,第一,使用Magic_Jmp避过IAT加密保护,对GetCurrentThreadId下断点找到OEP
关于第一条,就是上面2.1讲的原则,下面解释第二条。首先对GetCurrentThreadId下断。HE GetCurrentThreadId。查看堆栈窗口,会出现如下结果.中间省略多个,查看关于GetCurrentThreadId都是来自其他模块的调用,但是最后一个是来自程序的调用。这就是程序返回的时机,所以,F8步过,根据之前说的规则,OEP在该程序段最后一个call ecx中。

2.3 加 PassWord单进程
这是就比2.2多了一个密码验证,我们直接绕过密码验证就好。首先Shift+F9运行,通过查看导入表,在GetDlgItem处下断bpx GetDlgItem。然后在输入伪码按OK,程序中断在35359D0处.注意:先运行,在下断!在输入

首先祭上大杀器ArmInline,欲要善其事,必先利其器。需要我们填写的就是上述三个区域,不过我这个版本可以自动填写修复的数据,只需要知道我们需要修复的进程,如图,目标进程ID为FC4,选中后依次删除拼接代码和巡回IAT基址。

然后按照常规的方法dump和修复IAT就可以了。注意的是使用PELord一定要勾选从磁盘粘贴文件头(一般默认勾选上了)
如果你的ArmInline不能自己修复(反正牛逼的师傅都是自己修复的,我不牛逼所以都是软件自动修复的),关于Code Splicing的修复可以这样,Alt+M到内存窗口,在fraps模块之后有一段内存没有被其他模块映射(不知道这样说对不对,反正对于Kernel32这样的dll来说肯定是对的。大家理解就好)。在最后一块内存处,就是拼接代码起点,这个值不是一个定值。(这个只是经验之谈,需要大佬解释一波的)

接修正IAT乱序,首先随便找个函数调用,在信息窗口点数据窗口跟随地址,然后向上拖动窗口(你最好改成显示地址)。找到IAT起始地址,然后找到结束地址,两者相减。计算大小即可。关于填充地址。可以考虑在一块没有读写的空白区域就好。不过大佬给的建议是在程序加壳前原来IAT的相近地方。可以这样寻找。Alt+M到内存窗口,因为IAT早rdata区域,又因为IAT肯定保存了一些IID成员,其中有个Name成员,也就是DllName。我们通过全局搜索确定

0x3 Armadillo双进程脱壳
这一章节主要讲穿山甲的双进程保护手段。所以双进程保护,简单的来说就是创建两个进程,一个进程是另外一个进程的调试进程,又由于在R3下面一个进程只能被一个调试器附加。这样可以有效避免程序被调试。
0x3.1 标准保护
接下来简单讲解一下关于双进程保护的原理,主要可以利用互斥体来判断进程列表是否存在相同的进程(即多开)。首先是利用CreateMutex创建一个互斥体。然后在利用OpenMutex打开那个互斥体,如果OpenMutex成功返回互斥体句柄,说明已经存在一个进程。如果不存在则在CreateProcess一个进程。而对于穿山甲壳双转单也是如此。如果提前创建了一个即将被打开的互斥体。那么程序就不会去创建新的进程。如下的脱壳方法就是基于这点考虑。
首先对openMutex下断点(HE,bp皆可)。HE openMutexA,然后shift+F9。观察堆栈

0x3.2 CopyMem-II
去除CopyMem-ll 保护通常有两个方法。
方法1:首先寻找OEP,然后对WaitForDebugEvent下断点bp WaitForDebugEvent,接着运行程序,看堆栈,当出现pDebugEvent字符的时候,选择在数据窗口跟随,然后对WriteProcessMemory下断bp WriteProcessMemory,中断后,在数据窗口发现OEP。
这里重点讲一下第二个方法:
- bp WaitForDebugEvent,shift+F9运行起来,删除断点,然后执行到程序领空,大概停在0060F8BA

- 然后Ctrl+F搜索命令:or eax,0FFFFFFF8,想上看有两个比较,一个是cmp dword ptr ss:[ebp-0xA34],另外一个是cmp ecx,dword ptr ds:[0x64AF48],然后对第一个cmp下断点,F9运行。这一步你需要记住以下内容,等下patch的时候需要用到内容,第一:第一个cmp的地址0060FE43,第二:第一个cmp【】内的值ebp-0xA34,第三:第二个cmp【】的值:0x64AF48.除此以外,需要将次一个cmp栈里面的数据清0

0x4 带KEY的Armadillo
0x4.1 单进程
带KEY的Armadillo相当于给软件多了一层保护,我们此时还不能通过爆破的方式解决这个KEY,原因有2,第一,OD对于这类情况不提供修改的选项,第二,就算爆破成功了,后期软件中还存在暗桩。所以可以逆向算法的方式得到一组合适的KEY。
首先shitf+F9运行起来,不要管出现的对话框,首先随便输入个Key,然后下HE GetDlgItem断点即可。取消断点,ALT+F9执行返回。大概停在此处。




打好补丁后,在401000处F2下下断点,然后返回,剩下的使用上面讲的方法就可以脱去。
0x4.1 双进程
得鸽一下。
0x5 DLL脱壳
0x5.1 DLL脱壳
修改Magic_Jmp绕过IAT加密。

0x6 非常规方法应对
0x6.1 应对IAT加密
这里使用了非常简单的Arm作为示范,只含有IAT加密,不涉及其他,第二常规方法下建议使用增强版OD。
通常规避IAT加密的方法就是Magic_Jmp,然后.text下断到OEP。这里前辈给出新方法。介绍一下。
首先须要了解到Arm并不是对所有的API函数进行加密,前辈这里的思路是先直接到达OEP,在根据里面一直的函数地址寻找IAT地址,然后寻找出IAT中被加密的地方,下硬件断点。重新运行之后到达被修改的的地址,然后分析加密IAT的过程,使用jmp或者nop规避即可。
在.text下断,然后F9运行,程序到达OEP,只是IAT被加密了。


本文由看雪论坛 findreamwang 原创
原文链接:[原创]一篇文章带你学会Armadillo脱壳-『加壳脱壳』-看雪安全论坛 |
|