聚星亭

吾笨笨且懒散兮 急须改之而奋进
posts - 74, comments - 166, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

在begin09论坛上nick放出了一个UnpackMe,我闲来无聊就捣鼓了下。感觉这个壳还可以啦。

花指令比较少。
IAT处理上,很像是PE-Armor。
需要修复TLS表。

下面是我分析的详细过程:

在00401000下内存写入断点:

003D025F    8B95 7D040000   mov    edx, dword ptr [ebp+0x47D]
003D0265    03D5            add    edx
, ebp
003D0267    8B3A            mov    edi
, dword ptr [edx]
003D0269    0BFF            or      edi
, edi
003D026B    
75 02           jnz    short 003D026F
003D026D    EB 
65           jmp    short 003D02D4
003D026F    03BD 
48040000   add    edi, dword ptr [ebp+0x448]
003D0275    83C2 
05         add    edx, 0x5
003D0278    8BF2            mov    esi
, edx
003D027A    
56              push    esi
003D027B    FF95 3C040000   call    dword ptr 
[ebp+0x43C]                        ; kernel32.GetModuleHandleA
003D0281    0BC0            or      eax, eax
003D0283    
75 07           jnz    short 003D028C
003D0285    
56              push    esi
003D0286    FF95 
40040000   call    dword ptr [ebp+0x440]
003D028C    0FB64E FF       movzx  ecx
, byte ptr [esi-0x1]
003D0290    03F1            add    esi
, ecx
003D0292    8BD6            mov    edx
, esi
003D0294    8BF0            mov    esi
, eax
003D0296    
42              inc    edx
003D0297    8B0A            mov    ecx
, dword ptr [edx]
003D0299    83C2 
04         add    edx, 0x4
003D029C    
51              push    ecx
003D029D    0FB602          movzx  eax
, byte ptr [edx]
003D02A0    0BC0            or      eax
, eax
003D02A2    
75 14           jnz    short 003D02B8
003D02A4    
42              inc    edx
003D02A5    
52              push    edx
003D02A6    8B02            mov    eax
, dword ptr [edx]
003D02A8    
50              push    eax
003D02A9    
56              push    esi
003D02AA    FF95 
38040000   call    dword ptr [ebp+0x438]
003D02B0    
8907            mov    dword ptr [edi], eax
003D02B2    5A              pop    edx
003D02B3    83C2 
04         add    edx, 0x4
003D02B6    EB 
13           jmp    short 003D02CB
003D02B8    
42              inc    edx
003D02B9    
52              push    edx
003D02BA    
52              push    edx
003D02BB    
56              push    esi
003D02BC    FF95 
38040000   call    dword ptr [ebp+0x438]                        ; kernel32.GetProcAddress
003D02C2    8907            mov    dword ptr [edi], eax                          ; 保存API地址
003D02C4    5A              pop    edx
003D02C5    0FB642 FF       movzx  eax
, byte ptr [edx-0x1]
003D02C9    03D0            add    edx
, eax
003D02CB    
42              inc    edx
003D02CC    83C7 
04         add    edi, 0x4
003D02CF    
59              pop    ecx
003D02D0  ^ E2 CA           loopd  short 003D029C
003D02D2  ^ EB 
93           jmp    short 003D0267

 

很明显,这些是解密IAT的。

        0045E6CC  770F4880  oleaut32.SysFreeString
        0045E6D0  770FA3EC  oleaut32.SysReAllocStringLen
        0045E6D4  770F4B39  oleaut32.SysAllocStringLen
        0045E6D8  
00000000
        0045E6DC  77DA7ABB  advapi32.RegQueryValueExA
        0045E6E0  77DA7852  advapi32.RegOpenKeyExA
        0045E6E4  77DA6C27  advapi32.RegCloseKey
        0045E6E8  
