首页
论坛
专栏
课程

Armadillo标准壳扫盲

2005-8-2 16:13 12817

Armadillo标准壳扫盲

2005-8-2 16:13
12817
【前言】
本人初学脱壳,以前只会用自动脱壳器,手动只脱过upx的壳,实在是菜鸟一个。日前有幸拿到一个共享软件,用peid一查,Armadillo 1.xx - 2.xx -> Silicon Realms Toolworks [Overlay],俺出生牛犊不怕虎,见壳就有脱的冲动,用od载入一看,傻了眼,这壳和upx的完全不同,入口点和一般程序差不多嘛。遂知道自己水平不济,驱猫上看雪拜读各位前辈的文章。无奈本人水平实在有限,看了大半天还是没理清楚过程。想起马gg曾经说过,实践是检验真理的唯一标准,于是操起工具对该软件大卸七块。经过2天的仔细研习,终于悟得精要,成功把壳干掉了。鉴于感觉入门门槛确实有点高,因此特写此文以帮助菜鸟们迈过刀山火海,飞向光明之巅:D

【术语解释】
为什么我要写这一段呢?因为我发现看高手们的脱文,最难逾越的一关是术语。高手们脱文中的各种说法,并不能马上就明白过来究竟是什么东西。因此,希望在这里把Armadillo脱文经常遇到的几个术语稍作解释。本人水平有限,如果解释有误请指出。

[OEP] 这个是Original Entry Point的缩写,中文字面意思就是程序的原入口地址。为什么叫“原”呢?通常加壳软件会把原来的程序编码存放,以防止静态反汇编分析,并在执行前先运行一段解码的程序。所以,加壳后的程序,其入口地址是直接指向解码部分的代码,而非原来的程序入口。我们脱壳所要做的工作,就是还原出原来的程序,并且每次执行时直接从原入口地址开始执行(而不需要再运行用于解码的“壳”),因此需要得知原入口地址是什么,即OEP。

[Armadillo] 传说中的猛壳,因为拼写太长,也有人缩写为arm壳。它使用多种加密手段以防止脱壳,比如检测debugger、修改IAT、还有高级版本的stolen byte和双线程解码。

[IAT] Import Address Table的缩写,也有叫输入表,引入表。它用来保存程序用到的API函数的入口地址。

[RVA] Relative Virtual Address,相对虚拟地址。win32系统会把进程读入到内存中执行,所以存在着内存地址和文件偏移的转换关系。PE文件头里面会有一个内存基址base,原来在文件中偏移为x的内容,在内存里面的偏移就变成base+x。为了区分这两种地址偏移,通常叫文件中的偏移为RVA

[magic jump](一般破文是按10多次或者20多次F9,就来到magicjump。我根本不知道怎么去判断一个新软件的magicjump在哪里,也不知道那个次数是怎么得来的,不怕,下面我会教一种我认为比较好的方法)其实所谓magic jump,是指跳过改写IAT的代码段。Armadillo的解壳过程有一个特点,就是会改写IAT。(这里我用的是“改写”而不是某些文章中的“破坏”是有原因的。曾经我在这里也困惑过,破坏带有不可恢复的意思,事实上IAT对应的地址并没有完全破坏,只是被改写成更难辨认的形式。这里举一个具体例子)

00E6E0E1    mov edx,[EA01B8]    // ~= kernel32.dll/00D4/FindNextFileA
00E6E0E7    add edx,64
00E6E0EA    call edx
00E6E0EC    mov edx,[EA0144]    // ~= kernel32.dll/016F/GetModuleFileNameW
00E6E0F2    add edx,64
00E6E0F5    mov ecx,5

这个是被改写后的IAT指向的一端程序段。里面实际工作是作还原工作。先取出edx(这里对应一个假API),然后加上64偏移才得到真正的API,再进行函数调用。FindNextFileA后面的偏移64是GetTickCount,GetModuleFileNameW后面是GetModuleHandleA,所以上面的代码相当于
call kernel32.GetTickCount
nop

