huzhao23 发表于 2009-12-11 19:10

SDProtector Profesional Edition v1.12 脱壳分析

【文章标题】: SDProtector Profesional Edition v1.12 脱壳分析
【文章作者】: huzhao23
【作者邮箱】: 304333002@QQ.COM
【作者主页】: hi.baidu.com/hacknight
【软件名称】: 黑洞2005企业版Build 20050328
【下载地址】: 自己搜索下载
【保护方式】: SDProtector Profesional Edition v1.12
【使用工具】: OD,LOADPE,IMPREC
【软件介绍】: 远程控制管理软件
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
一个朋友发给我这个软件,要我脱壳,发现是软件保护神的保护方式,老版本的壳,不过这个软件的ANTI 还是很有特点的。
记得有一篇国外的文章详细的分析了这个壳的反调试,大家可以去找找,1.16 版的脱壳方法大同小异。大家可以尝试着跟下。
好了,不多废话了,下面开始脱壳把

1. 设置好OD ,用hideolldbg 隐藏OD(记得每次调试都要隐藏) ,调试选项里忽略除INT3,单步,非法访问内存异常之外的异常,然后我们隐藏下OD
   SHIFT+F9 运行,大概运行11次程序就跑飞了,我们在最后一次异常的时候停下来
   
代码如下:
00C71EFA    64:8F00         pop   dword ptr fs:               ; 0012FFE0   // SEH异常中断在这里
00C71EFD    5B            pop   ebx
00C71EFE    E8 01000000   call    00C71F04
00C71F03    FF58 05         call    far fword ptr
00C71F06    6BFF FF         imul    edi, edi, -1

看堆栈,跳出这个异常
0012FF98   0012FFE0指向下一个 SEH 记录的指针
0012FF9C   00C71ED3SE处理程序                   // 这里是出口

来到出口处,代码如下:
00C71ED3    E8 01000000   call    00C71ED9      //   在这里下好断点之后,shift+F9运行到这里
00C71ED8    FF58 05         call    far fword ptr

之后就是单步F7 往下走

到这里

00C71ED9    58            pop   eax
00C71EDA    05 96FFFFFF   add   eax, -6A
00C71EDF    8038 E8         cmp   byte ptr , 0E8               // 0E8 是异常标记
00C71EE2^ 75 B2         jnz   short 00C71E96                      // 这里不能跳,否则就跑飞
00C71EE4    C600 E9         mov   byte ptr , 0E9               // 0E9 也是异常标记
00C71EE7    2BC0            sub   eax, eax
00C71EE9    C3            retn

继续单步F7走,来到这里
7C92E48A    0AC0            or      al, al
7C92E48C    74 0C         je      short 7C92E49A
7C92E48E    5B            pop   ebx
7C92E48F    59            pop   ecx
7C92E490    6A 00         push    0
7C92E492    51            push    ecx
7C92E493    E8 C6EBFFFF   call    ZwContinue   // 这里也是异常

出口在00C71EFA地址处,同样在这里下断点,shift+f9 运行到00C71EFA地址处,继续F7 ,来到这里

00C71F04    58            pop   eax
00C71F05    05 6BFFFFFF   add   eax, -95
00C71F0A    8038 E9         cmp   byte ptr , 0E9
00C71F0D^ 75 87         jnz   short 00C71E96                        // 这里也不能跳转,否则出错
00C71F0F    C600 E8         mov   byte ptr , 0E8
00C71F12    9D            popfd
00C71F13    61            popad


F7 ,来到这里
00C71F4A    58            pop   eax
00C71F4B    9D            popfd
00C71F4C    74 31         je      short 00C71F7F                   ; 这里必须跳,修改标志位
00C71F4E    74 03         je      short 00C71F53
00C71F50    75 01         jnz   short 00C71F53

继续F7 ,走到这里

00C760BC    58            pop   eax                              ; Client.00C760BB
00C760BD    05 45B0FFFF   add   eax, FFFFB045                  ; 这个应该是加密因子,
00C760C2    C3            retn