00000000
        0045E6EC  77D311DB  user32.GetKeyboardType
        0045E6F0  77D2B19C  user32.DestroyWindow
        0045E6F4  77D2C908  user32.LoadStringA
        0045E6F8  77D507EA  user32.MessageBoxA
        0045E6FC  77D2C8B0  user32.CharNextA
        
0045E700  00000000
        
0045E704  7C8099B5  kernel32.GetACP
        
0045E708  7C802446  kernel32.Sleep
        .

 

继续向下,发现一个anti dump的代码:

003D0381    64:FF35 3000000>push    dword ptr fs:[0x30]
003D0388    
58              pop     eax
003D0389    85C0            test    eax
, eax
003D038B    
78 0F           js      short 003D039C   ; 这里修改SF标志位,让它跳。
003D038D    8B40 0C         mov     eax, dword ptr [eax+0xC]
003D0390    8B40 0C         mov     eax
, dword ptr [eax+0xC]
003D0393    C740 
20 0010000>mov     dword ptr [eax+0x20], 0x1000
003D039A    EB 1C           jmp     short 003D03B8
003D039C    6A 
00           push    0x0
003D039E    FF95 3C040000   call    dword ptr 
[ebp+0x43C]
003D03A4    85D2            test    edx
, edx
003D03A6    
79 10           jns     short 003D03B8
003D03A8    837A 
08 FF      cmp     dword ptr [edx+0x8], -0x1
003D03AC    
75 0A           jnz     short 003D03B8
003D03AE    8B52 
04         mov     edx, dword ptr [edx+0x4]
003D03B1    C742 
50 0010000>mov     dword ptr [edx+0x50], 0x1000
003D03B8    89AD D3020000   mov     dword ptr 
[ebp+0x2D3], ebp
003D03BE    EB 
59           jmp     short 003D0419
003D03C0    
60              pushad

 

然后在内存映射视图,的代码段下内存访问断点,很容易,我们就来到了如下的地方:

003D049E    8DB5 14040000  lea    esi, dword ptr [ebp+0x414]                ; 得到原始程序代码在壳中的地址。
003D04A4    8BBD 0C040000  mov    edi, dword ptr [ebp+0x40C]                ; 得到要填充的地址(也就是我们OEP的地址)
003D04AA    8B8D 10040000  mov    ecx, dword ptr [ebp+0x410]                ; 取出大小
003D04B0    66:8B1E        mov    bx, word ptr [esi]
003D04B3    33D8           xor    ebx
, eax
003D04B5    
66:891F        mov    word ptr [edi], bx                        ; 停在这里了
003D04B8    83C7 02        add    edi, 0x2
003D04BB    83C6 
02        add    esi, 0x2
003D04BE  ^ E2 F0          loopd  short 003D04B0
003D04C0    8B85 0C040000  mov    eax
, dword ptr [ebp+0x40C]
003D04C6    
894424 FC      mov    dword ptr [esp-0x4], eax
003D04CA    
61             popad
003D04CB    FF6424 DC      jmp    dword ptr 
[esp-0x24]                      ; 跳转到OEP


这样就来到OEP了,如下,根据这个入口点我们可以知道,这是一个Delphi6.0到7.0的程序。

0045671C    55              push    ebp
0045671D    8BEC            mov    ebp
, esp
0045671F    83C4 F0         add    esp
, -0x10
00456722    B8 C4524500     mov    eax, 004552C4
00456727    E8 A0FEFAFF     call    004065CC
0045672C    A1 
88894500     mov    eax, dword ptr [0x458988]
00456731    8B00            mov    eax, dword ptr [eax]
00456733    E8 80CAFFFF     call    004531B8
00456738    A1 88894500     mov    eax, dword ptr [0x458988]
0045673D    8B00            mov    eax
, dword ptr [eax]
0045673F    B2 
01           mov    dl, 0x1
00456741    E8 5AE8FFFF     call    00454FA0
00456746    8B0D 748A4500   mov    ecx, dword ptr [0x458A74]        ; UpkMe.0045DCC8
0045674C    A1 88894500     mov    eax, dword ptr [0x458988]
00456751    8B00            mov    eax, dword ptr [eax]
00456753    8B15 24514500   mov    edx, dword ptr [0x455124]        ; UpkMe.00455170
00456759    E8 72CAFFFF     call    004531D0
0045675E    A1 
88894500     mov    eax, dword ptr [0x458988]
00456763    8B00            mov    eax, dword ptr [eax]
00456765    E8 9ECBFFFF     call    00453308
0045676A    E8 B1DFFAFF     call    
00404720


