18

[原创]“九重妖塔”脱壳思路

lelfei 2017-11-13 14:32 1059
一、脱“壳”
程序有一段引导代码,功能只是IAT加密。OD载入后,停在004B84E0处,第一个CALL用于获取壳所需的API:
004B8A20    55              push ebp
004B8A21    8BEC            mov ebp,esp
004B8A23    51              push ecx
004B8A24    56              push esi
004B8A25    57              push edi
004B8A26    C745 FC 0000000>mov dword ptr ss:[ebp-0x4],0x0
004B8A2D    33C9            xor ecx,ecx
004B8A2F    64:A1 30000000  mov eax,dword ptr fs:[0x30]
004B8A35    8B40 0C         mov eax,dword ptr ds:[eax+0xC]
004B8A38    8B70 1C         mov esi,dword ptr ds:[eax+0x1C]
004B8A3B    8B46 08         mov eax,dword ptr ds:[esi+0x8]
004B8A3E    8B7E 20         mov edi,dword ptr ds:[esi+0x20]
004B8A41    8B36            mov esi,dword ptr ds:[esi]
004B8A43    66:394F 18      cmp word ptr ds:[edi+0x18],cx
004B8A47  ^ 75 F2           jnz short 九重妖塔.004B8A3B
004B8A49    8945 FC         mov dword ptr ss:[ebp-0x4],eax           ; 获取kernel32基址
004B8A4C    8B75 FC         mov esi,dword ptr ss:[ebp-0x4]
004B8A4F    E8 AC000000     call 九重妖塔.004B8B00                       ; 获取GetProcAddress地址
004B8A54    68 C8804B00     push 九重妖塔.004B80C8                       ; ASCII "LoadLibraryA"
004B8A59    56              push esi
004B8A5A    A3 E0384C00     mov dword ptr ds:[0x4C38E0],eax
004B8A5F    FFD0            call eax
004B8A61    68 D8804B00     push 九重妖塔.004B80D8                       ; ASCII "GetModuleHandleA"
004B8A66    56              push esi
004B8A67    A3 DC384C00     mov dword ptr ds:[0x4C38DC],eax
004B8A6C    FF15 E0384C00   call dword ptr ds:[0x4C38E0]
004B8A72    68 EC804B00     push 九重妖塔.004B80EC                       ; ASCII "VirtualProtect"
004B8A77    56              push esi
004B8A78    A3 D8384C00     mov dword ptr ds:[0x4C38D8],eax
004B8A7D    FF15 E0384C00   call dword ptr ds:[0x4C38E0]
004B8A83    68 FC804B00     push 九重妖塔.004B80FC                       ; ASCII "ExitProcess"
004B8A88    56              push esi
004B8A89    A3 D4384C00     mov dword ptr ds:[0x4C38D4],eax
004B8A8E    FF15 E0384C00   call dword ptr ds:[0x4C38E0]
004B8A94    68 08814B00     push 九重妖塔.004B8108                       ; ASCII "VirtualAlloc"
004B8A99    56              push esi
004B8A9A    A3 CC384C00     mov dword ptr ds:[0x4C38CC],eax
004B8A9F    FF15 E0384C00   call dword ptr ds:[0x4C38E0]
004B8AA5    6A 00           push 0x0
004B8AA7    A3 D0384C00     mov dword ptr ds:[0x4C38D0],eax
004B8AAC    FF15 D8384C00   call dword ptr ds:[0x4C38D8]
004B8AB2    A3 F4384C00     mov dword ptr ds:[0x4C38F4],eax
004B8AB7    A1 C8374B00     mov eax,dword ptr ds:[0x4B37C8]
004B8ABC    6A 40           push 0x40
004B8ABE    68 00300000     push 0x3000
004B8AC3    C1E0 02         shl eax,0x2
004B8AC6    50              push eax
004B8AC7    6A 00           push 0x0
004B8AC9    FF15 D0384C00   call dword ptr ds:[0x4C38D0]             ; kernel32.VirtualAlloc
004B8ACF    5F              pop edi                                  ; 申请空间
004B8AD0    A3 E4384C00     mov dword ptr ds:[0x4C38E4],eax
004B8AD5    C705 F0384C00 0>mov dword ptr ds:[0x4C38F0],0x7
004B8ADF    C705 EC384C00 0>mov dword ptr ds:[0x4C38EC],0x3
004B8AE9    C705 E8384C00 0>mov dword ptr ds:[0x4C38E8],0xD
004B8AF3    5E              pop esi
004B8AF4    8BE5            mov esp,ebp
004B8AF6    5D              pop ebp
004B8AF7    C3              retn

返回后,设置IAT段.idata属性为读写,并申请一个空间:
004B84F8    8D45 F8         lea eax,dword ptr ss:[ebp-0x8]
004B84FB    C745 F8 0000000>mov dword ptr ss:[ebp-0x8],0x0
004B8502    50              push eax
004B8503    A1 D8374B00     mov eax,dword ptr ds:[0x4B37D8]          ; 000AD000,.idata段偏移,IAT保存位置
004B8508    0305 F4384C00   add eax,dword ptr ds:[0x4C38F4]          ; 九重妖塔.00400000
004B850E    6A 04           push 0x4                                 ; 设置段为读写模式
004B8510    FF35 E0374B00   push dword ptr ds:[0x4B37E0]
004B8516    50              push eax
004B8517    FF15 D4384C00   call dword ptr ds:[0x4C38D4]             ; kernel32.VirtualProtect
004B851D    A1 C8374B00     mov eax,dword ptr ds:[0x4B37C8]
004B8522    6A 04           push 0x4
004B8524    68 00300000     push 0x3000
004B8529    C1E0 02         shl eax,0x2
004B852C    50              push eax
004B852D    6A 00           push 0x0
004B852F    FF15 D0384C00   call dword ptr ds:[0x4C38D0]             ; kernel32.VirtualAlloc
004B8535    8BD8            mov ebx,eax
004B8537    E8 54010000     call 九重妖塔.004B8690                   ; 获取IAT并加密