然后SHIFT+F9 ,中断在
00C7213D    64:8F00         pop   dword ptr fs:               ; 0012FFE0
00C72140    5B            pop   ebx
00C72141    E8 01000000   call    00C72147
00C72146    FF58 05         call    far fword ptr
00C72149    6BFF FF         imul    edi, edi, -1
00C7214C    FF80 38E97587   inc   dword ptr

同样是个SEH 异常,我们看堆栈,找到出口,然后shift+f9 运行到出口,接着又是一个context 结构体,走出来之后
继续F7 单步走 (要走很长一段时间)
来到这里

00C7213D    64:8F00         pop   dword ptr fs:               ; 到这里之后,堆栈里也显示一个SEH异常出口,但是我们不去那个出口,直接单步F8
00C72140    5B            pop   ebx
00C72141    E8 01000000   call    00C72147                         ; F7 进这个call
00C72146    FF58 05         call    far fword ptr

来到这里

00C72147    58            pop   eax
00C72148    05 6BFFFFFF   add   eax, -95
00C7214D    8038 E9         cmp   byte ptr , 0E9
00C72150^ 75 87         jnz   short 00C720D9                   ; 这里不能跳转,跳了就异常了,修改标志位不让它跳转
00C72152    C600 E8         mov   byte ptr , 0E8
00C72155    9D            popfd
00C72156    61            popad
然后继续F7 来到父子进程分离的地方

00C72194   /0F84 0E010000   je      00C722A8                         ; 这里就是关键父子进程分离的地方
00C7219A   |E8 01000000   call    00C721A0
00C7219F   |FF58 05         call    far fword ptr


00C72194   /0F84 0E010000   je      00C722A8 这里要修改标志位让跳转实现,否则程序将创建子进程运行,不利于我们脱壳

到这里关键的几个地方我们都找到了,下面用脚本实现以上修改,同时,到了这里之后还是会有反调试的机制存在,我们要在记录里看下还需要多少次
中断后就异常跑飞了,用脚本来实现
(借用了一个大牛的脚本修改了下),脚本如下

var SEH
var mess
//#log
eoe NighT1
eob NighT1
run
NighT1:
add SEH,1
log SEH
cmp SEH,a //第10次中断时跳转。
je stop1
esto


stop1:
coe
cob
mov SEH,0
bp 00C71F4C      // 这个地址是那个关键的JE
esto
bc eip
mov !zf,1
sti
run
bp 00C72194 //子进程与父进程分流处。
esto
bc eip
mov eip,00C722A8 //直接跳过创建子进程,强行让父进程以子进程运行。
eoe NighT2
eob NighT2
run

NighT2:
add SEH,1
log SEH
esto
ret

运行这个脚本之后,在记录里看见了一共SEH 了30 次就跑飞了,我们在30 处让程序中断下来 ,修改脚本实现

将NighT2 过程改成这样
NighT2:
add SEH,1
log SEH
cmp SEH,30
je stop2
esto

stop2:
coe
cob

ret

再次运行脚本,中断在这里
00C7607A    64:8F00         pop   dword ptr fs:               ; // 中断再这里
00C7607D    5B            pop   ebx
00C7607E    E8 01000000   call    00C76084                         ; F7
00C76083    FF58 05         call    far fword ptr


同样的方法走出着个异常
F7 进入这个CALL

00C76084    58            pop   eax
00C76085    05 6BFFFFFF   add   eax, -95
00C7608A    8038 E9         cmp   byte ptr , 0E9
00C7608D^ 75 87         jnz   short 00C76016                   // JNZ不能跳转,修改标志位不让它跳转
00C7608F    C600 E8         mov   byte ptr , 0E8
00C76092    9D            popfd
00C76093    61            popad
00C76094    C3            retn                                     ; 过了这个retn 就到了OEP


继续F7

来到OEP

