首页
社区
课程
招聘
[原创]一篇文章带你学会Armadillo脱壳
发表于: 2019-5-3 14:28 25199

[原创]一篇文章带你学会Armadillo脱壳

2019-5-3 14:28
25199

         最近在跟进一个APT组织的一次攻击,其中有一个样本使用了Arm加壳,所以花了差不多10多天的时间看看这方面的东西。并总结一下。

         这篇文章主要参考了FLY和刹那恍惚两位大佬的文章。和录制的视频。以及jcyhlh大侠在2008年写下的总结帖。那时候我估计还在玩泥巴呢。这是我写这篇文章的主要参考来源。前人栽树后人乘凉。此外还看了看雪的知识库。基本看了3.x和4.x所有师傅的文章。

         这篇文章的架构,文章架构主要参照了网上下载的视频教程的架构。并对此作出小小修改和注释以及归纳总结。更加方便我等小白学习成长。

         由于文章主要脱去的是3.x和4.x的Arm,可能有一些伪大佬又要说都发了几百遍了还在发。。对此我的处理意见是,把其直接挂在文章起始部分
这篇文章适合我等小白,所以伪大佬勿扰。真大佬可以daidaiwo
         最后,加油吧,小伙伴们。

         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代码。

         知己知彼百战不殆,在脱壳最重要的就是侦壳。这里需要使用到的工具主要有:PEID(不推荐),exepeinfo,ArmaFP,任务管理器。

         其中,exepeinfo是用于查壳的,任务管理器是用于判断是单进程还是双进程,如果是双进程就需要双转单。ArmaFP是用于判断其保护模式,是标准模式,还是全保护模式(专业模式)。

         不过关于壳的版本,exepeinfo容易误报,所以可以使用这个方法:OD载入程序,下HE OutputDebugStringA断点。shift+F9中断后,看堆栈如果出现如下的,就是4.0以上的壳。这是由于Arm在4.0利用Od在调式保护格式串的消息时会奔溃而新增的反调试技术。

         这是最简单的加密方法,只需要修改Magic_Jmp就可以了,因为这个版本单进程防护只是加密了IAT,(1)只需要绕过加密,(2)并让其解压压缩区段即可。

         绕过IAT加密的方法就是修改Magic_Jmp,这是脱穿山甲壳必须使用的方法。步骤如下:

         首先需要判断加壳版本是否是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.2多了一个密码验证,我们直接绕过密码验证就好。首先Shift+F9运行,通过查看导入表,在GetDlgItem处下断bpx GetDlgItem。然后在输入伪码按OK,程序中断在35359D0处.注意:先运行,在下断!在输入

         接着修改魔法跳,可以使用bp GetModueHandle或者HE GetModuleHandle。这里发现了kernel32.dll就可以执行到返回查看了。

         然后就是找OEP,这里还是可以使用2.2中对GetProcessId下断。这里介绍个新方法。**可以在内存窗口.text段按F2下断点。因为壳执行完肯定会执行代码段的内容。也就是说代码段是由外壳到源程序的一扇门。所以在此处下断必然成立。

         总结一下,现在有两个方法可以找OEP。第一是对GetProcessId下断,第二个就是在.text下断。

         Armadillo使用Code Splicing和Import Table Elimination两项技术使得程序修复变得更加困难。幸好有大佬开发了ArmInline工具可以使得修复变得简单一些。注意:本节只将修复,不讲程序优化。

         当我们寻找到OEP之后,就可以着手修复Code Splicing和Import Table Elimination了。

         首先祭上大杀器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。我们通过全局搜索确定

         这一章节主要讲穿山甲的双进程保护手段。所以双进程保护,简单的来说就是创建两个进程,一个进程是另外一个进程的调试进程,又由于在R3下面一个进程只能被一个调试器附加。这样可以有效避免程序被调试。

         接下来简单讲解一下关于双进程保护的原理,主要可以利用互斥体来判断进程列表是否存在相同的进程(即多开)。首先是利用CreateMutex创建一个互斥体。然后在利用OpenMutex打开那个互斥体,如果OpenMutex成功返回互斥体句柄,说明已经存在一个进程。如果不存在则在CreateProcess一个进程。而对于穿山甲壳双转单也是如此。如果提前创建了一个即将被打开的互斥体。那么程序就不会去创建新的进程。如下的脱壳方法就是基于这点考虑。

         首先对openMutex下断点(HE,bp皆可)。HE openMutexA,然后shift+F9。观察堆栈

         接着需要创建互斥体。转到401000处编写汇编代码,为什么需要401000,因为这是.text段,但是理论上在哪里修改都可以。然后将EIP修改到401000处,就可以在这里执行了,然后shitf+F9.

         接着就是处理加密IAT和跳转OEP,DUMP的问题了。最后到达OEP如下:

         去除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