在004B8537处的CALL里进行IAT解码,跟入:
004B8690    53              push ebx
004B8691    8BDC            mov ebx,esp
004B8693    83EC 08         sub esp,0x8
004B8696    83E4 F0         and esp,-0x10
004B8699    83C4 04         add esp,0x4
004B869C    55              push ebp
004B869D    8B6B 04         mov ebp,dword ptr ds:[ebx+0x4]           ; 九重妖塔.004B853C
004B86A0    896C24 04       mov dword ptr ss:[esp+0x4],ebp
004B86A4    8BEC            mov ebp,esp
004B86A6    83EC 68         sub esp,0x68
004B86A9    A1 44304B00     mov eax,dword ptr ds:[0x4B3044]
004B86AE    33C5            xor eax,ebp
004B86B0    8945 FC         mov dword ptr ss:[ebp-0x4],eax
004B86B3    8B15 E4374B00   mov edx,dword ptr ds:[0x4B37E4]
004B86B9    0315 F4384C00   add edx,dword ptr ds:[0x4C38F4]          ; 九重妖塔.00400000
004B86BF    8BC2            mov eax,edx                              ; 九重妖塔.004B2AA5
004B86C1    8915 C0374B00   mov dword ptr ds:[0x4B37C0],edx          ; 九重妖塔.004B2AA5
004B86C7    2B05 D4374B00   sub eax,dword ptr ds:[0x4B37D4]
004B86CD    A3 CC374B00     mov dword ptr ds:[0x4B37CC],eax
004B86D2    A1 DC374B00     mov eax,dword ptr ds:[0x4B37DC]
004B86D7    0305 F4384C00   add eax,dword ptr ds:[0x4C38F4]          ; 九重妖塔.00400000
004B86DD    56              push esi
004B86DE    57              push edi
004B86DF    8B3D B4374B00   mov edi,dword ptr ds:[0x4B37B4]
004B86E5    33F6            xor esi,esi
004B86E7    A3 B8374B00     mov dword ptr ds:[0x4B37B8],eax
004B86EC    33C0            xor eax,eax
004B86EE    8945 AC         mov dword ptr ss:[ebp-0x54],eax
004B86F1    85FF            test edi,edi
004B86F3    74 40           je short 九重妖塔.004B8735
004B86F5    8D0C32          lea ecx,dword ptr ds:[edx+esi]
004B86F8    894D A8         mov dword ptr ss:[ebp-0x58],ecx
004B86FB    8A09            mov cl,byte ptr ds:[ecx]
004B86FD    84C9            test cl,cl
004B86FF    74 2A           je short 九重妖塔.004B872B
004B8701    83E0 03         and eax,0x3
004B8704    C0C9 02         ror cl,0x2
004B8707    3288 C4374B00   xor cl,byte ptr ds:[eax+0x4B37C4]
004B870D    8A45 AC         mov al,byte ptr ss:[ebp-0x54]
004B8710    FEC0            inc al
004B8712    32C8            xor cl,al
004B8714    8B45 A8         mov eax,dword ptr ss:[ebp-0x58]
004B8717    8808            mov byte ptr ds:[eax],cl                 ; DLL名称解码
004B8719    8B45 AC         mov eax,dword ptr ss:[ebp-0x54]
004B871C    8B15 C0374B00   mov edx,dword ptr ds:[0x4B37C0]          ; 九重妖塔.004B2AA5
004B8722    40              inc eax
004B8723    8B3D B4374B00   mov edi,dword ptr ds:[0x4B37B4]
004B8729    EB 02           jmp short 九重妖塔.004B872D
004B872B    33C0            xor eax,eax
004B872D    46              inc esi
004B872E    8945 AC         mov dword ptr ss:[ebp-0x54],eax
004B8731    3BF7            cmp esi,edi
004B8733  ^ 72 C0           jb short 九重妖塔.004B86F5
004B8735    833D C8374B00 0>cmp dword ptr ds:[0x4B37C8],0x0
004B873C    C745 AC 0000000>mov dword ptr ss:[ebp-0x54],0x0
004B8743    0F86 9B020000   jbe 九重妖塔.004B89E4
004B8749    33FF            xor edi,edi
004B874B    897D A8         mov dword ptr ss:[ebp-0x58],edi
004B874E    66:90           nop
004B8750    8B35 B8374B00   mov esi,dword ptr ds:[0x4B37B8]          ; 九重妖塔.004C6000
004B8756    F6043E 01       test byte ptr ds:[esi+edi],0x1           ; DLL分为2类,用2种不同的方式解码
004B875A    8B743E 04       mov esi,dword ptr ds:[esi+edi+0x4]
004B875E    0F84 02010000   je 九重妖塔.004B8866
004B8764    03F2            add esi,edx                              ; 九重妖塔.004B2AA5
004B8766    56              push esi                                 ; ----第1种解码方式----
004B8767    FF15 D8384C00   call dword ptr ds:[0x4C38D8]             ; kernel32.GetModuleHandleA
004B876D    8BC8            mov ecx,eax
004B876F    85C9            test ecx,ecx
004B8771    75 09           jnz short 九重妖塔.004B877C
004B8773    56              push esi
004B8774    FF15 DC384C00   call dword ptr ds:[0x4C38DC]             ; kernel32.LoadLibraryA
004B877A    8BC8            mov ecx,eax
004B877C    A1 B8374B00     mov eax,dword ptr ds:[0x4B37B8]
004B8781    8B0407          mov eax,dword ptr ds:[edi+eax]
004B8784    D1E8            shr eax,1
004B8786    50              push eax
004B8787    51              push ecx
004B8788    FF15 E0384C00   call dword ptr ds:[0x4C38E0]             ; kernel32.GetProcAddress
004B878E    6A 40           push 0x40                                ; 上面获取到真实API地址
004B8790    68 00300000     push 0x3000
004B8795    6A 20           push 0x20
004B8797    6A 00           push 0x0
004B8799    8BF8            mov edi,eax
004B879B    C745 D0 E801000>mov dword ptr ss:[ebp-0x30],0x1E8        ; 以下为第1段空间代码
004B87A2    C745 D4 00E958E>mov dword ptr ss:[ebp-0x2C],0xEB58E900
004B87A9    66:C745 D8 01E8 mov word ptr ss:[ebp-0x28],0xE801
004B87AF    C645 DA B8      mov byte ptr ss:[ebp-0x26],0xB8
004B87B3    C745 DF EB01153>mov dword ptr ss:[ebp-0x21],0x351501EB
004B87BA    C745 E3 1906172>mov dword ptr ss:[ebp-0x1D],0x20170619
004B87C1    C745 E7 EB01FF5>mov dword ptr ss:[ebp-0x19],0x50FF01EB
004B87C8    C745 EB EB02FF1>mov dword ptr ss:[ebp-0x15],0x15FF02EB
004B87CF    C645 EF C3      mov byte ptr ss:[ebp-0x11],0xC3
004B87D3    FF15 D0384C00   call dword ptr ds:[0x4C38D0]             ; kernel32.VirtualAlloc
004B87D9    6A 40           push 0x40                                ; 申请第1段空间
004B87DB    68 00300000     push 0x3000
004B87E0    6A 20           push 0x20
004B87E2    6A 00           push 0x0
004B87E4    8BF0            mov esi,eax
004B87E6    C745 B0 E801000>mov dword ptr ss:[ebp-0x50],0x1E8        ; 以下为第2段空间代码
004B87ED    C745 B4 00E958E>mov dword ptr ss:[ebp-0x4C],0xEB58E900
004B87F4    66:C745 B8 01E8 mov word ptr ss:[ebp-0x48],0xE801
004B87FA    C645 BA B8      mov byte ptr ss:[ebp-0x46],0xB8
004B87FE    C745 BF EB01153>mov dword ptr ss:[ebp-0x41],0x351501EB
004B8805    C745 C3 2605891>mov dword ptr ss:[ebp-0x3D],0x19890526
004B880C    C745 C7 EB01FF5>mov dword ptr ss:[ebp-0x39],0x50FF01EB
004B8813    C745 CB EB02FF1>mov dword ptr ss:[ebp-0x35],0x15FF02EB
004B881A    C645 CF C3      mov byte ptr ss:[ebp-0x31],0xC3
004B881E    FF15 D0384C00   call dword ptr ds:[0x4C38D0]             ; kernel32.VirtualAlloc
004B8824    8BC8            mov ecx,eax                              ; 申请第2段空间
004B8826    81F1 19061720   xor ecx,0x20170619                       ; 第2段地址入口加密
004B882C    81F7 26058919   xor edi,0x19890526                       ; API地址加密
004B8832    894D DB         mov dword ptr ss:[ebp-0x25],ecx          ; 写入加密后的第2段地址入口
004B8835    0F1045 D0       movups xmm0,dqword ptr ss:[ebp-0x30]
004B8839    8B4D AC         mov ecx,dword ptr ss:[ebp-0x54]
004B883C    897D BB         mov dword ptr ss:[ebp-0x45],edi          ; 写入加密后的API地址
004B883F    0F1106          movups dqword ptr ds:[esi],xmm0          ; 第1段空间代码写入
004B8842    0F1045 E0       movups xmm0,dqword ptr ss:[ebp-0x20]
004B8846    0F1146 10       movups dqword ptr ds:[esi+0x10],xmm0
004B884A    0F1045 B0       movups xmm0,dqword ptr ss:[ebp-0x50]
004B884E    0F1100          movups dqword ptr ds:[eax],xmm0          ; 第2段空间代码写入
004B8851    0F1045 C0       movups xmm0,dqword ptr ss:[ebp-0x40]
004B8855    0F1140 10       movups dqword ptr ds:[eax+0x10],xmm0
004B8859    A1 E4384C00     mov eax,dword ptr ds:[0x4C38E4]
004B885E    893488          mov dword ptr ds:[eax+ecx*4],esi         ; 第1段地址入口写入到临时IAT中
004B8861    E9 56010000     jmp 九重妖塔.004B89BC
004B8866    03F2            add esi,edx                              ; 九重妖塔.004B2AA5
004B8868    56              push esi                                 ; ----第2种解码方式----
004B8869    FF15 D8384C00   call dword ptr ds:[0x4C38D8]             ; kernel32.GetModuleHandleA
004B886F    8BC8            mov ecx,eax
004B8871    894D A4         mov dword ptr ss:[ebp-0x5C],ecx
004B8874    85C9            test ecx,ecx
004B8876    75 0A           jnz short 九重妖塔.004B8882
004B8878    56              push esi
004B8879    FF15 DC384C00   call dword ptr ds:[0x4C38DC]             ; kernel32.LoadLibraryA
004B887F    8945 A4         mov dword ptr ss:[ebp-0x5C],eax
004B8882    A1 B8374B00     mov eax,dword ptr ds:[0x4B37B8]
004B8887    8B7407 0C       mov esi,dword ptr ds:[edi+eax+0xC]
004B888B    33C0            xor eax,eax
004B888D    0335 CC374B00   add esi,dword ptr ds:[0x4B37CC]          ; 九重妖塔.004B2000
004B8893    8975 9C         mov dword ptr ss:[ebp-0x64],esi
004B8896    8945 A0         mov dword ptr ss:[ebp-0x60],eax
004B8899    3806            cmp byte ptr ds:[esi],al
004B889B    74 26           je short 九重妖塔.004B88C3
004B889D    0f1f00          nop dword ptr ds:[eax]
004B88A0    8A1430          mov dl,byte ptr ds:[eax+esi]
004B88A3    8BC8            mov ecx,eax
004B88A5    83E1 03         and ecx,0x3
004B88A8    C0CA 03         ror dl,0x3
004B88AB    3291 D0374B00   xor dl,byte ptr ds:[ecx+0x4B37D0]
004B88B1    8D48 01         lea ecx,dword ptr ds:[eax+0x1]
004B88B4    32D1            xor dl,cl
004B88B6    881430          mov byte ptr ds:[eax+esi],dl             ; API名称解密
004B88B9    40              inc eax
004B88BA    803C30 00       cmp byte ptr ds:[eax+esi],0x0
004B88BE  ^ 75 E0           jnz short 九重妖塔.004B88A0
004B88C0    8945 A0         mov dword ptr ss:[ebp-0x60],eax
004B88C3    56              push esi
004B88C4    FF75 A4         push dword ptr ss:[ebp-0x5C]             ; kernel32.76900000
004B88C7    FF15 E0384C00   call dword ptr ds:[0x4C38E0]             ; kernel32.GetProcAddress
004B88CD    6A 40           push 0x40                                ; 上面获取到真实API地址
004B88CF    68 00300000     push 0x3000
004B88D4    6A 20           push 0x20
004B88D6    6A 00           push 0x0
004B88D8    8BF8            mov edi,eax
004B88DA    C745 B0 E801000>mov dword ptr ss:[ebp-0x50],0x1E8        ; 以下为第1段空间代码
004B88E1    C745 B4 00E958E>mov dword ptr ss:[ebp-0x4C],0xEB58E900
004B88E8    66:C745 B8 01E8 mov word ptr ss:[ebp-0x48],0xE801
004B88EE    C645 BA B8      mov byte ptr ss:[ebp-0x46],0xB8
004B88F2    C745 BF EB01153>mov dword ptr ss:[ebp-0x41],0x351501EB
004B88F9    C745 C3 1906172>mov dword ptr ss:[ebp-0x3D],0x20170619
004B8900    C745 C7 EB01FF5>mov dword ptr ss:[ebp-0x39],0x50FF01EB
004B8907    C745 CB EB02FF1>mov dword ptr ss:[ebp-0x35],0x15FF02EB
004B890E    C645 CF C3      mov byte ptr ss:[ebp-0x31],0xC3
004B8912    FF15 D0384C00   call dword ptr ds:[0x4C38D0]             ; kernel32.VirtualAlloc
004B8918    6A 40           push 0x40                                ; 申请第1段空间
004B891A    68 00300000     push 0x3000
004B891F    6A 20           push 0x20
004B8921    6A 00           push 0x0
004B8923    8BF0            mov esi,eax
004B8925    C745 D0 E801000>mov dword ptr ss:[ebp-0x30],0x1E8        ; 以下为第2段空间代码
004B892C    C745 D4 00E958E>mov dword ptr ss:[ebp-0x2C],0xEB58E900
004B8933    66:C745 D8 01E8 mov word ptr ss:[ebp-0x28],0xE801
004B8939    C645 DA B8      mov byte ptr ss:[ebp-0x26],0xB8
004B893D    C745 DF EB01153>mov dword ptr ss:[ebp-0x21],0x351501EB
004B8944    C745 E3 2605891>mov dword ptr ss:[ebp-0x1D],0x19890526
004B894B    C745 E7 EB01FF5>mov dword ptr ss:[ebp-0x19],0x50FF01EB
004B8952    C745 EB EB02FF1>mov dword ptr ss:[ebp-0x15],0x15FF02EB
004B8959    C645 EF C3      mov byte ptr ss:[ebp-0x11],0xC3
004B895D    FF15 D0384C00   call dword ptr ds:[0x4C38D0]             ; kernel32.VirtualAlloc
004B8963    8BC8            mov ecx,eax                              ; 申请第2段空间
004B8965    81F7 26058919   xor edi,0x19890526                       ; API地址加密
004B896B    81F1 19061720   xor ecx,0x20170619                       ; 第2段地址入口加密
004B8971    897D DB         mov dword ptr ss:[ebp-0x25],edi          ; 写入加密后的API地址
004B8974    894D BB         mov dword ptr ss:[ebp-0x45],ecx          ; 写入加密后的第2段地址入口
004B8977    0F1045 B0       movups xmm0,dqword ptr ss:[ebp-0x50]
004B897B    8B4D AC         mov ecx,dword ptr ss:[ebp-0x54]
004B897E    0F1106          movups dqword ptr ds:[esi],xmm0          ; 第1段空间代码写入
004B8981    0F1045 C0       movups xmm0,dqword ptr ss:[ebp-0x40]
004B8985    0F1146 10       movups dqword ptr ds:[esi+0x10],xmm0
004B8989    0F1045 D0       movups xmm0,dqword ptr ss:[ebp-0x30]
004B898D    0F1100          movups dqword ptr ds:[eax],xmm0          ; 第2段空间代码写入
004B8990    0F1045 E0       movups xmm0,dqword ptr ss:[ebp-0x20]
004B8994    0F1140 10       movups dqword ptr ds:[eax+0x10],xmm0
004B8998    A1 E4384C00     mov eax,dword ptr ds:[0x4C38E4]
004B899D    893488          mov dword ptr ds:[eax+ecx*4],esi         ; 第1段地址入口写入到临时IAT中
004B89A0    8B45 A0         mov eax,dword ptr ss:[ebp-0x60]
004B89A3    48              dec eax
004B89A4    0345 9C         add eax,dword ptr ss:[ebp-0x64]          ; 九重妖塔.004B228D
004B89A7    8038 00         cmp byte ptr ds:[eax],0x0
004B89AA    74 10           je short 九重妖塔.004B89BC
004B89AC    0f1f40 00       nop dword ptr ds:[eax]
004B89B0    8D40 FF         lea eax,dword ptr ds:[eax-0x1]
004B89B3    C640 01 00      mov byte ptr ds:[eax+0x1],0x0            ; 把API名称清0
004B89B7    8038 00         cmp byte ptr ds:[eax],0x0
004B89BA  ^ 75 F4           jnz short 九重妖塔.004B89B0
004B89BC    8B45 AC         mov eax,dword ptr ss:[ebp-0x54]
004B89BF    8B7D A8         mov edi,dword ptr ss:[ebp-0x58]
004B89C2    40              inc eax
004B89C3    8B15 C0374B00   mov edx,dword ptr ds:[0x4B37C0]          ; 九重妖塔.004B2AA5
004B89C9    83C7 10         add edi,0x10
004B89CC    8945 AC         mov dword ptr ss:[ebp-0x54],eax
004B89CF    897D A8         mov dword ptr ss:[ebp-0x58],edi
004B89D2    3B05 C8374B00   cmp eax,dword ptr ds:[0x4B37C8]          ; DLL为的API解码完毕?
004B89D8  ^ 0F82 72FDFFFF   jb 九重妖塔.004B8750
004B89DE    8B3D B4374B00   mov edi,dword ptr ds:[0x4B37B4]
004B89E4    33C0            xor eax,eax
004B89E6    85FF            test edi,edi
004B89E8    74 1B           je short 九重妖塔.004B8A05
004B89EA    66:0f1f4400 00  nop word ptr ds:[eax+eax]
004B89F0    C60410 00       mov byte ptr ds:[eax+edx],0x0            ; DLL名称清0
004B89F4    40              inc eax
004B89F5    3B05 B4374B00   cmp eax,dword ptr ds:[0x4B37B4]
004B89FB    73 08           jnb short 九重妖塔.004B8A05
004B89FD    8B15 C0374B00   mov edx,dword ptr ds:[0x4B37C0]          ; 九重妖塔.004B2AA5
004B8A03  ^ EB EB           jmp short 九重妖塔.004B89F0
004B8A05    8B4D FC         mov ecx,dword ptr ss:[ebp-0x4]
004B8A08    5F              pop edi
004B8A09    33CD            xor ecx,ebp
004B8A0B    5E              pop esi
004B8A0C    E8 AF010000     call 九重妖塔.004B8BC0
004B8A11    8BE5            mov esp,ebp
004B8A13    5D              pop ebp
004B8A14    8BE3            mov esp,ebx
004B8A16    5B              pop ebx
004B8A17    C3              retn