call kernel32.GetModuleHandleA

这样可以使得手动脱壳过程中把IAT表弄坏(因为无法识别出正确的API),但是加壳程序却可以正常运行。是不是很狡猾?解决办法也简单,在脱壳的过程中避开执行改写IAT表的代码段,只需要修改一条指令,这条指令,正是magic jump!

能够坚持看到这里是否已经有点烦闷了?基本理论就这么多了。准备好工具了吗?让我们马上开始。

【工具】OD、LordPE、ImportREC
【过程】
【Action 1】 明察暗访OEP
OD载入程序,用插件隐藏OD,忽略所有异常,alt_m查看内存映射,在00401000处下内存读取断点,F9
程序停下来了,看到没有,熟悉的开头。没有看到?肯定你遇到异常了,shift_F9试试?
005E14E4     55              push ebp
005E14E5     8BEC            mov ebp,esp
005E14E7     83C4 E4         add esp,-1C

我们找到OEP了,马上记下吧。Action 1目标完成:OEP=001E14E4
等等,是不是打错字了?不是005E14E4吗?还记得RVA吗?通常来说,windows会把程序读到从00400000开始的连续内存空间(当然也不是一成不变,只是通常碰到的情况都是这样),也就是说你看到的OEP 005E14E4是内存的地址,它的RVA是001E14E4。明白了吗?

【Action 2】攻下桥头堡
运行到OEP预示着解码阶段的完成了。所以理论上现在内存中的是已解码的程序。先不要动OD,保持在OEP入口。运行LordPE,选刚刚运行的程序的线程,full dump,Action 2完成!

先别对着dump出来的exe笑啊,如果现在那个是最终的脱壳结果,Armadillo就不叫猛壳了,我刚刚写的一堆理论也就白费劲。喝口水再继续吧。下面才到重点。

【Action 3】扫清地雷阵
OD没有关掉吧?恩,别动它,继续保持。运行ImportREC,选择程序进程,在下面的IAT Infos needed填入刚才拿到的OEP。AutoSearch,看到RVA框变了,那个就是IAT的地址和大小了。我这里找到的数值是001ED240
回到OD,d 5ed240(还记得刚刚说过的内存偏移的换算关系吗?),看到什么了?那个就是IAT呀。记下它的样子。然后分别在第一个项目和最后一个项目下硬件写入断点。(为什么用硬件捏?因为它不影响速度,而且重新运行的时候不会没掉,呵呵)
下面重新运行吧。F9,碰到硬件断点了。还记得IAT的样子吗?继续F9,直到第一个条目和你刚刚记下的一样。现在按page up,一直向上找GetModuleHandleA