005A9174    55            push    ebp                              ; OEP
005A9175    8BEC            mov   ebp, esp
005A9177    83C4 F0         add   esp, -10
005A917A    B8 4C8A5A00   mov   eax, 005A8A4C
005A917F    E8 F0D6E5FF   call    00406874
005A9184    A1 309B5E00   mov   eax, dword ptr
005A9189    8B00            mov   eax, dword ptr
005A918B    E8 D43FEEFF   call    0048D164
005A9190    8B0D 7C985E00   mov   ecx, dword ptr           ; Client.005EE228
005A9196    A1 309B5E00   mov   eax, dword ptr
005A919B    8B00            mov   eax, dword ptr
005A919D    8B15 442C5A00   mov   edx, dword ptr           ; Client.005A2C90
005A91A3    E8 D43FEEFF   call    0048D17C
005A91A8    A1 309B5E00   mov   eax, dword ptr
005A91AD    8B00            mov   eax, dword ptr
005A91AF    E8 4840EEFF   call    0048D1FC
005A91B4    E8 DBAFE5FF   call    00404194
005A91B9    8D40 00         lea   eax, dword ptr
005A91BC    0000            add   byte ptr , al

到这里DUMP

但是这个时候是DUMP 不了的,因为区段被修改了访问权限,修改权限为所有,然后就可以DUMP


2. IAT 的修复

SDPprotector 这个壳实在还原了IAT 之后,再来到OEP 的,所以,SEH<30 次的中断之后,对 IAT 进行处理的,我尝试了下 ,大概中断了12次就停在了壳对IAT
处理的地方。修改脚本
将NighT2 过程改成这样
NighT2:
add SEH,1
log SEH
cmp SEH,12
je stop2
esto

stop2:
coe
cob

ret

重载程序,重新运行脚本


00C764FB    90            nop                                    ; 中断在这里
00C764FC    3C 04         cmp   al, 4
00C764FE    74 32         je      short 00C76532
00C76500    74 03         je      short 00C76505
00C76502    75 01         jnz   short 00C76505
00C76504    E8 E8010000   call    00C766F1
00C76509    00FF            add   bh, bh
00C7650B    58            pop   eax

单步走

00C7653C    0F31            rdtsc                                    ; 反调试
00C7653E    8BC8            mov   ecx, eax
00C76540    8BDA            mov   ebx, edx
00C76542    7E 06         jle   short 00C7654A
00C76544    7F 04         jg      short 00C7654A
00C76546    0010            add   byte ptr , dl
00C76548    40            inc   eax

单步F7 走到这里
00C7656F    9D            popfd
00C76570    58            pop   eax
00C76571    0F31            rdtsc                                    ; 反调试
00C76573    2BC1            sub   eax, ecx
00C76575    1BD3            sbb   edx, ebx
00C76577    83FA 00         cmp   edx, 0                           ; 这里要把edx 置为0
00C7657A^ 75 84         jnz   short 00C76500
00C7657C    3D 00000060   cmp   eax, 60000000                  ; 这里把eax置为0
00C76581^ 0F87 79FFFFFF   ja      00C76500
00C76587    74 39         je      short 00C765C2                   ; JE和jnz 是jmp 的变形
00C76589    75 37         jnz   short 00C765C2

F7 到这里

00C7E182    8B8424 4C040000 mov   eax, dword ptr          ; 来到这里
00C7E189    33ED            xor   ebp, ebp                         ; 这里就是处理 IAT 的开始了
00C7E18B    85C0            test    eax, eax
00C7E18D    896C24 14       mov   dword ptr , ebp
00C7E191    75 6D         jnz   short 00C7E200
00C7E193    68 FDDE4000   push    0040DEFD
00C7E198    E8 007FFFFF   call    00C7609D
00C7E19D    50            push    eax
00C7E19E    68 C4AA4000   push    0040AAC4
00C7E1A3    E8 F57EFFFF   call    00C7609D

F8 到这里

00C7E31A    53            push    ebx
00C7E31B    895C24 54       mov   dword ptr , ebx
00C7E31F    E8 DCC4FFFF   call    00C7A800
00C7E324    E8 16C5FFFF   call    00C7A83F                         ; 这里有一个异常,F7 进去