可见获取到真实API地址后,申请了2段内存空间,第2段内存空间入口加密后写到第1段的代码中,API地址加密后写到第2段的代码中。我们随便找一个API跟进去看看,去掉花指令后其实非常简单:
025D000A    B8 19064922     mov eax,0x22490619
025D0012    35 19061720     xor eax,0x20170619                       ; 第2段地址入口解码
025D001A    50              push eax
025D001F    C3              retn                                     ; 跳到第2段入口025E0000

025E000A    B8 2B430E6F     mov eax,0x6F0E432B
025E0012    35 26058919     xor eax,0x19890526                       ; API地址解码
025E001A    50              push eax
025E001F    C3              retn                                     ; 跳到API执行

仅仅是经过2段跳后直接去执行API了。
返回后的工作很简单,把临时IAT地址复制到真实IAT中,跳到OEP:
004B853C    8B0D C8374B00   mov ecx,dword ptr ds:[0x4B37C8]
004B8542    33F6            xor esi,esi
004B8544    85C9            test ecx,ecx
004B8546    74 43           je short 九重妖塔.004B858B
004B8548    0f1f8400 000000>nop dword ptr ds:[eax+eax]
004B8550    A1 D4374B00     mov eax,dword ptr ds:[0x4B37D4]
004B8555    8BCE            mov ecx,esi
004B8557    3305 B4374B00   xor eax,dword ptr ds:[0x4B37B4]
004B855D    03C9            add ecx,ecx
004B855F    8904B3          mov dword ptr ds:[ebx+esi*4],eax
004B8562    A1 B8374B00     mov eax,dword ptr ds:[0x4B37B8]
004B8567    8B54C8 08       mov edx,dword ptr ds:[eax+ecx*8+0x8]
004B856B    A1 E4384C00     mov eax,dword ptr ds:[0x4C38E4]
004B8570    8B0CB0          mov ecx,dword ptr ds:[eax+esi*4]
004B8573    A1 F4384C00     mov eax,dword ptr ds:[0x4C38F4]
004B8578    890C10          mov dword ptr ds:[eax+edx],ecx           ; 临时IAT复制到真实IAT中
004B857B    0335 F0384C00   add esi,dword ptr ds:[0x4C38F0]
004B8581    8B0D C8374B00   mov ecx,dword ptr ds:[0x4B37C8]
004B8587    3BF1            cmp esi,ecx
004B8589  ^ 72 C5           jb short 九重妖塔.004B8550
004B858B    33F6            xor esi,esi
004B858D    85C9            test ecx,ecx
004B858F    74 3B           je short 九重妖塔.004B85CC
004B8591    A1 B8374B00     mov eax,dword ptr ds:[0x4B37B8]
004B8596    8BCE            mov ecx,esi
004B8598    03C9            add ecx,ecx
004B859A    8B54C8 08       mov edx,dword ptr ds:[eax+ecx*8+0x8]
004B859E    A1 E4384C00     mov eax,dword ptr ds:[0x4C38E4]
004B85A3    8B0CB0          mov ecx,dword ptr ds:[eax+esi*4]
004B85A6    A1 F4384C00     mov eax,dword ptr ds:[0x4C38F4]
004B85AB    890C10          mov dword ptr ds:[eax+edx],ecx           ; 临时IAT复制到真实IAT中
004B85AE    A1 D4374B00     mov eax,dword ptr ds:[0x4B37D4]
004B85B3    3305 B4374B00   xor eax,dword ptr ds:[0x4B37B4]
004B85B9    8904B3          mov dword ptr ds:[ebx+esi*4],eax
004B85BC    0335 EC384C00   add esi,dword ptr ds:[0x4C38EC]
004B85C2    8B0D C8374B00   mov ecx,dword ptr ds:[0x4B37C8]
004B85C8    3BF1            cmp esi,ecx
004B85CA  ^ 72 C5           jb short 九重妖塔.004B8591
004B85CC    33F6            xor esi,esi
004B85CE    85C9            test ecx,ecx
004B85D0    74 3B           je short 九重妖塔.004B860D
004B85D2    A1 B8374B00     mov eax,dword ptr ds:[0x4B37B8]
004B85D7    8BCE            mov ecx,esi
004B85D9    03C9            add ecx,ecx
004B85DB    8B54C8 08       mov edx,dword ptr ds:[eax+ecx*8+0x8]
004B85DF    A1 E4384C00     mov eax,dword ptr ds:[0x4C38E4]
004B85E4    8B0CB0          mov ecx,dword ptr ds:[eax+esi*4]
004B85E7    A1 F4384C00     mov eax,dword ptr ds:[0x4C38F4]
004B85EC    890C10          mov dword ptr ds:[eax+edx],ecx           ; 临时IAT复制到真实IAT中
004B85EF    A1 D4374B00     mov eax,dword ptr ds:[0x4B37D4]
004B85F4    3305 B4374B00   xor eax,dword ptr ds:[0x4B37B4]
004B85FA    8904B3          mov dword ptr ds:[ebx+esi*4],eax
004B85FD    0335 E8384C00   add esi,dword ptr ds:[0x4C38E8]
004B8603    8B0D C8374B00   mov ecx,dword ptr ds:[0x4B37C8]
004B8609    3BF1            cmp esi,ecx
004B860B  ^ 72 C5           jb short 九重妖塔.004B85D2
004B860D    33F6            xor esi,esi
004B860F    85C9            test ecx,ecx
004B8611    74 44           je short 九重妖塔.004B8657
004B8613    33FF            xor edi,edi
004B8615    66              datasize:
004B8616    66              datasize:
004B8617    66:0f1f8400 000>nop word ptr ds:[eax+eax]
004B8620    A1 D4374B00     mov eax,dword ptr ds:[0x4B37D4]
004B8625    3305 B4374B00   xor eax,dword ptr ds:[0x4B37B4]
004B862B    3904B3          cmp dword ptr ds:[ebx+esi*4],eax
004B862E    74 1F           je short 九重妖塔.004B864F
004B8630    A1 B8374B00     mov eax,dword ptr ds:[0x4B37B8]
004B8635    8B5407 08       mov edx,dword ptr ds:[edi+eax+0x8]
004B8639    A1 E4384C00     mov eax,dword ptr ds:[0x4C38E4]
004B863E    8B0CB0          mov ecx,dword ptr ds:[eax+esi*4]
004B8641    A1 F4384C00     mov eax,dword ptr ds:[0x4C38F4]
004B8646    890C10          mov dword ptr ds:[eax+edx],ecx           ; 临时IAT复制到真实IAT中
004B8649    8B0D C8374B00   mov ecx,dword ptr ds:[0x4B37C8]
004B864F    46              inc esi
004B8650    83C7 10         add edi,0x10
004B8653    3BF1            cmp esi,ecx
004B8655  ^ 72 C9           jb short 九重妖塔.004B8620
004B8657    A1 BC374B00     mov eax,dword ptr ds:[0x4B37BC]
004B865C    0305 F4384C00   add eax,dword ptr ds:[0x4C38F4]          ; 九重妖塔.00400000
004B8662    A3 F8384C00     mov dword ptr ds:[0x4C38F8],eax          ; 真实OEP
004B8667    5F              pop edi
004B8668    5E              pop esi
004B8669    5B              pop ebx
004B866A    FF35 F8384C00   push dword ptr ds:[0x4C38F8]
004B8670    C3              retn                                     ; 飞到OEP

