softdenfender采用双进程来防脱壳,如ShineGood所言“父进程要做的事是建立临时文件,写入前面GetTickCount所得值的加密值,再 CreateProcessA建立子进程,随后自己
退出,”,因此我们可以参考peaceclub提供的方法强制转单进程:
附:代码:
00723D2E /75 07 jnz short 00723D37 ; Ns.00723D37
00723D30 |74 05 je short 00723D37 ; Ns.00723D37
00723D32 |0010 add byte ptr ds:[eax],dl
00723D34 |40 inc eax ; Ns.00723D1C
00723D35 |00E8 add al,ch
00723D37 \0F84 9A000000 je 00723DD7 ; 强行跳转
00723D3D E8 01000000 call 00723D43 ; Ns.00723D43
00723D42 FF58 05 call far fword ptr ds:[eax+5]
00723D45 1100 adc dword ptr ds:[eax],eax ; Ns.00723D1C
因为有断点检测,因此我们下硬件断点,当然也可以在函数开始五个字节以后下F2断点代码:0072C7FE 8B00 mov eax,dword ptr ds:[eax] //api出int3断点检测,共检测五个字节
0072C800 8038 CC cmp byte ptr ds:[eax],0CC
0072C803 74 22 je short 0072C827 ; Ns.0072C827
0072C805 8078 01 CC cmp byte ptr ds:[eax+1],0CC
0072C809 74 1C je short 0072C827 ; Ns.0072C827
0072C80B 8078 02 CC cmp byte ptr ds:[eax+2],0CC
0072C80F 74 16 je short 0072C827 ; Ns.0072C827
0072C811 8078 03 CC cmp byte ptr ds:[eax+3],0CC
0072C815 74 10 je short 0072C827 ; Ns.0072C827
0072C817 8078 04 CC cmp byte ptr ds:[eax+4],0CC
0072C81B 74 0A je short 0072C827 ; Ns.0072C827
0072C81D 50 push eax
0072C81E C3 retn
he GetModuleHandleA
ctrl+F9执行到返回:代码:00406F50 53 push ebx
00406F51 8BD8 mov ebx, eax
00406F53 33C0 xor eax, eax
00406F55 A3 C4805D00 mov dword ptr [5D80C4], eax
00406F5A 6A 00 push 0
00406F5C E8 2BFFFFFF call 00406E8C
00406F61 A3 68F65D00 mov dword ptr [5DF668], eax ;返回这里
00406F66 A1 68F65D00 mov eax, dword ptr [5DF668]
00406F6B A3 D0805D00 mov dword ptr [5D80D0], eax
可以看出:代码:005D733C 55 push ebp ; oep
005D733D 8BEC mov ebp, esp
005D733F 83C4 F0 add esp, -10
005D7342 53 push ebx
005D7343 B8 246B5D00 mov eax, 005D6B24
005D7348 E8 03FCE2FF call 00406F50
005D734D 8B1D 44E55D00 mov ebx, dword ptr [5DE544] ; 返回这里
005D7353 8B03 mov eax, dword ptr [ebx]
005D7355 E8 8E68EBFF call 0048DBE8
OEP:005D733C
IAT:005E51F4--005E5B7C SIZE:98C
可以dump了。
参考peaceclub的方法,我们可以写如下修复IAT的代码,当然你也可以用ImprREC的level2和level3或插件修复,不过我的机器由于装着kav,它会hook几个函数,导致ImprREC不能正常修复,所以我只能自己动手写代码修复了。
二进制:代码:005E9A7C 60 pushad
005E9A7D 9C pushfd
005E9A7E BF F4515E00 mov edi, 005E51F4
005E9A83 66:837F 02 14 cmp word ptr [edi+2], 14
005E9A88 75 22 jnz short 005E9AAC
005E9A8A 8B17 mov edx, dword ptr [edi]
005E9A8C 90 nop
005E9A8D 90 nop
005E9A8E 90 nop
005E9A8F 8B42 12 mov eax, dword ptr [edx+12]
005E9A92 8B18 mov ebx, dword ptr [eax]
005E9A94 891F mov dword ptr [edi], ebx
005E9A96 90 nop
005E9A97 EB 13 jmp short 005E9AAC
005E9A99 90 nop
005E9A9A 90 nop
005E9A9B 90 nop
005E9A9C 90 nop
005E9A9D 90 nop
005E9A9E 90 nop
005E9A9F 90 nop
005E9AA0 90 nop
005E9AA1 90 nop
005E9AA2 90 nop
005E9AA3 90 nop
005E9AA4 90 nop
005E9AA5 90 nop
005E9AA6 90 nop
005E9AA7 90 nop
005E9AA8 90 nop
005E9AA9 90 nop
005E9AAA 90 nop
005E9AAB 90 nop
005E9AAC 83C7 04 add edi, 4
005E9AAF 81FF 7C5B5E00 cmp edi, 005E5B80
005E9AB5 7D 02 jge short 005E9AB9
005E9AB7 ^ EB CA jmp short 005E9A83
005E9AB9 9D popfd
005E9ABA 61 popad
具体方法可参考peaceclub的文章。代码:60 9C BF F4 51 5E 00 66 83 7F 02 14 75 22 8B 17 90 90 90 8B 42 12 8B 18 89 1F 90 EB 13 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 83 C7 04 81 FF 80 5B 5E 00 7D 02 EB CA 9D 61
不过这样修复后还是有8个指针修复不了,peaceclub说“找个delphi的程序把iat表保存下来和它对照一下”,我甚为不解,iat表会一样吗?这样做肯定不行的。
我们在005E51F4下内存访问断点,几次中断后会来到:
大概有十一个这种判断,代码:0072ACE7 837D 00 00 cmp dword ptr [ebp], 0
0072ACEB 0F84 3C030000 je 0072B02D ;为0则开始下一个dll
0072ACF1 8B7C24 14 mov edi, dword ptr [esp+14]
0072ACF5 8D4C24 38 lea ecx, dword ptr [esp+38]
0072ACF9 8D9424 3C010000 lea edx, dword ptr [esp+13C]
...
...
0072AF26 68 E2894000 push 004089E2
0072AF2B E8 31D1FFFF call 00728061
0072AF30 50 push eax
0072AF31 57 push edi
0072AF32 E8 92E2FFFF call 007291C9
0072AF37 85C0 test eax, eax
0072AF39 75 11 jnz short 0072AF4C
0072AF3B 68 867C4000 push 00407C86
0072AF40 E8 1CD1FFFF call 00728061
0072AF45 8906 mov dword ptr [esi], eax
0072AF47 E9 AA000000 jmp 0072AFF6
0072AF4C 68 F3894000 push 004089F3
0072AF51 E8 0BD1FFFF call 00728061
0072AF56 50 push eax
0072AF57 57 push edi
0072AF58 E8 6CE2FFFF call 007291C9
0072AF5D 85C0 test eax, eax
0072AF5F 75 11 jnz short 0072AF72
...
0072AFBC 57 push edi
0072AFBD 52 push edx
0072AFBE E8 94E7FFFF call 00729757
0072AFC3 50 push eax
0072AFC4 E8 17F8FFFF call 0072A7E0
0072AFC9 8906 mov dword ptr [esi], eax
0072AFCB EB 29 jmp short 0072AFF6
0072AFCD 8B4424 10 mov eax, dword ptr [esp+10]
0072AFD1 57 push edi
0072AFD2 50 push eax
0072AFD3 E8 7FE7FFFF call 00729757
0072AFD8 8906 mov dword ptr [esi], eax
0072AFDA 8B8C24 44040000 mov ecx, dword ptr [esp+444]
0072AFE1 85C9 test ecx, ecx
0072AFE3 75 11 jnz short 0072AFF6
0072AFE5 8B4C24 1C mov ecx, dword ptr [esp+1C]
0072AFE9 85C9 test ecx, ecx
0072AFEB 74 09 je short 0072AFF6
0072AFED 8901 mov dword ptr [ecx], eax
0072AFEF 83C1 04 add ecx, 4
0072AFF2 894C24 1C mov dword ptr [esp+1C], ecx
0072AFF6 33C9 xor ecx, ecx
0072AFF8 66:8B0B mov cx, word ptr [ebx]
0072AFFB 51 push ecx
0072AFFC 68 FF000000 push 0FF
0072B001 57 push edi
0072B002 E8 48E1FFFF call 0072914F
0072B007 66:C703 0000 mov word ptr [ebx], 0
0072B00C 3BEE cmp ebp, esi
0072B00E 74 0A je short 0072B01A
0072B010 6A 04 push 4
0072B012 6A 00 push 0
0072B014 55 push ebp
0072B015 E8 35E1FFFF call 0072914F
0072B01A 8B5C24 34 mov ebx, dword ptr [esp+34]
0072B01E 8B7C24 20 mov edi, dword ptr [esp+20]
0072B022 83C5 04 add ebp, 4 ;下一个
0072B025 83C6 04 add esi, 4
0072B028 ^ E9 BAFCFFFF jmp 0072ACE7
代码:0072AE26 50 push eax
0072AE27 57 push edi
0072AE28 E8 9CE3FFFF call 007291C9 ;判断是否是几个特殊的函数
0072AE2D 85C0 test eax, eax
0072AE2F 75 11 jnz short 0072AE42 ;我们要强制它跳,才能躲过特殊的函数的处理
不过壳还有内存校验,每patch过一个dll文件,我们要恢复原来的代码,很是麻烦,当然你可以在这里下内存访问断点,看哪里是检验处,修改之。我嫌麻烦,既然我们只剩下8个指针了,也不多,分别跟踪一下也不是很麻烦,经过跟踪我们得到那8个被特殊照顾的函数:代码:0072AFBE E8 94E7FFFF call 00729757 ;此时eax里是我们要的函数真实地址
0072AFC3 50 push eax ;Nop掉,避开加密
0072AFC4 E8 17F8FFFF call 0072A7E0 ;Nop掉
0072AFC9 8906 mov dword ptr [esi], eax
0072AFCB EB 29 jmp short 0072AFF6
赶紧fix吧,可以收工了。代码:005E521C kernel32.GetVersion
005E5234 kernel32.SetCurrentDirectoryA
005E5250 kernel32.GetStartupInfoA
005E5268 kernel32.GetCurrentDirectoryA
005E526C kernel32.GetCommandLineA
005E53FC GetVersionExA
005E5400 GetVersion
005E546C GetCurrentProcessId