00E86AB1     6A 00           push 0
00E86AB3     FF15 D400E900   call dword ptr ds:[E900D4]               ; kernel32.GetModuleHandleA
00E86AB9     3985 90C4FFFF   cmp dword ptr ss:[ebp-3B70],eax
00E86ABF     75 0F           jnz short 00E86AD0
00E86AC1     C785 8CC4FFFF 8>mov dword ptr ss:[ebp-3B74],0E95180
00E86ACB     E9 C4000000     jmp 00E86B94
00E86AD0     83A5 68C2FFFF 0>and dword ptr ss:[ebp-3D98],0
00E86AD7     C785 64C2FFFF C>mov dword ptr ss:[ebp-3D9C],0E957C0
00E86AE1     EB 1C           jmp short 00E86AFF
00E86AE3     8B85 64C2FFFF   mov eax,dword ptr ss:[ebp-3D9C]
00E86AE9     83C0 0C         add eax,0C
00E86AEC     8985 64C2FFFF   mov dword ptr ss:[ebp-3D9C],eax
00E86AF2     8B85 68C2FFFF   mov eax,dword ptr ss:[ebp-3D98]
00E86AF8     40              inc eax
00E86AF9     8985 68C2FFFF   mov dword ptr ss:[ebp-3D98],eax
00E86AFF     8B85 64C2FFFF   mov eax,dword ptr ss:[ebp-3D9C]
00E86B05     8338 00         cmp dword ptr ds:[eax],0
00E86B08     0F84 86000000   je 00E86B94
00E86B0E     8B85 64C2FFFF   mov eax,dword ptr ss:[ebp-3D9C]
00E86B14     8B40 08         mov eax,dword ptr ds:[eax+8]
00E86B17     83E0 01         and eax,1
00E86B1A     85C0            test eax,eax
00E86B1C     74 25           je short 00E86B43
00E86B1E     A1 2800EA00     mov eax,dword ptr ds:[EA0028]
00E86B23     8B0D 2800EA00   mov ecx,dword ptr ds:[EA0028]
00E86B29     8B40 20         mov eax,dword ptr ds:[eax+20]
00E86B2C     3341 40         xor eax,dword ptr ds:[ecx+40]
00E86B2F     8B0D 2800EA00   mov ecx,dword ptr ds:[EA0028]
00E86B35     3341 28         xor eax,dword ptr ds:[ecx+28]
00E86B38     25 80000000     and eax,80
00E86B3D     85C0            test eax,eax
00E86B3F     74 02           je short 00E86B43
00E86B41   ^ EB A0           jmp short 00E86AE3
00E86B43     8B85 68C2FFFF   mov eax,dword ptr ss:[ebp-3D98]
00E86B49     8B0D 74B7E900   mov ecx,dword ptr ds:[E9B774]
00E86B4F     8B15 2800EA00   mov edx,dword ptr ds:[EA0028]
00E86B55     8B0481          mov eax,dword ptr ds:[ecx+eax*4]
00E86B58     3342 24         xor eax,dword ptr ds:[edx+24]
00E86B5B     8B0D 2800EA00   mov ecx,dword ptr ds:[EA0028]
00E86B61     3341 28         xor eax,dword ptr ds:[ecx+28]
00E86B64     8B0D 2800EA00   mov ecx,dword ptr ds:[EA0028]
00E86B6A     3341 44         xor eax,dword ptr ds:[ecx+44]
00E86B6D     8B0D 2800EA00   mov ecx,dword ptr ds:[EA0028]
00E86B73     3341 6C         xor eax,dword ptr ds:[ecx+6C]
00E86B76     3985 90C4FFFF   cmp dword ptr ss:[ebp-3B70],eax

你看到的这段可能会跟我给出的有点差异,不过很好认,会有一段mov和xor交错出现的地方,并且mov语句是完全相同的。这里是00E86B1E-00E86B76

向上找可以跳过这段代码的转跳语句,这里是
00E86B08     0F84 86000000   je 00E86B94                ;magic jump!!!!!!!!

我看到其他教程,这句是je short的,所以可能是Armadillo版本不同。不过道理都是一样,避开对IAT表的改写。
把这句改成jmp,再按F9,遇到第二个硬件断点,这时IAT转换完成。这个可是没有被做过手脚的完整IAT啊~
哦,这里别忘了,回到刚刚修改的jmp那里,改回je啊。不然后面的解码会出错导致程序异常终止了。(至少我脱的这个壳会这样。好像只有很少的脱文提到要恢复指令,反正恢复也没坏,多做一步吧,不然异常了可能还要重新来过)
再bp 005e14e4,在OEP处下断,F9,运行到OEP

【Action 4】长驱直入,胜利会师
拿出ImportREC出来吧,重新选一下进程,autosearch,步骤应该都熟悉了。这次可以点Get Imports了。如果还有unresolved pointer,就点Show Invalid,Trace Level1试试,剩下的用Cut thunk全部干掉。然后fix dump,选择Action 2 dump出来的exe,应该就多出来一个文件名后面多带一个_的exe文件。这个是脱壳后独立运行的exe啊。试试能不能运行,不行的话,调整一下ImportREC的参数再试试,有些软件不能用Add new section的。把auto search的结果填到New Import Infos,去掉Add new section再试一遍。