由于壳并没有对API做什么干预,修复IAT的方法就很简单,只需要patch几个地方,用API地址替换掉二段跳地址的填充,就能还原完整的IAT了。需要patch以下4个地方:
004B8965    81F7 26058919   xor edi,0x19890526                       ; API地址加密
改为NOP,不对API地址加密
004B885E    893488          mov dword ptr ds:[eax+ecx*4],esi         ; 第1段地址入口写入到临时IAT中
改为mov dword ptr ds:[eax+ecx*4],edi,把API写入到临时IAT中
004B8965    81F7 26058919   xor edi,0x19890526                       ; API地址加密
改为NOP,不对API地址加密
004B899D    893488          mov dword ptr ds:[eax+ecx*4],esi         ; 第1段地址入口写入到临时IAT中
改为mov dword ptr ds:[eax+ecx*4],edi,把API写入到临时IAT中

执行到OEP后,用ImportREC修复一下,手动填入OEP为442A2,RVA为AD000,注意AD280处的ntdll.NtdllDefWindowProc_W需要改到user32.DefWindowProcW,最后一个无效函数直接删除就行了。

二、去“ANTI”
在OD中运行程序有一个比较奇怪的现象,直接F9程序运行的很好,但是切换到其他窗口再切换回程序居然就直接退出了,感觉像是HOOK了WindowProc处理过程,在窗口刷新时能检测到被调试了。在程序退出时查看堆栈(注意要用上面的脱壳版本):