接下来我们修复IAT。
我们知道,Delphi程序,一般第一个函数的第一个API是GetModuleHandle。我们从这里入手,来看一下。

004065CC    53                       push    ebx
004065CD    8BD8                 mov    ebx
, eax
004065CF    33C0                   xor    eax
, eax
004065D1    A3 
88774500     mov    dword ptr [0x457788], eax
004065D6    6A 
00                 push    0x0
004065D8    E8 2BFFFFFF   call    
00406508  ; 这里应该是GetModuleHandleAPI的间接地址。进去应该是一个JMP跳,可是被修改成了自身的地址。
{
        
00406508    90                               nop
        
00406509    E8 B29EFCFF           call 003D03C0
        {
                003D03C0    
60              pushad
                003D03C1    
90              nop                                      ; 去掉花
                003D03C2    90              nop
                003D03C3    
90              nop
                003D03C4    
90              nop
                003D03C5    
90              nop
                003D03C6    
90              nop
                003D03C7    
90              nop
                003D03C8    
90              nop
                003D03C9    
90              nop
                003D03CA    5D              pop    ebp
                003D03CB    8B6D 
00         mov    ebp, dword ptr [ebp]            ; 003D00F3
                003D03CE    8B7C24 20       mov    edi, dword ptr [esp+0x20]        ; 取出CALL调用API的下面一行地址
                003D03D2    8BB5 81040000   mov    esi, dword ptr [ebp+0x481]      ; 1B09
                003D03D8    03F5            add    esi, ebp
                003D03DA    8B06            mov    eax
, dword ptr [esi]
                003D03DC    33D2            xor    edx
, edx
                003D03DE    B9 
02000000     mov    ecx, 0x2
                003D03E3    F7E1            mul    ecx
                003D03E5    D1E8            shr    eax
, 1
                003D03E7    3BF8            cmp    edi
, eax                        ; EDI中存放的是目标IAT,EAX不停的遍历
                003D03E9    75 0A           jnz    short 003D03F5
                003D03EB    0AD2            or      dl
, dl
                003D03ED    
75 04             jnz    short 003D03F3          ; CALL/ JMP的分流器。
                003D03EF    EB 09            jmp    short 003D03FA
                003D03F1    EB 
02             jmp    short 003D03F5
                003D03F3    EB 
13             jmp    short 003D0408
                003D03F5    83C6 
08          add    esi, 0x8
                003D03F8  ^ EB E0             jmp    short 003D03DA
                003D03FA    8B46 
04          mov    eax, dword ptr [esi+0x4]
                003D03FD    
3306                xor    eax, dword ptr [esi]
                003D03FF    
894424 FC       mov    dword ptr [esp-0x4], eax
                003D0403    
61                     popad
                003D0404    FF6424 DC       jmp    dword ptr 
[esp-0x24]
                003D0408    8B46 
04            mov    eax, dword ptr [esi+0x4]        ; 如果想定了,那就把[ESI+0x4]的内容跟[ESI]的内容异或,得到的就是正确的API地址了
                003D040B    3306                 xor    eax, dword ptr [esi]
                003D040D    
894424 FC       mov    dword ptr [esp-0x4], eax
                003D0411    
61                     popad
                003D0412    83C4 
04           add    esp, 0x4
                003D0415    FF6424 D8       jmp    dword ptr 
[esp-0x28]            ; JMP到正确的API地址中
        }
}