进这个CALL
00C7A83F    83EC 68         sub   esp, 68                        ; F7 来到这里
00C7A842    53            push    ebx
00C7A843    56            push    esi
00C7A844    57            push    edi
00C7A845    E8 6CB8FFFF   call    00C760B6
00C7A84A    6A 00         push    0
00C7A84C    8BF8            mov   edi, eax
00C7A84E    E8 EC640000   call    00C80D3F
00C7A853    50            push    eax
00C7A854    E8 6CC6FFFF   call    00C76EC5
00C7A859    E8 58B8FFFF   call    00C760B6
00C7A85E    8BF0            mov   esi, eax
00C7A860    81EE 00010000   sub   esi, 100
00C7A866    E8 84C0FFFF   call    00C768EF
00C7A86B    8BD8            mov   ebx, eax
00C7A86D    8D4424 1C       lea   eax, dword ptr
00C7A871    50            push    eax
00C7A872    E8 85C7FFFF   call    00C76FFC
00C7A877    68 00010000   push    100
00C7A87C    8D4C24 24       lea   ecx, dword ptr
00C7A880    56            push    esi
00C7A881    51            push    ecx
00C7A882    E8 9DC7FFFF   call    00C77024
00C7A887    81C3 A8FBFFFF   add   ebx, -458
00C7A88D    81C6 58040000   add   esi, 458
00C7A893    53            push    ebx
00C7A894    8D5424 30       lea   edx, dword ptr
00C7A898    56            push    esi
00C7A899    52            push    edx
00C7A89A    E8 85C7FFFF   call    00C77024
00C7A89F    8D4424 38       lea   eax, dword ptr
00C7A8A3    8D4C24 28       lea   ecx, dword ptr
00C7A8A7    50            push    eax
00C7A8A8    51            push    ecx
00C7A8A9    E8 1AC8FFFF   call    00C770C8
00C7A8AE    83C4 24         add   esp, 24
00C7A8B1    83C7 60         add   edi, 60
00C7A8B4    8D5424 0C       lea   edx, dword ptr
00C7A8B8    6A 10         push    10
00C7A8BA    57            push    edi
00C7A8BB    52            push    edx
00C7A8BC    E8 31D0FFFF   call    00C778F2
00C7A8C1    5F            pop   edi
00C7A8C2    5E            pop   esi
00C7A8C3    85C0            test    eax, eax
00C7A8C5    5B            pop   ebx
00C7A8C6    EB 0A         jmp   short 00C7A8D2                   ; 这要修改成JMP 否则就会在下面的 调试中调用异常处理函数
00C7A8C8    E8 FAB7FFFF   call    00C760C7
00C7A8CD    E8 ADFBFFFF   call    00C7A47F
00C7A8D2    B8 01000000   mov   eax, 1
00C7A8D7    83C4 68         add   esp, 68
00C7A8DA    C3            retn

继续F8