0018FC00   76F6FD02  返回到 ntdll_12.76F6FD02
0018FC04   76FA9C4E  返回到 ntdll_12.76FA9C4E 来自 ntdll_12.ZwTerminateProcess
0018FC08   FFFFFFFF
0018FC0C   FFFFFFFF
0018FC10   0018FEC4
0018FC14   00000000
0018FC18   57C70000
0018FC1C  /0018FC30
0018FC20  |769179DD  返回到 kernel32.769179DD 来自 ntdll_12.RtlExitUserProcess
0018FC24  |00000000
0018FC28  |77E8F3B0
0018FC2C  |FFFFFFFF
0018FC30  ]0018FC7C
0018FC34  |0040FD22  返回到 九重妖塔.0040FD22 来自 kernel32.ExitProcess

是40FD22调用的ExitProcess,过去看看:
00410435  |.  6A 02         push 0x2
00410437  |.  6A 00         push 0x0
00410439  |.  6A 00         push 0x0
0041043B  |.  68 F0FC4000   push 九重妖塔.0040FCF0
00410440  |.  6A 00         push 0x0
00410442  |.  68 FFFFFF7F   push 0x7FFFFFFF
00410447  |.  6A 01         push 0x1
00410449  |.  FF15 7CD24A00 call dword ptr ds:[0x4AD27C]             ;  user32.SetWinEventHook
0041044F  |.  8B55 14       mov edx,[arg.4]
00410452  |.  E8 F9F9FFFF   call 九重妖塔.0040FE50                   ; 调用下面的函数