理论上讲,按照上面的分析,改写类似于如下的代码:

        00406508    90                               nop
        
00406509    E8 B29EFCFF           call 003D03C0


这样的代码,写个脚本修复所有的代码这个壳应该就算是脱OK了。
可是,情况却不是这样的,我们在运行到:

004065CC    53                       push    ebx
004065CD    8BD8                 mov    ebx
, eax
004065CF    33C0                   xor    eax
, eax
004065D1    A3 
88774500     mov    dword ptr [0x457788], eax
004065D6    6A 
00                 push    0x0
004065D8    E8 2BFFFFFF   call    
00406508


这里的代码的时候,程序莫名奇妙的异常了,查了一下异常信息是:0x80000004 (SINGLE STEP)异常。
具体原因,我水平有限,没有办法,我们就在到达OEP以前来修复这个IAT。

具体过程如下:

        00406508    90                               nop
        
00406509    E8 B29EFCFF           call 003D03C0

 

根据这个代码,我们重新加载程序,在地址00406508上下内存写入断点。运行程序,来到如下代码:

003D01B3    8BF8            mov    edi, eax
003D01B5    8BCA            mov    ecx
, edx
003D01B7    
56              push    esi
003D01B8    F3:A4           rep    movs byte ptr es:
[edi], byte ptr>; 在这里了
003D01BA    5E              pop    esi
003D01BB    
53              push    ebx
003D01BC    
68 00800000     push    0x8000
003D01C1    6A 
00           push    0x0
003D01C3    
56              push    esi
003D01C4    FF95 
69040000   call    dword ptr [ebp+0x469]
003D01CA    5B              pop    ebx
003D01CB    83C3 
04         add    ebx, 0x4
003D01CE  ^ EB A6           jmp    short 003D0176


这时我们去看一下我们要关注的地址已经被改成了什么样子:

00406508    90                       nop
00406509    E8 00000000      call    0040650E
0040650E    8BC0                  mov    eax
, eax


看到了吧,我们的00406508地址处的代码已经被改写了,只不过还没有完全写完。
我们继续看代码:

003D026F    03BD 48040000   add    edi, dword ptr [ebp+0x448]
003D0275    83C2 
05         add    edx, 0x5
003D0278    8BF2            mov    esi
, edx
003D027A    
56              push    esi
003D027B    FF95 3C040000   call    dword ptr 
[ebp+0x43C]                          ; kernel32.GetModuleHandleA
003D0281    0BC0            or      eax, eax
003D0283    
75 07           jnz    short 003D028C
003D0285    
56              push    esi
003D0286    FF95 
40040000   call    dword ptr [ebp+0x440]
003D028C    0FB64E FF       movzx  ecx
, byte ptr [esi-0x1]
003D0290    03F1            add    esi
, ecx

003D02B8    
42              inc    edx
003D02B9    
52              push    edx
003D02BA    
52              push    edx
003D02BB    
56              push    esi
003D02BC    FF95 
38040000   call    dword ptr [ebp+0x438]                          ; kernel32.GetProcAddress
003D02C2    8907            mov    dword ptr [edi], eax                          ; 保存API地址
003D02C4    5A              pop    edx
003D02C5    0FB642 FF       movzx  eax
, byte ptr [edx-0x1]
003D02C9    03D0            add    edx
, eax
003D02CB    
42              inc    edx
003D02CC    83C7 
04         add    edi, 0x4
003D02CF    
59              pop    ecx
003D02D0  ^ E2 CA           loopd  short 003D029C                                
; 循环获取所有用到的API地址
003D02D2  ^ EB 93           jmp    short 003D0267                                ; 继续其它DLL


我们可以猜测出来,接下来程序要做什么。
对的,它是要把所有API调用的地址代码从类似于:

00406508    90                      nop
00406509    E8 00000000     call    0040650E
0040650E    8BC0                 mov    eax
, eax


改写成:

00406508    90                            nop
00406509    E8 B29EFCFF        call 003D03C0


就是说,程序会自动定位所有要改写的地方,我们就可以借用这个时机,来修复我们的IAT调用。
好,我们继续。

003D02D4    8B85 79040000  mov    eax, dword ptr [ebp+0x479]
003D02DA    83F8 
01        cmp    eax, 0x1
003D02DD    0F85 
9E000000  jnz    003D0381
003D02E3    8BBD 
81040000  mov    edi, dword ptr [ebp+0x481]                    ; 1B90
003D02E9    03FD            add    edi, ebp
003D02EB    8DB5 CD020000  lea    esi
, dword ptr [ebp+0x2CD]
003D02F1    8B07            mov    eax
, dword ptr [edi]
003D02F3    0BC0            or      eax
, eax
003D02F5    
75 02          jnz    short 003D02F9
003D02F7    EB 1D          jmp    short 003D0316
003D02F9    
25 FFFFFF7F    and    eax, 0x7FFFFFFF                                ; 很关键的代码,用来计算填充位置的算法
003D02FE    8BDE            mov    ebx, esi


为了相信跟踪我们熟悉的API,以保证代码的准确性,我们可以在这里下条件断点: EAX == 0x0040650E,然后自己跟踪这个过程。
经过调试,我们知道,此时的[EDI]跟0x0x7FFFFFFF&运算以后,再减去4就是我们要填充的地址了。
而[EDI+4]中存放的就是我们需要的API地址。

当然,如果相信分析过我们逆向班15课的课后作业的话,我们很明白,这个壳加密的IAT不一定全是FF25类型的,还有FF15类型的。
详细分析003D03C0这个CALL的话,我们就可以明白,它有一个分流器来处理这些IAT加密。

003D0300    2BD8            sub    ebx, eax
003D0302    
8958 FC        mov    dword ptr [eax-0x4], ebx                      ; 改写代码了~~~~,也就是说,我们就在这里下手,嘿嘿
003D0305    83C7 04        add    edi, 0x4
003D0308    8B1F            mov    ebx
, dword ptr [edi]              ; 看到了吧,EDI+4中的内容就是API地址的指针。
003D030A    8B0B            mov    ecx, dword ptr [ebx]
003D030C    334F FC        xor    ecx
, dword ptr [edi-0x4]
003D030F    890F            mov    dword ptr 
[edi], ecx
003D0311    83C7 
04        add    edi, 0x4                                ; 继续下一个位置。
003D0314  ^ EB DB          jmp    short 003D02F1


好了,现在让我们整理一下我们现在所掌握的信息:

整理

1、003D0302    mov  dword ptr [eax-0x4], ebx  ; 这里的[EAX-4]CALL后面的地址。
        由此我们知道,[EAX-6]就是JMP的机器指令地址了,我们可以给这里赋值为FF25,也就是:mov    word ptr [eax-0x6], 0x25FF

2、我们已经知道了如何获取API地址,以及填写到哪个地址。


现在万事俱备,就差我们去修补它了,好我们开始动手修改这个壳的代码来修复IAT了。
先找一个足够大的空间,来写我们的代码,我找到下面的地址:

003D0593    90              nop
003D0594    
90              nop


好,我们先改个跳转,来转移到我们的这个地址上:

003D02F9    33D2            xor    edx, edx                        ; 很关键的代码,用来计算填充位置的算法
003D02FB    B9 02000000    mov    ecx, 0x2
003D0300    F7E1            mul    ecx
003D0302    D1E8            shr    eax
, 1                          ; 改写代码了~~~~,也就是说,我们就在这里下手,嘿嘿
003D0304    08D2            or      dl, dl
003D0306    0F85 
87020000  jnz    003D0593                        ; 这里是CALL/JMP的分流,跳了就是FF25类型的,按照FF25的方式休息,如果不跳,就是按照FF15的方式修复
003D030C    E9 9D020000    jmp    003D05AE                        ; 跳到FF15的修复代码中