接下来patch数据,我们向下看,找到add eax,0xff语句,在这里就可以patch了

接着shift+F9,中断在006100F8处,就可以dump处子进程了

         接下来就是还原IAT

首先对DebugActiveProcess下断点BP DebugActiveProcess这样是为了寻找子进程,在堆栈窗口发现子进程ID为D84(不定)。接着重新打开一个OD,附加子进程,然后F9+F12,中断在入口点

将死跳转字节EB FE正常指令字节55 8B,然后就可以执行我们上节讲的双变单了。在401000修改完双转单代码后,shift+F9跑起来,再次中断在OpenMutexA处。

         带KEY的Armadillo相当于给软件多了一层保护,我们此时还不能通过爆破的方式解决这个KEY,原因有2,第一,OD对于这类情况不提供修改的选项,第二,就算爆破成功了,后期软件中还存在暗桩。所以可以逆向算法的方式得到一组合适的KEY。

         首先shitf+F9运行起来,不要管出现的对话框,首先随便输入个Key,然后下HE GetDlgItem断点即可。取消断点,ALT+F9执行返回。大概停在此处。

         然后向上找,找到这个函数开始地方,也就是上一个ret的下个指令.然后下硬件执行断点。然后重新载入,shitf+F9

         此时中断在之前下的执行断点处。单步走到021B4478处的第一个大跳转je 021B45F2右键跟随。

         跟随到021B45F2处,F2下断点,执行到此处,继续单步跟。

         一直到021B4689处

         在021982C2步入,执行到021A59FA处可以发现EAX就是硬件号3C6663B2。接着在一个可以执行的代码段打补丁

         ctrl+g,输入00401000然后输入如下内容

         打好补丁后,在401000处F2下下断点,然后返回,剩下的使用上面讲的方法就可以脱去。

         得鸽一下。

         修改Magic_Jmp绕过IAT加密。

         接下来就是和exe脱壳不一样的地方,处理重定位表。大佬这边的操作有点不明白,哪位师傅如果知道告知一下。首先对GetTickCount下硬件断点HE GetTickCount,然后shitf+f9,观察堆栈是这个结果的话,删除断点,并返回.程序停在029AC3C8处。

         然后ctrl+s,搜索,之后在找到的地址下断运行。就会出现如下黄色字体,记住标记的重定位RVA=6000和size=3B0.并将029ACFB8处跳转改为绝对跳转

         此处提供另外一种方法,首先在内存窗口,在PE文件头下访问断点,然后shift+F9中断到029A9BC7,这里是DLL文件的文件头区域

         接着ctrl+s搜索如下指令

         我们先来跟一下。这里是为了获取pdata,reloc

         此时,当我们遍历到了reloc的时候,也就是eac为reloc的时候,在信息窗口显示的数据就是reloc的RVA=6000。size=3B0

         绕过重定位表处理之后,直接在 EdrLib .text段上下F2断点,然后shitf+f9直达OEP,注意并不是在LoadDll.exe的text段,而是需要脱壳的DLL的text段下断点。

         接下来就可以dump程序了,在LordPE目录中修改重定位信息。因为没有处理重定位表,所以只需要修复DLL原来的重定位表的RVA和大小就行了。

         因为没有修改IAT表,所以IAT表的数据是正确的。所以直接Ctrl+M,选中.rdata处,双击,为了方便查看选择地址显示.可以判断起始地址为A24000,结束地址为A240C8,大小为C8

         接下有有一个很秀的操作,将我们获得从A24000-A240C8的IAT数据,复制到新打开的notepad中的404000-4040C8处.这叫借鸡生蛋。然后在ImportRCE中IAT的RVA填写404000,大小填写C8就好了

         这里使用了非常简单的Arm作为示范,只含有IAT加密,不涉及其他,第二常规方法下建议使用增强版OD。

         通常规避IAT加密的方法就是Magic_Jmp,然后.text下断到OEP。这里前辈给出新方法。介绍一下。

         首先须要了解到Arm并不是对所有的API函数进行加密,前辈这里的思路是先直接到达OEP,在根据里面一直的函数地址寻找IAT地址,然后寻找出IAT中被加密的地方,下硬件断点。重新运行之后到达被修改的的地址,然后分析加密IAT的过程,使用jmp或者nop规避即可。

         在.text下断,然后F9运行,程序到达OEP,只是IAT被加密了。

         大家应该都知道IID中所有函数应该是连续的,但是这些是不连续的,应该是被加密的。但是也说过其只是对IAT部分函数地址(有歧义自行理解)进行加密。但是IAT的RVA应该是一致的。所以将IAT的起始RVA=62E4,结束RVA=6524,大小应该为240,oep为4010cc记录下来。

         我们在0040645C处下硬件断点,然后重新载入,接着按shitf+9,即可到达0218CF28处

         接着往下跟,在0218CD6B处发现比较一个,可以发现第一轮他是和RegCreateKeyA比较

         经过如下分析,我们可以知道0218CF1A处就是我们加密IAT的操作。同时也知道Arm只是针对部分IAT进行加密的。所以只需要修改之前在0218CD6B处的jnz short 0218CD88,或者位于0218CF18处的jnb short 0218CF37即可!

 
 
 
 
 
 
 
 
 
 
 
 

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 10
支持
分享
最新回复 (13)
雪    币: 21722
活跃值: (5564)
能力值: ( LV12,RANK:460 )
在线值:
发帖
回帖
粉丝
2
精前留名
2019-5-3 14:37
1
雪    币: 88
活跃值: (73)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
1.能否分享一下范例
2.0x2.1 step3撤销之前的修改是什么意思
谢谢
2019-5-3 19:29
0
雪    币: 2943
活跃值: (1788)
能力值: ( LV9,RANK:850 )
在线值:
发帖
回帖
粉丝
4
你找个软件脱一次就会明白的,之前在OD中把je改成jmp,跳过之后,再恢复现状啊,把jmp改回je
2019-5-3 20:52
0
雪    币: 2375
活跃值: (433)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
wofan[OCN] 你找个软件脱一次就会明白的,之前在OD中把je改成jmp,跳过之后,再恢复现状啊,把jmp改回je
vmp是否比Armadillo更恶心啊?
2019-5-3 21:45
0
雪    币: 2938
活跃值: (18)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
6
收藏不了了么.
2019-5-3 22:23
0
雪    币: 314
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
既然前辈是精华,那我就给你点赞
2019-5-4 21:48
0
雪    币: 26588
活跃值: (63242)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
8
fqbqrr 收藏不了了么.
2019-5-5 09:40
0
雪    币: 1725
活跃值: (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
小白我还是看不懂,还需要继续学习
2019-5-6 09:14
0
雪    币: 498
活跃值: (2314)
能力值: ( LV12,RANK:356 )
在线值:
发帖
回帖
粉丝
10
fawcgzmg 1.能否分享一下范例 2.0x2.1 step3撤销之前的修改是什么意思 谢谢
链接:https://pan.baidu.com/s/1IXJ35suU5cqpOSBbvpchGw 
提取码:bzrl 
用例和视频基本在上面,
2019-5-6 10:58
0
雪    币: 498
活跃值: (2314)
能力值: ( LV12,RANK:356 )
在线值:
发帖
回帖
粉丝
11
fawcgzmg 1.能否分享一下范例 2.0x2.1 step3撤销之前的修改是什么意思 谢谢
链接:https://pan.baidu.com/s/1IXJ35suU5cqpOSBbvpchGw 
提取码:bzrl 
用例和视频基本在上面,
2019-5-6 10:58
0
雪    币: 565
活跃值: (40)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
12
楼主链接已经失效,能再发一次吗,谢谢~
2019-8-25 18:50
0
雪    币: 245
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
楼主链接已经失效,能再发一次吗?
2019-10-8 17:31
0
雪    币:
活跃值: (421)
能力值: ( LV5,RANK:73 )
在线值:
发帖
回帖
粉丝
14
6
2020-5-1 15:01
0
游客
登录 | 注册 方可回帖
返回
//