0040FEE3  |.  B8 F0FC4000   mov eax,九重妖塔.0040FCF0
0040FEE8  |.  C785 38FFFFFF>mov [local.50],0x5B4A2D0E
0040FEF2  |.  83C0 4A       add eax,0x4A
0040FEF5  |.  C785 3CFFFFFF>mov [local.49],0xECFBDB98
0040FEFF  |.  50            push eax
0040FF00  |.  68 F0FC4000   push 九重妖塔.0040FCF0
0040FF05  |.  8D8D 38FFFFFF lea ecx,[local.50]
0040FF0B  |.  C785 40FFFFFF>mov [local.48],0x98CBDEFC
0040FF15  |.  C785 44FFFFFF>mov [local.47],0x1A25B476
0040FF1F  |.  C785 48FFFFFF>mov [local.46],0xD4E3A5F7
0040FF29  |.  C745 8C 00000>mov [local.29],0x0
0040FF30  |.  C745 90 00000>mov [local.28],0x0
0040FF37  |.  C745 94 00000>mov [local.27],0x0
0040FF3E  |.  E8 7DF9FFFF   call 九重妖塔.0040F8C0                   ; SHA1计算


果然是窗口消息处理相关的API。再搜索一下0040FCF0引用参考,找到3个,但是都是来自同一个地方:
00410435  |.  6A 02         push 0x2
00410437  |.  6A 00         push 0x0
00410439  |.  6A 00         push 0x0
0041043B  |.  68 F0FC4000   push 九重妖塔.0040FCF0
00410440  |.  6A 00         push 0x0
00410442  |.  68 FFFFFF7F   push 0x7FFFFFFF
00410447  |.  6A 01         push 0x1
00410449  |.  FF15 7CD24A00 call dword ptr ds:[0x4AD27C]             ;  user32.SetWinEventHook
0041044F  |.  8B55 14       mov edx,[arg.4]
00410452  |.  E8 F9F9FFFF   call 九重妖塔.0040FE50                   ; 调用下面的函数