【Action 5】清除残余势力
脱壳出来的程序很大,因为里面包含了很多已经没用的解码程序段。为了做到完美脱壳,我们可以把没用的代码清理掉。主要过程可以参考《脱壳后软件减肥大法》http://www.pediy.com/bbshtml/BBS6/pediy6313.htm,这里就不赘述了。不过调整.idata保证VA连续的那一步我不是按它的,不需要手动调整,直接用LordPE的rebuild PE就可以了,有现成工具干吗还要造轮子了?

【后记】
当我看到脱壳出来的程序正常运行时,有一种兴奋的感觉。也许我是脱壳菜鸟,这些对高手们确实不值得一提。可是正如fly斑竹所说,我知道自己进阶了。把过程和大家共享,希望大家可以跨过入门的门槛,共同进步。

[公告]安全服务和外包项目请将项目需求发到看雪企服平台:https://qifu.kanxue.com

最新回复 (35)
henryouly 8 2005-8-2 16:19
2
0
顺便请教一下,我正在学写ollydbg的插件,打算做一个自动脱arm标注壳的咚咚(如果能力所限不能完全自动,至少可以做到配合其他工具使用,不需要在od里面慢慢设断点、改magic jump的)

现在遇到两个问题:
1、找到oep后怎么确定iat?也就是说importrec的autosearch是什么原理?
2、如何判断iat里面的thunk是否有效?(importrec的cut thunk原理)

ps,这两个问题是只在od完成操作,不借助其他pe工具的情况下。
skyege 2 2005-8-2 16:39
3
0
加精!
tcllct 2005-8-2 21:11
4
0
非常好。顶以下!
fly 85 2005-8-2 21:25
5
0
你是说写脱壳脚本吧?
避开输入表加密到OEP就行了
有不少这样的脚本,去找个看看
henryouly 8 2005-8-2 21:57
6
0
不是ollymachine的脚本。想直接用vc写插件,当然,锻炼目的为主
henryouly 8 2005-8-2 22:06
7
0
oh,找到了,是ollyscript
http://bbs.pediy.com/showthread.php?s=&threadid=13622&highlight=armadillo

看来也没办法简单判断IAT,本来想做得完美一点
ljy3282393 1 2005-8-2 23:08
8
0
写得非常好,特别适合俺等菜鸟学习!不过请问楼主:你文中所说的这个共享软件能给个下载地址吗?
hitakei 2005-8-3 00:32
9
0
Mr. Fly,

请联系我。

bianyang04@sina.com

谢谢。
henryouly 8 2005-8-3 00:53
10
0
其实我是对XDeskCal 2.1脱壳的(在论坛搜我另一篇求教的帖子就可以看到)。不过我这篇文章并不打算特别针对某个软件,而希望去帮助读者建立一个连贯的思路。具体来说,并非讲某一步应该怎么做,而是讲为什么这里应该去这样做。理解了这些思路我觉得有助于举一反三,利用这种思路去研究其他加密壳,真正是学到脱密的技巧。这才是我写此文的目的。
dfui 2005-8-3 01:00
11
0
给个下载地址。练练手。。。。。。不会就问。
不耻下问。。。。终有一天我要赶上你。
henryouly 8 2005-8-3 01:13
12
0
大哥,软件名字都告诉您了,网上随便搜一个吧,学脱壳的话搜索引擎是个好帮手。
赶上我这个目标也太低了,能赶上fly还差不多 。我也只是几天前才知道Armadillo这个壳,也是几天前才弄清楚怎么脱。而且这个还是初级的版本,高级版本尚没机会碰,应该技术含量更高。一起努力吧!
寒江雪 2005-8-3 09:22
13
0
刚上手就能脱穿山甲 基本功扎实

写得非常好 适合菜鸟学习

