首页
社区
课程
招聘
[原创]对一个IAT加密壳的分析
发表于: 2009-7-7 22:24 24701

[原创]对一个IAT加密壳的分析

2009-7-7 22:24
24701

这几天研究脱壳,上论坛看到一老兄求助地址(http://bbs.pediy.com/showthread.php?t=92330),由于自己也是新手,所以下载下来研究半天也无进展,幸好得到看雪老大的帮助,让我柳暗花明又一村,呵呵,经过老大的详细指点,终于将这个壳去掉了,下面将我的心得写出来,也算是留个记号吧,好久没来看雪发文章了!

    OD载入后,不分析,如图,一开始就是一个异常安装,并故意产生一个向[00000000]写入的异常如图:
   

    SHIFT+F7进入异常处理,在ZWContinue前看堆栈中有一个地址是00401016,如图:

  

    到00401016处,是一个无条件跳转指令:

  

    那么我们就到00720FAF处直接下断,然后F9到此处,如图:

   

    取消此处的断点,然后继续向下跑,来到此处:

     

    此时,应该进入到此CALL内部,因为直接F8的话会产生不能继续的异常(进程终止),估计此CALL中有作怪的地方,F7进入:
  
   

   继续向下,来到这里,果然发现了捣乱的地方:

   

    此处的两个je任意一个让其实现即可避过壳的检测。如果用SoftICE,会有通过CreateFile检测调试器的代码,本文忽略。过了拦路虎,就能顺利通过此CALL了,如图:

    

    继续F8向下,发现一个大的跨段跳跃,通过它走向OEP处的(如图):

   

    F8来到了程序的OEP,此时DUMP,然后用ImportREC修复,发现有很多无效的的函数指针,如图:

   

    这时可以用它强行一个一个地对函数的IAT进行修复,但是数量十分大,上百个函数,得找到一个更明智的办法才行啊!为什么加壳的程序能正常运行,而我们脱出来的就不行了,还有这么多无效的指针?应该是壳对部分的IAT进行了加密处理,只要找到了加密部分,绕过去不就能正常脱壳了么?

    然后就来实现吧,CTRL+F2重新载入程序,找到IAT的起始地址 1D4090加上基址就是5D4090,CTRL+F2重新载入程序,d 5d4090, 在此处下硬件写入断点

   

    重复前面的一些步骤,F9几次以后来到这里,发现向IAT的首地址写入了数据:
 
   

    而后面是一个回跳,继续向IAT的后续地址写入函数指针,所以可以判断,这就是IAT的加密代码部分(这个壳加密的是kernel32.dll中的部分函数IAT):

003914A7    C783 CC1A0010 0>mov     dword ptr [ebx+10001ACC], 0
003914B1    8B02            mov     eax, dword ptr [edx]
003914B3    85C0            test    eax, eax
003914B5    74 67           je      short 0039151E
003914B7    52              push    edx
003914B8    8983 CC1A0010   mov     dword ptr [ebx+10001ACC], eax
003914BE    A9 00000080     test    eax, 80000000
003914C3    74 09           je      short 003914CE
003914C5    25 FFFFFF7F     and     eax, 7FFFFFFF
003914CA    6A 00           push    0
003914CC    EB 0E           jmp     short 003914DC
003914CE    8B4D 08         mov     ecx, dword ptr [ebp+8]
003914D1    0341 08         add     eax, dword ptr [ecx+8]
003914D4    33C9            xor     ecx, ecx
003914D6    66:8B08         mov     cx, word ptr [eax]
003914D9    51              push    ecx
003914DA    40              inc     eax
003914DB    40              inc     eax
003914DC    50              push    eax
003914DD    FF75 FC         push    dword ptr [ebp-4]
003914E0    FF93 0A210010   call    dword ptr [ebx+1000210A]
003914E6    5A              pop     edx
003914E7    50              push    eax
003914E8    8B02            mov     eax, dword ptr [edx]
003914EA    A9 00000080     test    eax, 80000000
003914EF    75 18           jnz     short 00391509
003914F1    8B4D 08         mov     ecx, dword ptr [ebp+8]
003914F4    0341 08         add     eax, dword ptr [ecx+8]
003914F7    C600 00         mov     byte ptr [eax], 0
003914FA    40              inc     eax
003914FB    C600 00         mov     byte ptr [eax], 0
003914FE    40              inc     eax
003914FF    8A08            mov     cl, byte ptr [eax]
00391501    C600 00         mov     byte ptr [eax], 0
00391504    40              inc     eax
00391505    84C9            test    cl, cl
00391507  ^ 75 F6           jnz     short 003914FF
00391509    58              pop     eax
0039150A    85C0            test    eax, eax
0039150C  ^ 0F84 3FFFFFFF   je      00391451
00391512    8906            mov     dword ptr [esi], eax
00391514    8902            mov     dword ptr [edx], eax
00391516    83C2 04         add     edx, 4
00391519    83C6 04         add     esi, 4
0039151C  ^ EB 89           jmp     short 003914A7
    
    我们要让IAT部分得到正确的地址,就必须让EAX的值是对应的函数地址值!由于我们到达加密IAT代码部分时IAT的首部已经被写入了加密的IAT值,也就是说加密函数至少已经运行了一次!所以此时必须CTRL+F2再次重新载入程序,来到加密代码首部,然后继续向下,修改代码如下,保持EDX的值是压栈时的值,得到正确的函数地址指针:

   

    这样,这个加密IAT的部分就相当于被我们绕过去了。直接F4到加密结束部分,发现IAT部分已经被写入了正确的函数地址信息:

   

    最后,再次将我们修改的部分还原,就可以直接到达原来的OEP处了!(CTRL+G,输入原来我们找到的OEP地址,F2下断,F9到达后dump即可!)再用ImportREC修复时,发现所有的IAT都有效了,如图:

   

    修复后程序能正常运行,PEID查壳,VC++编写:

   


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (52)
雪    币: 324
活跃值: (10)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
2
哇,沙发学习..
2009-7-8 02:46
0
雪    币: 290
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
这是一个很经典的思路
2009-7-8 09:25
0
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
想问下,关于‘此时必须CTRL+F2再次重新载入程序,来到加密代码首部’, 重新载入程序,加密代码首部还没有出现, ctrl+G找不到003914A7。是否可以解释一下。谢谢
2009-7-8 15:11
0
雪    币: 1074
活跃值: (160)
能力值: ( LV13,RANK:760 )
在线值:
发帖
回帖
粉丝
5
在最后一次IAT内存写入的硬件断点之前,就行了,如果再往前有可能还没有进行解码呢
2009-7-8 17:30
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
经典,值得学习学习
2009-7-8 21:41
0
雪    币: 276
活跃值: (34)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
我是参照原贴9楼,跟进“003914E0    FF93 0A210010   call    dword ptr [ebx+1000210A]”这个CALL,修改跳转,跳过加密。
2009-7-8 22:58
0
雪    币: 224
活跃值: (147)
能力值: ( LV9,RANK:970 )
在线值:
发帖
回帖
粉丝
8
第2,3张图的原理呢
2009-7-9 13:31
0
雪    币: 1074
活跃值: (160)
能力值: ( LV13,RANK:760 )
在线值:
发帖
回帖
粉丝
9
SEH恢复,但我是直觉这么做的,呵呵。
2009-7-10 08:13
0
雪    币: 2067
活跃值: (82)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
10
大牛问你第2'3图的原理
我顺便学习一下.
2009-7-10 09:03
0
雪    币: 1074
活跃值: (160)
能力值: ( LV13,RANK:760 )
在线值:
发帖
回帖
粉丝
11
sessiondiy大侠能讲第二三图的原理么? 直接跟进系统领空也应该能看到返回点,只不过麻烦点吧!
2009-7-10 10:10
0
雪    币: 2067
活跃值: (82)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
12
我都看 Context结构

你可否说明一下你直接看Stack的原理.
2009-7-10 10:27
0
雪    币: 8209
活跃值: (4513)
能力值: ( LV15,RANK:2473 )
在线值:
发帖
回帖
粉丝
13
彪悍的直觉不需要原理
2009-7-10 11:24
0
雪    币: 2067
活跃值: (82)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
14
那只好只能膜拜无法学习了
2009-7-10 12:17
0
雪    币: 1074
活跃值: (160)
能力值: ( LV13,RANK:760 )
在线值:
发帖
回帖
粉丝
15
    呵呵,我也说不出原理,但是事实证明这样是能走出某些SEH的,如本文中的实例就能说明这一点!
2009-7-10 14:58
0
雪    币: 2242
活跃值: (488)
能力值: ( LV9,RANK:200 )
在线值:
发帖
回帖
粉丝
16
以前也跟跟过这个壳
那我就帮楼主补充两点
正处于学习中 所以有什么不对和不足的地方请指出

1.关于SEH
壳入口处故意造成 mov [0],0的内存访问异常
来到异常处理处
00720F9A    8B5424 04       MOV EDX,DWORD PTR SS:[ESP+4]   ;取EXCEPTION_RECORD
00720F9E    8B52 0C         MOV EDX,DWORD PTR DS:[EDX+C]   ;取ExceptionAddress
00720FA1    C602 E9         MOV BYTE PTR DS:[EDX],0E9  ;修改为jmp 跳到自己要去的地方
00720FA4    83C2 05         ADD EDX,5
00720FA7    2BCA            SUB ECX,EDX  ;算出到要去地方的偏移
00720FA9    894A FC         MOV DWORD PTR DS:[EDX-4],ECX

ret之后 就会回到CONTEXT结构里的eip处继续执行
该异常处理并没有修改eip的值 所以会跳到00401016继续执行

2.关于IAT加密
觉得这个才是重点吧 虽然说只是简单的加密下

来到处理IAT的地方
000314D9    51              PUSH ECX    ;Hint
000314DA    40              INC EAX
000314DB    40              INC EAX
000314DC    50              PUSH EAX    ;要处理的函数名地址
000314DD    FF75 FC         PUSH DWORD PTR SS:[EBP-4]   ;kernel32的ImageBase
000314E0    FF93 0A210010   CALL DWORD PTR DS:[EBX+1000210A]  ;我这里是call到000300DD

000300DD    55              PUSH EBP
000300DE    8BEC            MOV EBP,ESP
000300E0    83C4 FC         ADD ESP,-4
000300E3    53              PUSH EBX
000300E4    57              PUSH EDI
000300E5    56              PUSH ESI
000300E6    E8 00000000     CALL 000300EB
000300EB    5B              POP EBX
000300EC    81EB FE103E00   SUB EBX,3E10FE
000300F2    FF75 10         PUSH DWORD PTR SS:[EBP+10]
000300F5    FF75 0C         PUSH DWORD PTR SS:[EBP+C]
000300F8    FF75 08         PUSH DWORD PTR SS:[EBP+8]
000300FB    FF93 2F103E00   CALL DWORD PTR DS:[EBX+3E102F]             ;里面简单的封装了下GetProcAddress
00030101    8945 FC         MOV DWORD PTR SS:[EBP-4],EAX             ;保存下子刚取得的函数地址
00030104    8B8B 61103E00   MOV ECX,DWORD PTR DS:[EBX+3E1061]             ;获得当前所填IAT模块的ImageBase
0003010A    3B4D 08         CMP ECX,DWORD PTR SS:[EBP+8]             ;判断下是不是kernel32的ImageBase
0003010D    75 63           JNZ SHORT 00030172                       ;不是的话就跳走了 下面的代码就是加密了
0003010F    33C0            XOR EAX,EAX
00030111    0383 43103E00   ADD EAX,DWORD PTR DS:[EBX+3E1043]        ;判断下堆地址是否存在(变形IAT用),不存在的话就申请
00030117    74 0D           JE SHORT 00030126
00030119    05 07000000     ADD EAX,7
0003011E    3B83 47103E00   CMP EAX,DWORD PTR DS:[EBX+3E1047]             ;判断下空间是否够用,不够用也要申请
00030124    72 25           JB SHORT 0003014B
00030126    6A 40           PUSH 40
00030128    68 00100000     PUSH 1000
0003012D    68 00100000     PUSH 1000
00030132    6A 00           PUSH 0
00030134    FF93 3F103E00   CALL DWORD PTR DS:[EBX+3E103F]           ;VirtualAlloc
0003013A    8983 43103E00   MOV DWORD PTR DS:[EBX+3E1043],EAX
00030140    05 00100000     ADD EAX,1000
00030145    8983 47103E00   MOV DWORD PTR DS:[EBX+3E1047],EAX
0003014B    8DBB E9103E00   LEA EDI,DWORD PTR DS:[EBX+3E10E9]        ;临时构造变形的地址
                                                                     ;内容为一个模板
                                                                     mov eax,函数地址   5个字节大 B8+地址
                                                                     jmp eax            2个字节 FFE0
00030151    8BF7            MOV ESI,EDI                               
00030153    81C7 01000000   ADD EDI,1                                ;修改后面的立即数
00030159    8B45 FC         MOV EAX,DWORD PTR SS:[EBP-4]             ;取出函数地址
0003015C    AB              STOS DWORD PTR ES:[EDI]                  ;存放到EDI的地址里去
0003015D    8BBB 43103E00   MOV EDI,DWORD PTR DS:[EBX+3E1043]        ;这里才是真正存放变形过后的代码
00030163    8BC7            MOV EAX,EDI                                     ;这里就return这里的地址 让IAT填充这个地址
00030165    B9 07000000     MOV ECX,7                                     ; 5+2 = 7
0003016A    018B 43103E00   ADD DWORD PTR DS:[EBX+3E1043],ECX        ; 因为要连续存放 再把该地址add 7
00030170    F3:A4           REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>  ;把处理过模板的内容copy到使用的地方去
00030172    5E              POP ESI
00030173    5F              POP EDI
00030174    5B              POP EBX
00030175    C9              LEAVE
00030176    C2 0C00         RETN 0C
2009-7-10 17:03
0
雪    币: 319
活跃值: (49)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
17
强人。。。。。学习了。。。。。。。
2009-7-10 17:06
0
雪    币: 1074
活跃值: (160)
能力值: ( LV13,RANK:760 )
在线值:
发帖
回帖
粉丝
18
呵呵,“疯子”不错!
2009-7-10 17:19
0
雪    币: 1270
活跃值: (109)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
19
跟着年少兄学习。
2009-7-10 18:04
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
谢谢楼主了!!!
2009-7-10 18:11
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
太厉害了!佩服!!
2009-7-12 01:30
0
雪    币: 50
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
谢谢楼主学习了
2009-7-12 07:03
0
雪    币: 423
活跃值: (11)
能力值: ( LV9,RANK:230 )
在线值:
发帖
回帖
粉丝
23
关于那方面的艺术,本来想写一大篇较系统的文章给您。无奈俗务缠身,抽不出时间兑现我的
诺言。或者,你对于那方面的艺术,有什么需要问的,我看看抽时间回应,可好?

金融危机风雨欲来,下半年大战将至。七月份我还能抽出时间,以后估计没有心情了。

您看可好?
2009-7-12 23:31
0
雪    币: 2067
活跃值: (82)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
24
你是要讲 EXCEPTION_RECORD  吗?

想起来了....  你是要讲很黄很暴力的那个.
2009-7-13 02:35
0
雪    币: 264
活跃值: (11)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
25
彪悍的SEH只需要直觉..
2009-7-13 03:27
0
游客
登录 | 注册 方可回帖
返回
//