0040FEE3  |.  B8 F0FC4000   mov eax,九重妖塔.0040FCF0
0040FEE8  |.  C785 38FFFFFF>mov [local.50],0x5B4A2D0E
0040FEF2  |.  83C0 4A       add eax,0x4A
0040FEF5  |.  C785 3CFFFFFF>mov [local.49],0xECFBDB98
0040FEFF  |.  50            push eax
0040FF00  |.  68 F0FC4000   push 九重妖塔.0040FCF0
0040FF05  |.  8D8D 38FFFFFF lea ecx,[local.50]
0040FF0B  |.  C785 40FFFFFF>mov [local.48],0x98CBDEFC
0040FF15  |.  C785 44FFFFFF>mov [local.47],0x1A25B476
0040FF1F  |.  C785 48FFFFFF>mov [local.46],0xD4E3A5F7
0040FF29  |.  C745 8C 00000>mov [local.29],0x0
0040FF30  |.  C745 90 00000>mov [local.28],0x0
0040FF37  |.  C745 94 00000>mov [local.27],0x0
0040FF3E  |.  E8 7DF9FFFF   call 九重妖塔.0040F8C0                   ; SHA1计算

在0040FF3E处的CALL里,出现了"sha1 too many bytes"提示,再结合前后可以大致猜测出流程:设置窗口的SetWinEventHook为0040FCF0,并验证0040FCF0+4A的SHA1值,正确时才显示主窗口。
那么处理方法有2种:一是修改0040FCF0函数,强制跳过ExitProcess,同时也要修改后面的SHA1验证;二是直接处理掉SetWinEventHook,别HOOK到0040FCF0。我这里用的是第二种方法,直接修改00410435处的代码为JMP 0041044F,修改后程序完美运行。