00C7E329    8B7C24 38       mov   edi, dword ptr
00C7E32D    68 C4AA4000   push    0040AAC4
00C7E332    E8 667DFFFF   call    00C7609D
00C7E337    50            push    eax
00C7E338    53            push    ebx
00C7E339    E8 BB96FFFF   call    00C779F9
00C7E33E    85C0            test    eax, eax
00C7E340    74 5C         je      short 00C7E39E                   ; nop
00C7E342    68 23DF4000   push    0040DF23
00C7E347    E8 517DFFFF   call    00C7609D
00C7E34C    50            push    eax
00C7E34D    53            push    ebx
00C7E34E    E8 A696FFFF   call    00C779F9
00C7E353    85C0            test    eax, eax
00C7E355    74 47         je      short 00C7E39E                   ; nop
00C7E357    68 2EDF4000   push    0040DF2E
00C7E35C    E8 3C7DFFFF   call    00C7609D
00C7E361    50            push    eax
00C7E362    53            push    ebx
00C7E363    E8 9196FFFF   call    00C779F9
00C7E368    85C0            test    eax, eax
00C7E36A    74 32         je      short 00C7E39E                   ; nop
00C7E36C    68 38DF4000   push    0040DF38
00C7E371    E8 277DFFFF   call    00C7609D
00C7E376    50            push    eax
00C7E377    53            push    ebx
00C7E378    E8 7C96FFFF   call    00C779F9
00C7E37D    85C0            test    eax, eax
00C7E37F    74 1D         je      short 00C7E39E                   ; nop
00C7E381    68 45DF4000   push    0040DF45
00C7E386    E8 127DFFFF   call    00C7609D
00C7E38B    50            push    eax
00C7E38C    53            push    ebx
00C7E38D    E8 6796FFFF   call    00C779F9
00C7E392    85C0            test    eax, eax
00C7E394    C74424 24 00000>mov   dword ptr , 0            ; 0是IAT 不加密的标志
00C7E39C    75 08         jnz   short 00C7E3A6
00C7E39E    C74424 24 01000>mov   dword ptr , 1            ; 1是IAT 不加密的标志
00C7E3A6    68 51DF4000   push    0040DF51
00C7E3AB    E8 ED7CFFFF   call    00C7609D
00C7E3B0    50            push    eax
00C7E3B1    53            push    ebx
00C7E3B2    E8 4296FFFF   call    00C779F9
00C7E3B7    85C0            test    eax, eax
00C7E3B9    74 7F         je      short 00C7E43A                   ; nop
00C7E3BB    8B8424 4C040000 mov   eax, dword ptr

继续F8

00C7EA4D    68 6AE04000   push    0040E06A
00C7EA52    E8 4676FFFF   call    00C7609D
00C7EA57    50            push    eax                              ; 对"MessageBoxA"特殊处理
00C7EA58    57            push    edi
00C7EA59    E8 1480FFFF   call    00C76A72
00C7EA5E    85C0            test    eax, eax
00C7EA60    75 0E         jnz   short 00C7EA70                   ; 这里改成jmp
00C7EA62    68 B1CE4000   push    0040CEB1
00C7EA67    E8 3176FFFF   call    00C7609D
00C7EA6C    8906            mov   dword ptr , eax
00C7EA6E    EB 50         jmp   short 00C7EAC0
00C7EA70    68 10CF4000   push    0040CF10
00C7EA75    E8 2376FFFF   call    00C7609D
00C7EA7A    50            push    eax                              ; 对 "MessageBoxW"特殊处理
00C7EA7B    57            push    edi
00C7EA7C    E8 F17FFFFF   call    00C76A72
00C7EA81    85C0            test    eax, eax
00C7EA83    75 0E         jnz   short 00C7EA93                   ; 这里改成JMP
00C7EA85    68 27CF4000   push    0040CF27
00C7EA8A    E8 0E76FFFF   call    00C7609D
00C7EA8F    8906            mov   dword ptr , eax
00C7EA91    EB 2D         jmp   short 00C7EAC0
00C7EA93    8B4C24 10       mov   ecx, dword ptr
00C7EA97    57            push    edi
00C7EA98    51            push    ecx
00C7EA99    E8 FAB9FFFF   call    00C7A498
00C7EA9E    8906            mov   dword ptr , eax             ; 这里就是获取了API 函数的真实地址给ESI内存
00C7EAA0    EB 1E         jmp   short 00C7EAC0
00C7EAA2    8B5424 10       mov   edx, dword ptr
00C7EAA6    57            push    edi
00C7EAA7    52            push    edx
00C7EAA8    E8 EBB9FFFF   call    00C7A498
00C7EAAD    8906            mov   dword ptr , eax
00C7EAAF    8B4C24 14       mov   ecx, dword ptr
00C7EAB3    85C9            test    ecx, ecx
00C7EAB5    74 09         je      short 00C7EAC0
00C7EAB7    8901            mov   dword ptr , eax
00C7EAB9    83C1 04         add   ecx, 4
00C7EABC    894C24 14       mov   dword ptr , ecx
00C7EAC0    33C0            xor   eax, eax
00C7EAC2    66:8B03         mov   ax, word ptr
00C7EAC5    50            push    eax
00C7EAC6    68 FF000000   push    0FF
00C7EACB    57            push    edi
00C7EACC    E8 5D8DFFFF   call    00C7782E
00C7EAD1    66:C703 0000    mov   word ptr , 0
00C7EAD6    8B7C24 10       mov   edi, dword ptr
00C7EADA    3BEE            cmp   ebp, esi
00C7EADC    74 08         je      short 00C7EAE6
00C7EADE    6A 04         push    4
00C7EAE0    55            push    ebp
00C7EAE1    E8 B27FFFFF   call    00C76A98
00C7EAE6    8B5C24 18       mov   ebx, dword ptr
00C7EAEA    83C5 04         add   ebp, 4
00C7EAED    83C6 04         add   esi, 4
00C7EAF0^ E9 98F9FFFF   jmp   00C7E48D                         ; 这里是DLL 里的各个函数循环
00C7EAF5    E8 8E7DFFFF   call    00C76888
00C7EAFA    8B7424 20       mov   esi, dword ptr
00C7EAFE    8B5424 3C       mov   edx, dword ptr
00C7EB02    8B4E 04         mov   ecx, dword ptr
00C7EB05    51            push    ecx
00C7EB06    68 FF000000   push    0FF
00C7EB0B    52            push    edx
00C7EB0C    E8 1D8DFFFF   call    00C7782E
00C7EB11    6A 14         push    14
00C7EB13    56            push    esi
00C7EB14    E8 7F7FFFFF   call    00C76A98
00C7EB19    83C6 14         add   esi, 14
00C7EB1C    8B5C24 14       mov   ebx, dword ptr
00C7EB20    8B6C24 34       mov   ebp, dword ptr
00C7EB24    897424 20       mov   dword ptr , esi
00C7EB28^ E9 92F7FFFF   jmp   00C7E2BF                         ; 这里是程序调用的各个DLL 循环
00C7EB2D    8B8424 4C040000 mov   eax, dword ptr          ; 走到这里就得到了一个完整的IAT了
00C7EB34    85C0            test    eax, eax