RVA 应该是 相对虚拟地址吧
henryouly 8 2005-8-3 11:07
14
0
谢谢寒江雪提醒,已经做了修改
昕雨轩 2005-8-3 20:37
15
0
精彩,,,,,,,
调频二台 2005-8-3 21:04
16
0
真得很好。。。
tcllct 2005-8-3 21:16
17
0
想看看实效,我不给个程序,你试试?如何?
liyangsj 25 2005-8-4 10:31
18
0
顶一个!!!
fly 85 2005-8-4 10:59
19
0
之所以加此篇为精华
鼓励新人的成分居多

避开输入表加密的地方不只一处,另外,很早也就提出在那个地方修改后要还原代码
用ImportRec修复输入表一般要“Add New Section”,稳定些
完美脱壳谈何容易?不是优化一下大小就“完美”了

多努力
prince 16 2005-8-4 12:43
20
0
支持支持~
林海雪原 6 2005-8-8 14:40
21
0
支持.............
双色重阳 2005-8-9 17:07
22
0
怎么脱Armadillo 高版本(3.00a - 3.61)的壳?似乎没什么办法啊!!!
tom88 2005-8-10 00:17
23
0
正本清源,我就是跳不过此类壳壳的关,看了楼主的再试试看看!!!谢谢.
yunfeng 1 2005-8-10 10:49
24
0
我正在收集这方面的资料,我也试一试脱这个软件加的壳.
ljy3282393 1 2005-9-14 14:41
25
0
然后分别在第一个项目和最后一个项目下硬件写入断点
........

楼主:这里有点看得不明白!第一个项目和最后一个项目是指哪里?能否抓个图来看清楚一点?谢谢!
yinfuxiang 2005-9-14 14:57
26
0
我是菜鸟,看的是一头雾水,不过我想一定用的到,先收藏!!
pendan2001 4 2005-9-14 23:26
27
0
GOOD!
lcsuper 2005-11-7 20:21
28
0
最初由 ljy3282393 发布

楼主:这里有点看得不明白!第一个项目和最后一个项目是指哪里?能否抓个图来看清楚一点?谢谢!

这一点我也不明白!我弄了半天也没有搞明白
杨长伟 2005-11-7 22:28
29
0
请问楼主:

 用你的方式也脱不了我的穿山甲,怪怪的:

第一步我下内存访问断点后,按f9程式就运行了???
arwin 2005-11-8 09:02
30
0
支持!我有个问题不是很明白,我近段也在学脱这个壳,但是脱了几个总有一个问题,就是脱完后运行程序退出时会有错误。
Lenus 3 2005-11-8 14:59
31
0
挑几个小毛病 (不要生气哦)

1.“实践是检验真理的唯一标准”不是马克思说的,是邓爷爷说的。
2.IAT是 import address table 没错。但是IAT不是输入表。输入表指向并改写IAT!

如有不对,请指正
ChinaSoft 2005-11-9 09:34
32
0
  ,多谢楼主!雪中送炭!
aiww 2005-11-9 21:21
33
0
按楼主的说的方法做了 使用importrec GetImport后有很多无效指针  Trace Level1后,还是有无效指针一共19个, Cut thunk 修复完后程序不能运行
反复调试过程中发现虽然修改了 magic jmp,但iat很多项还是指向壳的,而且importrec trace1很多修复的不正确
是不是还要手工修复呢 但是楼主并没有提出呢?
thrashkiller 2005-11-10 15:11
34
0
写得真得不错!支持一下~~
无奈无赖 2006-1-2 22:35
35
0
最初由 ljy3282393 发布

楼主:这里有点看得不明白!第一个项目和最后一个项目是指哪里?能否抓个图来看清楚一点?谢谢!


我也看不明白这里。楼主解答一下啊
kyc 19 2006-1-3 11:21
36
0
循序渐进的好教材,支持。
游客
登录 | 注册 方可回帖
返回