三、还原加密代码

程序里0043EFF0有一个简单的虚拟机,还原虚拟机代码是很头疼的事,不过调试发现,虚拟机的作用是对指定的代码地址进行加解密,没有涉及到计算。因此完全可以忽略虚拟机,在虚拟机入口下断,观察调用时的参数设置,把虚拟机解密出的代码保存到EXE中。具体操作步骤为:
1.使用前面patch过的程序,执行到OEP。
2.在虚拟机入口0043EFF0下断,并对00401000代码段创建备份。
3.运行程序,当断在0043EFF0处时,查看返回地址处的代码,看之前有没有call 0043EE40,这个函数是专门用来设置虚拟机参数的,push的4个参数分别为:代码地址、代码长度、密钥、密钥长度,根据代码地址和长度把解密的数据保存到EXE原位置中。如果没有call 0043EE40,就有mov dword ptr ds:[0x48C0E9],0041AED0这一类的代码,这里的0041AED0就是解密代码入口地址,把解密后的数据复制到EXE原位置中。

四、待完成
以上是我一个晚上的分析,当天在单位值班,可以静下心来慢慢跟,第二天单位有事就没玩了,后面是需要耐心的活,我的耐心也耗的差不多了,留给有心人接着干吧。果不其然这一题满分通关,看了作者的设计说明,又简单看了一下后续调试,按我的思路应该是可以做出这一题的,但是这个CM比较闹心的是,验证的过程分了好多个部分,这一部分验证通过了才会解码下一步的代码,否则就不知道下一步的方向是否正确,这就要求分析出这一部分的功能才能进入下一步,对耐心是一个巨大的挑战。
我当时分析出了第一步是取注册码前一半,进行BASE64编码再BASE32编码再BASE16编码,验证最后字符串的长度的HASH值是否为0x511DD735,穷举完再逆推回去得到注册码长度为30位。
看到第二步是取BASE16编码的一部分,对-0x1989和0x2017进行加减运算,又是需要穷举,而且这才注册码前半截的一小部分验证,实在是没耐心跟下去了。
最后给愿意继续挑战的人几点意见吧:
1.看设计说明里提到了使用代码CRC作为解码KEY,我也看了一下,还是比较容易判断的,就是call 0043EE40设置参数时,看密钥是否是明码的,如果不是就要小心了。
2.程序建立了几个新线程,但是按我的修改方法没感觉什么地方影响到了,应该不是作者设计的。
3.我个人认为这一题最有意思的就是算法,比较绕,但是也能慢慢悟出来。如果能分析出所有算法,对个人的分析能力应该有很大提高。

最后,附上我已经PATCH一部分的EXE,本想把所有的PATCH都做完的,用CRC做KEY的方法太恶心人了,CRC结果并不是静态的,必须按流程走到那一步才能得到CRC结果,实在是没耐心搞了。
上传的附件:
最新回复 (3)
14
不问年少 6天前
2
很强大。必须顶。但是不能保存到文件,因为oninitialdialog中有文件代码段校验,并以hash值进行函数解码。
18
lelfei 6天前
3
不问年少 很强大。必须顶。但是不能保存到文件,因为oninitialdialog中有文件代码段校验,并以hash值进行函数解码。
解出的代码在什么时候用?如果是initdialog的时候用的,就已经跳过了,如果是后面验证时用的,那么目前还没遇到
14
不问年少 5天前
4
若保存到文件会导致连锁反应,oninitialdialog首当其冲会解码失败。后面会有以obinitialdialog的hash解码也会失败。结果就是直接崩溃。此cm设计的第一步就是反暴破。而且你直接修改此setwinevent的 sha值也会引起后面的解码失败,(点击按钮后)结果就是崩溃……你可以看看源码。
返回