走到这里了,我们就可以修复IAT了

填上OEP ,自动查找IAT 就可以了,然后转存,保存文件。
运行,程序能正常跑起来。脱壳完毕

--------------------------------------------------------------------------------
【经验总结】
老壳还是有些值得分析的价值的,这个壳的反调试的方法在其他的壳里也存在,所以,脱壳,单步跟踪分析壳的原理才是脱
壳的王道。
小小脱文,没什么太多的技术含量,大牛们飞过哈。呵呵
--------------------------------------------------------------------------------
【版权声明】: 本文原创于http://www.52pojie.cn, 转载请注明作者并保持文章的完整, 谢谢!
                                                       2009年12月12日 19:02:18

kainlove 发表于 2009-12-11 19:17

膜拜大侠,完全看不懂~

2051314 发表于 2009-12-11 20:17

支持一个 学习下。

huzhao23 发表于 2009-12-11 20:22

不容易啊,呵呵,得到精华,自己庆祝下,来到LCG 有点时间了,没有啥贡献,对不住大家哈

wa126 发表于 2009-12-11 20:31

楼主写了这么牛的文章还如此谦虚,让我等膜拜。

西氏 发表于 2009-12-11 21:24

强悍的人。

热火朝天 发表于 2009-12-11 21:48

厉害啊,进来膜拜一下

有梦 发表于 2009-12-12 22:24

进来学习学习:loveliness:

zsl01 发表于 2010-6-28 08:22

强悍的人。

gxhappylife 发表于 2011-6-22 20:35

确定是你写的吗?我看着很眼熟 这个壳版本比较低但是特别不好的脱 我现在破的这个软件 就在这卡住了 一点头绪都没有
页: [1] 2
查看完整版本: SDProtector Profesional Edition v1.12 脱壳分析