33 D2 B9 02 00 00 00 F7 E1 D1 E8 08 D2 0F 85 87 02 00 00 E9 9D 02 00 00

到我们新找到空间将代码改写成如下样子:

003D0593    66:C740 FA FF25 mov    word ptr [eax-0x6], 0x25FF      ; FF25的修复代码。
003D0599    8B5F 04        mov    ebx, dword ptr [edi+0x4]
003D059C    
8958 FC        mov    dword ptr [eax-0x4], ebx
003D059F    8B0B            mov    ecx
, dword ptr [ebx]
003D05A1    334F FC        xor    ecx
, dword ptr [edi-0x4]
003D05A4    890F            mov    dword ptr 
[edi], ecx
003D05A6    83C7 
08        add    edi, 0x8
003D05A9  ^ E9 43FDFFFF    jmp    003D02F1
003D05AE    
66:C740 FA FF15 mov    word ptr [eax-0x6], 0x15FF      ; FF15的修复代码
003D05B4    8B5F 04        mov    ebx, dword ptr [edi+0x4]
003D05B7    
8958 FC        mov    dword ptr [eax-0x4], ebx
003D05BA    8B0B            mov    ecx
, dword ptr [ebx]
003D05BC    334F FC        xor    ecx
, dword ptr [edi-0x4]
003D05BF    890F            mov    dword ptr 
[edi], ecx
003D05C1    83C7 
08        add    edi, 0x8
003D05C4  ^ E9 28FDFFFF    jmp    003D02F1

66 C7 40 FA FF 25 8B 5F 04 89 58 FC 8B 0B 33 4F FC 89 0F 83 C7 08 E9 43 FD FF FF 66 C7 40 FA FF
15 8B 5F 04 89 58 FC 8B 0B 33 4F FC 89 0F 83 C7 08 E9 43 FD FF FF

 执行完这些代码,让我们看下API调用的代码,如下:

00406505    8D40 00        lea    eax, dword ptr [eax]
00406508  - FF25 8CE74500  jmp    dword ptr [0x45E78C]            ; kernel32.GetModuleHandleA
0040650E    8BC0            mov    eax, eax
00406510  - FF25 88E74500  jmp    dword ptr [0x45E788]            ; kernel32.LocalAlloc
00406516    8BC0            mov    eax, eax
00406518  - FF25 84E74500  jmp    dword ptr [0x45E784]            ; kernel32.TlsGetValue
0040651E    8BC0            mov    eax, eax
00406520  - FF25 80E74500  jmp    dword ptr [0x45E780]            ; kernel32.TlsSetValue
00406526    8BC0            mov    eax, eax
00406528    50              push    eax
00406529    6A 40          push    0x40
0040652B    E8 E0FFFFFF    call    
00406510                        ; jmp to kernel32.LocalAlloc


不过这个壳好像没有FF15类型的,好,到现在已经全部修复完成了。

接下来就是让代码修复OEP出的代码,然后我们跳到OEP处就可以了。
但是如果我们现在继续在00401000段下个断点程序会抛异常而不会像我们一开始那样,到OEP附近。
我们单步跟踪:

003D0429    8D85 D7020000   lea     eax, dword ptr [ebp+0x2D7]
003D042F    
8947 08         mov     dword ptr [edi+0x8], eax
003D0432    8B4F 0C         mov     ecx
, dword ptr [edi+0xC]
003D0435    03C1            add     eax
, ecx
003D0437    
8947 0C         mov     dword ptr [edi+0xC], eax
003D043A    8B95 E0030000   mov     edx
, dword ptr [ebp+0x3E0]
003D0440    8DB5 E4030000   lea     esi
, dword ptr [ebp+0x3E4]
003D0446    B8 FFFF0000     mov     eax
, 0xFFFF
003D044B    
3385 FC030000   xor     eax, dword ptr [ebp+0x3FC]
003D0451    
3385 00040000   xor     eax, dword ptr [ebp+0x400]
003D0457    
3385 04040000   xor     eax, dword ptr [ebp+0x404]
003D045D    8B3E            mov     edi
, dword ptr [esi]
003D045F    83C6 
04         add     esi, 0x4
003D0462    B9 
08000000     mov     ecx, 0x8
003D0467    8A1F            mov     bl
, byte ptr [edi]
003D0469    32C3            xor     al
, bl
003D046B    D1E8            shr     eax
, 1
003D046D    
73 05           jnb     short 003D0474
003D046F    
35 01A00000     xor     eax, 0xA001
003D0474  ^ E2 F5           loopd   short 003D046B
003D0476    
47              inc     edi
003D0477    3B3E            cmp     edi
, dword ptr [esi]
003D0479  ^ 
75 E7           jnz     short 003D0462
003D047B    83C6 
04         add     esi, 0x4
003D047E    83EA 
01         sub     edx, 0x1
003D0481    83FA 
00         cmp     edx, 0x0
003D0484  ^ 
75 D7           jnz     short 003D045D                   ; 循环修复并填充OEP处的代码
003D0486    8DBD 0C040000   lea     edi, dword ptr [ebp+0x40C]
003D048C    
66:8B1F         mov     bx, word ptr [edi]
003D048F    33D8            xor     ebx
, eax
003D0491    
66:891F         mov     word ptr [edi], bx
003D0494    
66:8B5F 02      mov     bx, word ptr [edi+0x2]
003D0498    33D8            xor     ebx
, eax
003D049A    
66:895F 02      mov     word ptr [edi+0x2], bx
003D049E    8DB5 
14040000   lea     esi, dword ptr [ebp+0x414]
003D04A4    8BBD 0C040000   mov     edi
, dword ptr [ebp+0x40C]
003D04AA    8B8D 
10040000   mov     ecx, dword ptr [ebp+0x410]
003D04B0    
66:8B1E         mov     bx, word ptr [esi]
003D04B3    33D8            xor     ebx
, eax
003D04B5    
66:891F         mov     word ptr [edi], bx               ; 如果上面单步跟踪执行的话,这里的EDI不是一个正常的地址,这里就会出异常。
003D04B8    83C7 02         add     edi, 0x2
003D04BB    83C6 
02         add     esi, 0x2
003D04BE  ^ E2 F0           loopd   short 003D04B0                   
; 接着修复OEP处的代码。
003D04C0    8B85 0C040000   mov     eax, dword ptr [ebp+0x40C]       ; 这里取出OEP
003D04C6    894424 FC       mov     dword ptr [esp-0x4], eax
003D04CA    
61              popad
003D04CB    FF6424 DC       jmp     dword ptr 
[esp-0x24]             ; 跳到OEP去。

当我们单步跟踪到003D04B5的时候,发现,EDI不是一个正常的地址,往这里写内容,程序会异常的。
通过我们刚才到OEP的调试,我们知道,edi本身应该是我们OEP的地址,这个代码就是填充OEP用的。我们先不管它。

在003D04C0这里,将EAX修改为我们的OEP,然后跳到OEP以后,手工改好了OEP的代码,dump出一个文件,修复了下转存文件。可是问题提示C0000005初始化错误,本来以为全盘皆输了,经Nick提示,说是要修复TLS表。
所以,我按照没脱壳的程序把TLS填好,重新计算了下索引变量的虚拟地址(就是TLS表的RVA+SIZE)。然后保存,运行,OK了

问题解决了,嘿嘿。

加壳的程序,脱壳后的程序,已经脱壳脚本还有分析笔记下载/Files/besterChen/Unpack/01/UpkMe.rar

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理