吾爱破解周年献礼----攻破ZProtect IAT保护最后的堡垒---Anti-Hook
目标程序是一个ZProtect 1.4 企业版加壳的程序。1.到OEP去
对于这个版本来说,单纯的是ESP定律不再适用,什么意思呢?如果仅仅下硬件断点是断不下来的,我们需要一种辅助断点方式、
先单步走,仍然是走到pushad 以后下hr esp。然后Ctrl+G 输入GetModuleHandleA
到这里来7C80B731 >8BFF mov edi,edi
7C80B733 55 push ebp
7C80B734 8BEC mov ebp,esp
7C80B736 837D 08 00 cmp dword ptr ss:,0
7C80B73A 74 18 je short kernel32.7C80B754<--- 在这里下F2断点.
7C80B73C FF75 08 push dword ptr ss:
7C80B73F E8 C0290000 call kernel32.7C80E104
7C80B744 85C0 test eax,eax
7C80B746 74 08 je short kernel32.7C80B750
7C80B748 FF70 04 push dword ptr ds:
7C80B74B E8 7D2D0000 call kernel32.GetModuleHandleW
7C80B750 5D pop ebp解释一下为什么要这么下.GetModuleHandleA这个函数在壳的运行中是至关重要的,调用的次数非常的频繁,而且即便是过了OEP以后,主程序初始化的时候也会调用这个函数,也就是说,我们即便不能到达OEP,也可能到达OEP附近。所以用这个断点来辅助我们找OEP。
断点下好以后,F9运行,注意看反汇编窗口EIP的位置。数次之后,就会断在下面的代码上:00A70447^\E9 5929FFFF jmp 00A62DA5这就是ESP定律应该执行到的位置。
然后取消GetModuleHandleA 里面的Int3断点。这点很重要!!!!!!!否则后面在Patch代码修复IAT的时候就会壳的多线程校验检测到。
再走两步就到了这里,这就是OEP,标准的Delphi入口00453D0C 55 push ebp
00453D0D 8BEC mov ebp,esp
00453D0F 83C4 F0 add esp,-10
00453D12 B8 2C3B4500 mov eax,zp_1_4.00453B2C
00453D17 E8 441FFBFF call zp_1_4.00405C60
00453D1C A1 58504500 mov eax,dword ptr ds:
00453D21 8B00 mov eax,dword ptr ds:
00453D23 E8 74E3FFFF call zp_1_4.0045209C
00453D28 8B0D 38514500 mov ecx,dword ptr ds: ; zp_1_4.00456BFC
00453D2E A1 58504500 mov eax,dword ptr ds:
00453D33 8B00 mov eax,dword ptr ds:
00453D35 8B15 3C364500 mov edx,dword ptr ds: ; zp_1_4.00453688
00453D3B E8 74E3FFFF call zp_1_4.004520B4
00453D40 A1 58504500 mov eax,dword ptr ds:
00453D45 8B00 mov eax,dword ptr ds:
00453D47 E8 E8E3FFFF call zp_1_4.00452134
00453D4C E8 0B00FBFF call zp_1_4.00403D5C上面是比较中规中矩的方法,下面介绍一种比较取巧的方法。
直接在OD中运行程序。然后到00401000去,分析一下代码。00401000 /04104000 dd zp_1_4.00401004
00401004 \03 db 03
00401005 .07 db 07
00401006 .42 6F 6F 6C 6>ascii "Boolean"
0040100D 01 db 01
0040100E 00 db 00
0040100F 00 db 00
00401010 00 db 00
00401011 00 db 00
00401012 01 db 01
00401013 00 db 00
00401014 00 db 00
00401015 00 db 00
00401016 00104000 dd zp_1_4.00401000
0040101A .05 db 05
0040101B .46 61 6C 73 6>ascii "False"
00401020 .04 db 04
00401021 .54 72 75 65 ascii "True"看到这些,凭经验很容易判断这是个Delphi的程序,一般来说,Delphi程序的入口点都在代码段的最下面。但是ZProtect合并了所有的数据段,所以找到的时候,我们可以找一串连续的,较长的00 00 就可以了,因为这是原来数据段的分割。这样也很容易就找到了OEP。
2,记录一些数据,方便修复。
OEP=00453d0c
查找E9 ?? ?? ?? ?? 90--这是ZProtect对IAT调用的修改方式。如果是这种形式表示以前的调用方式是FF 25型的
或者E8 ?? ?? ?? ?? 90---如果是这种方式,则代表原来的调用方式是FF 15型的。
确定被修改的IAT调用方式是FF 25
IAT调用的特征码是
E9 ?? ?? 09 00 90
E9 ?? ?? 07 00 90
E9 ?? ?? 08 00 90
便于后面修复IAT
查找一下FF 25---这是为了确定GetModuleHandleA这个函数的调用位置。因为ZProtect不会处理GetModuleHandleA的调用方式,而只会模拟这个函数。
确定有效的GetModuleHandleA调用有两处。00405B9C $- FF25 E4714500 jmp dword ptr ds: ds:=00A425D0
00401264 $- FF25 6C714500 jmp dword ptr ds: ds:=00A425D0可见两处调用是同一个伪IAT。
IAT调用开始位置:004011F4
IAT调用结束位置:004239A3
这样可以减少查找时间。
3,接下来找IAT的解密call
F7单步走,一直走,直到走进一处IAT调用的代码后,记录下面的代码。
根据我第一篇的分析,下面就是解密call了00A643E5 FF15 346FA500 call dword ptr ds: 这个就是解密call了~
00A6D63D 8B0D 8076A500 mov ecx,dword ptr ds:--这里装的是伪IAT的地址
00A64674 85C9 test ecx,ecx
00A59940 8BF0 mov esi,eax
00A5AF4D /0F84 55910000 je 00A640A8
00A5B842 A1 8476A500 mov eax,dword ptr ds:
00A673CA 2BC1 sub eax,ecx
00A6C6F8 C1F8 02 sar eax,2
00A5C550 3BF0 cmp esi,eax
00A63FFF^\0F82 5981FFFF jb 00A5C15E
00A5C15E 8B0CB1 mov ecx,dword ptr ds:--这里就是获得函数地址了
00A5C901 894C24 2C mov dword ptr ss:,ecx
00A68A0B 5E pop esi
00A58F96 C2 0400 retn 4
00A620FF 61 popad
00A653E4 C3 retn----------这里返回到API执行 但是代码被复制到内存,无法知道真正的内存地址了。
找到解密call了 我们就可以修复IAT调用了~ 到伪IAT一看 发现IAT被Hook了~
伪IAT的开始地址是00A85D48
结束地址是00A86314
这个地址 对于同一台机器和同一个OD,是不变的~
之前说过,ZP会把IAT(包括伪IAT)复制几份放在内存中,但只有
00A6D63D 8B0D 8076A500 mov ecx,dword ptr ds:
这里给出的IAT基地址才是真正完整的IAT地址。
4,修复Anti-Hook
下面就是伪IAT了(部分,全本见附件)00A85D4800BE9719
00A85D4C00BE8F1F
00A85D5000DBB1DE
00A85D5400BEB19C
00A85D5800EAFE01
00A85D5C00BE42ED
00A85D6000DBB5EA
00A85D6400AB2446
00A85D6800BF0277
00A85D6C00BE9ED9
00A85D7000BED226
00A85D7400AB9F81
00A85D7800AE60DB不过首先要先修复被Hook的API地址。
向上翻看下。发现这里有
这里有一连串的DLL基址
简单分析一下就会知道:
数据的结构是这样的:
Dword CopyMemorySize
Dword CopyDllBase
Dword CopyMemoryBase
需要说明的是,这里面的CopyMemorySize正好等于相应dll的镜像大小。
为什么会这样呢?继续看下就知道了~00A84CF00011E000
00A84CF47C800000kernel32.7C800000
00A84CF800AB0000
00A84CFC00090000
00A84D0077D10000user32.77D10000
00A84D0400BD0000
00A84D08000A9000
00A84D0C77DA0000advapi32.77DA0000
00A84D1000C60000
00A84D140008B000
00A84D18770F0000oleaut32.770F0000
00A84D1C00D10000
00A84D2000008000
00A84D2477BD0000version.77BD0000
00A84D2800DA0000
00A84D2C00049000
00A84D3077EF0000gdi32.77EF0000
00A84D3400DB0000
00A84D380009A000
00A84D3C5D170000comctl32.5D170000
00A84D4000E00000
00A84D4400093000
00A84D487C920000ntdll.7C920000
00A84D4C00EA0000
00A84D50007F4000
00A84D547D590000shell32.7D590000
00A84D5800F40000我们现在知道了00AB0000 这里内存里面放的是Kernel32.dll的函数。那么我们就进去看看代码
在这里找一段代码,二进制复制,然后在内存中查找这段二进制00AB24D6 68 C09A837C push 7C839AC0
00AB24DB 64:A1 00000000mov eax,dword ptr fs:
00AB24E1 50 push eax
00AB24E2 8B4424 10 mov eax,dword ptr ss:
00AB24E6 896C24 10 mov dword ptr ss:,ebp
00AB24EA 8D6C24 10 lea ebp,dword ptr ss:
00AB24EE 2BE0 sub esp,eax
00AB24F0 53 push ebx
00AB24F1 56 push esi
00AB24F2 57 push edi
00AB24F3 8B45 F8 mov eax,dword ptr ss:
00AB24F6 8965 E8 mov dword ptr ss:,esp
00AB24F9 50 push eax
00AB24FA 8B45 FC mov eax,dword ptr ss:
00AB24FD C745 FC FFFFFFF>mov dword ptr ss:,-1
00AB2504 8945 F8 mov dword ptr ss:,eax
00AB2507 8D45 F0 lea eax,dword ptr ss:
00AB250A 64:A3 00000000mov dword ptr fs:,eax
00AB2510 C3 retn
7C8024D6 68 C09A837C push kernel32.7C839AC0
7C8024DB 64:A1 00000000mov eax,dword ptr fs:
7C8024E1 50 push eax
7C8024E2 8B4424 10 mov eax,dword ptr ss:
7C8024E6 896C24 10 mov dword ptr ss:,ebp
7C8024EA 8D6C24 10 lea ebp,dword ptr ss:
7C8024EE 2BE0 sub esp,eax
7C8024F0 53 push ebx
7C8024F1 56 push esi
7C8024F2 57 push edi
7C8024F3 8B45 F8 mov eax,dword ptr ss:
7C8024F6 8965 E8 mov dword ptr ss:,esp
7C8024F9 50 push eax
7C8024FA 8B45 FC mov eax,dword ptr ss:
7C8024FD C745 FC FFFFFFF>mov dword ptr ss:,-1
7C802504 8945 F8 mov dword ptr ss:,eax
7C802507 8D45 F0 lea eax,dword ptr ss:
7C80250A 64:A3 00000000mov dword ptr fs:,eax
7C802510 C3 retn找到了,原来在这里。
比较一下就能看出来:代码地址相对于内存基地址的偏移是固定。这也就是为什么内存大小跟相应的dll的镜像大小相等:壳是为了保证能让所有的API都能复制到一个内存段中,所以只能申请一个跟dll的镜像一样大的内存段。
了解了这些,修复的方法就呼之欲出了。
伪IAT中的API地址其实都是真的,只是基地址不对,只要减去当前的基地址,再加上原来的基地址就一些OK了!!00453D6C BE 485DA800 mov esi,0A85D48 ; 伪IAT的开始地址
00453D71 81FE 1863A800 cmp esi,0A86318 ; 伪IAT的结束位置
00453D77 68 0000AB00 push 0AB0000
00453D7C 68 0000BD00 push 0BD0000
00453D81 68 0000C600 push 0C60000
00453D86 68 0000D100 push 0D10000
00453D8B 68 0000DA00 push 0DA0000
00453D90 68 0000DB00 push 0DB0000
00453D95 68 0000E000 push 0E00000
00453D9A 68 0000EA00 push 0EA0000
00453D9F 68 0000F400 push 0F40000 ; 这些是每个dll的代码所在的内存段,具体参见笔记
===========================================================================================
00453DA4 72 05 jb short zp_1_4.00453DAB
00453DA6 E9 07010000 jmp zp_1_4.00453EB2 ; 出口,在这里下好断点~
00453DAB 8B06 mov eax,dword ptr ds:
00453DAD 3E:3B4424 20 cmp eax,dword ptr ds:
00453DB2 72 4E jb short zp_1_4.00453E02 ; 出错口
00453DB4 3E:3B4424 1C cmp eax,dword ptr ds:
00453DB9 72 52 jb short zp_1_4.00453E0D
00453DBB 3E:3B4424 18 cmp eax,dword ptr ds:
00453DC0 72 57 jb short zp_1_4.00453E19
00453DC2 3E:3B4424 14 cmp eax,dword ptr ds:
00453DC7 72 5C jb short zp_1_4.00453E25
00453DC9 3E:3B4424 10 cmp eax,dword ptr ds:
00453DCE 72 61 jb short zp_1_4.00453E31
00453DD0 3E:3B4424 0C cmp eax,dword ptr ds:
00453DD5 72 66 jb short zp_1_4.00453E3D
00453DD7 3E:3B4424 08 cmp eax,dword ptr ds:
00453DDC 72 6B jb short zp_1_4.00453E49
00453DDE 3E:3B4424 04 cmp eax,dword ptr ds:
00453DE3 72 70 jb short zp_1_4.00453E55
00453DE5 3E:3B0424 cmp eax,dword ptr ds:
00453DE9 72 76 jb short zp_1_4.00453E61
00453DEB BB A8000000 mov ebx,0A8
00453DF0 8BEC mov ebp,esp
00453DF2 3E:8B4D 00 mov ecx,dword ptr ds:
00453DF6 290E sub dword ptr ds:,ecx
00453DF8 E8 00000000 call zp_1_4.00453DFD
00453DFD 5A pop edx
00453DFE 03D3 add edx,ebx
00453E00 FFD2 call edx
00453E02 83C6 04 add esi,4
00453E05 81FE 1863A800 cmp esi,0A86318
00453E0B^ EB 97 jmp short zp_1_4.00453DA4
=====================================================================================
00453E0D 3E:8D6C24 20 lea ebp,dword ptr ds:
00453E12 BB 70000000 mov ebx,70 ; ebx中的值是函数的偏移,主要是为了代码的可移植性
00453E17^ EB D9 jmp short zp_1_4.00453DF2
00453E19 3E:8D6C24 1C lea ebp,dword ptr ds:
00453E1E BB 77000000 mov ebx,77
00453E23^ EB CD jmp short zp_1_4.00453DF2
00453E25 3E:8D6C24 18 lea ebp,dword ptr ds:
00453E2A BB 7E000000 mov ebx,7E
00453E2F^ EB C1 jmp short zp_1_4.00453DF2
00453E31 3E:8D6C24 14 lea ebp,dword ptr ds:
00453E36 BB 85000000 mov ebx,85
00453E3B^ EB B5 jmp short zp_1_4.00453DF2
00453E3D 3E:8D6C24 10 lea ebp,dword ptr ds:
00453E42 BB 8C000000 mov ebx,8C
00453E47^ EB A9 jmp short zp_1_4.00453DF2
00453E49 3E:8D6C24 0C lea ebp,dword ptr ds:
00453E4E BB 93000000 mov ebx,93
00453E53^ EB 9D jmp short zp_1_4.00453DF2
00453E55 3E:8D6C24 08 lea ebp,dword ptr ds:
00453E5A BB 9A000000 mov ebx,9A
00453E5F^ EB 91 jmp short zp_1_4.00453DF2
00453E61 3E:8D6C24 04 lea ebp,dword ptr ds:
00453E66 BB A1000000 mov ebx,0A1
00453E6B^ EB 85 jmp short zp_1_4.00453DF2
================================================================================================
00453E6D 8106 0000807C add dword ptr ds:,7C800000 ; 下面是每个dll的真实基址
00453E73 C3 retn
00453E74 8106 0000D177 add dword ptr ds:,77D10000
00453E7A C3 retn
00453E7B 8106 0000DA77 add dword ptr ds:,77DA0000
00453E81 C3 retn
00453E82 8106 00000F77 add dword ptr ds:,770F0000
00453E88 C3 retn
00453E89 8106 0000BD77 add dword ptr ds:,77BD0000
00453E8F C3 retn
00453E90 8106 0000EF77 add dword ptr ds:,77EF0000
00453E96 C3 retn
00453E97 8106 0000175D add dword ptr ds:,5D170000
00453E9D C3 retn
00453E9E 8106 0000927C add dword ptr ds:,7C920000
00453EA4 C3 retn
00453EA5 8106 0000597D add dword ptr ds:,7D590000
00453EAB C3 retn二进制
BE 48 5D A8 00 81 FE 18 63 A8 00 68 00 00 AB 00 68 00 00 BD 00 68 00 00 C6 00 68 00 00 D1 00 68
00 00 DA 00 68 00 00 DB 00 68 00 00 E0 00 68 00 00 EA 00 68 00 00 F4 00 72 05 E9 07 01 00 00 8B
06 3E 3B 44 24 20 72 4E 3E 3B 44 24 1C 72 52 3E 3B 44 24 18 72 57 3E 3B 44 24 14 72 5C 3E 3B 44
24 10 72 61 3E 3B 44 24 0C 72 66 3E 3B 44 24 08 72 6B 3E 3B 44 24 04 72 70 3E 3B 04 24 72 76 BB
A8 00 00 00 8B EC 3E 8B 4D 00 29 0E E8 00 00 00 00 5A 03 D3 FF D2 83 C6 04 81 FE 18 63 A8 00 EB
97 3E 8D 6C 24 20 BB 70 00 00 00 EB D9 3E 8D 6C 24 1C BB 77 00 00 00 EB CD 3E 8D 6C 24 18 BB 7E
00 00 00 EB C1 3E 8D 6C 24 14 BB 85 00 00 00 EB B5 3E 8D 6C 24 10 BB 8C 00 00 00 EB A9 3E 8D 6C
24 0C BB 93 00 00 00 EB 9D 3E 8D 6C 24 08 BB 9A 00 00 00 EB 91 3E 8D 6C 24 04 BB A1 00 00 00 EB
85 81 06 00 00 80 7C C3 81 06 00 00 D1 77 C3 81 06 00 00 DA 77 C3 81 06 00 00 0F 77 C3 81 06 00
00 BD 77 C3 81 06 00 00 EF 77 C3 81 06 00 00 17 5D C3 81 06 00 00 92 7C C3 81 06 00 00 59 7D C3执行完这段代码后就得到了修复好的IAT了。00A85D4877D29719user32.PtInRect
00A85D4C77D28F1Fuser32.IntersectRect
00A85D5077EFB1DEgdi32.GetDIBColorTable
00A85D5477D2B19Cuser32.DestroyWindow
00A85D587C92FE01ntdll.RtlGetLastWin32Error
00A85D5C77D242EDuser32.SetForegroundWindow
00A85D6077EFB5EAgdi32.CreatePalette
00A85D647C802446kernel32.Sleep
00A85D6877D30277user32.OpenClipboard
00A85D6C77D29ED9user32.GetKeyState
00A85D7077D2D226user32.GetKeyboardState
00A85D747C809F81kernel32.InitializeCriticalSection
00A85D787C8360DBkernel32.GlobalFindAtomA
00A85D7C77EF700Agdi32.CreateCompatibleBitmap
00A85D8077D30D96user32.EmptyClipboard
00A85D8477D297FFuser32.IsIconic
00A85D885D1B2C59comctl32.ImageList_BeginDragIAT的二进制
19 97 D2 77 1F 8F D2 77 DE B1 EF 77 9C B1 D2 77 01 FE 92 7C ED 42 D2 77 EA B5 EF 77 46 24 80 7C
77 02 D3 77 D9 9E D2 77 26 D2 D2 77 81 9F 80 7C DB 60 83 7C 0A 70 EF 77 96 0D D3 77 FF 97 D2 77
59 2C 1B 5D FD 4C 0F 77 A9 E4 D2 77 7E C1 D2 77 00 10 92 7C 81 9E D2 77 CE EC EF 77 9D 86 D1 77
1C EF EF 77 65 02 D3 77 6B 21 D3 77 5A 51 0F 77 1B 82 EF 77 1B A9 D2 77 B2 DE D2 77 2F 9C D2 77
C7 06 81 7C D0 B6 EF 77 5A 13 93 7C 26 ED D3 77 28 8E D1 77 9B F9 D2 77 55 96 D2 77 F6 9B D2 77
E1 9A 80 7C 5E 20 83 7C FE A9 F2 77 AB 7A DA 77 46 24 80 7C 1A B6 EF 77 BB 6B 0F 77 84 CB D2 77
BF 99 80 7C 8A BA EF 77 B1 C7 F1 77 F3 99 D2 77 30 25 80 7C F3 D5 D2 77 1E 0C 81 7C A5 99 80 7C
7A 97 D2 77 10 AB 0F 77 AB 0B 83 7C 10 F7 D4 77 1C EF D2 77 E8 C2 D2 77 F2 D2 80 7C B4 F6 D4 77
C7 03 D3 77 8A 9C D2 77 DB 11 D3 77 08 C9 D2 77 08 C9 D2 77 E6 61 D5 77 78 D5 17 5D 60 9B D2 77
AA 18 BD 77 EF D9 EF 77 5D EE D3 77 C1 A0 EF 77 3E D3 D2 77 29 5E EF 77 53 1D 80 7C 1B 9C D2 77
A1 01 81 7C 37 D8 EF 77 44 99 D2 77 02 C7 D3 77 AB AE D2 77 AD F0 D2 77 9E 0F D3 77 6D 40 1B 5D
D5 8F D2 77 97 D9 EF 77 FF DC EF 77 A0 97 D2 77 82 2B 1B 5D 96 D8 D2 77 8E 90 D2 77 23 98 D2 77
5B F2 D2 77 B0 C8 D2 77 12 B1 D2 77 D0 97 80 7C F6 8B D1 77 5A CA D2 77 16 F7 D1 77 07 95 D2 77
7A C3 D2 77 5F 6E EF 77 A6 8F D2 77 1E DA EF 77 1F 6D F0 77 BA 0D D3 77 FA 2C 1B 5D EE 8B EF 77
5F F4 D2 77 30 99 D2 77 0A 98 80 7C 9E BA EF 77 19 9E EF 77 3C 47 D2 77 21 90 D1 77 AB 7A DA 77
C8 F1 D4 77 97 85 EF 77 7F 9A F1 77 7C 79 F0 77 0F 91 D2 77 5A 13 93 7C 55 9C 80 7C E2 DF D2 77
C7 86 D1 77 9D D3 D2 77 17 87 D2 77 12 FF 80 7C EA 07 D5 77 49 24 81 7C 56 98 80 7C 14 8E EF 77
FD 8F D2 77 46 BE 80 7C D2 D1 D2 77 DB 5E EF 77 6B F5 D2 77 30 AE 80 7C 04 F7 D2 77 AA 60 82 7C
06 2F 81 7C 05 02 18 5D 77 5D EF 77 2F FB D2 77 12 D3 D2 77 D3 CE D2 77 22 B2 D2 77 D0 D8 EF 77
AD 2F 81 7C B0 C8 D2 77 C4 D2 D2 77 9C F6 D4 77 DF 06 18 5D 5F B5 80 7C 06 62 83 7C 3F AE D1 77
EF 70 87 7C 27 D4 D2 77 05 80 D6 77 B8 96 D1 77 39 4B 0F 77 1D 9A 80 7C F9 C7 D2 77 1E 98 80 7C
42 8C D1 77 56 6A EF 77 F4 C7 17 5D BD FD 80 7C 9D 08 83 7C BA 14 D3 77 7B 1F D3 77 91 BE 80 7C
5E C3 D2 77 EC A3 0F 77 5B EA EF 77 78 8E D1 77 4C B7 EF 77 BF FC 80 7C A1 2C 1B 5D F6 E8 D2 77
42 78 DA 77 C9 2F 81 7C E0 10 92 7C 17 6C DA 77 90 F7 82 7C F2 D2 80 7C F5 2D 1B 5D EA 07 D5 77
45 88 D2 77 C9 2F 81 7C EF 19 BD 77 B8 97 80 7C C1 60 83 7C 0E 97 D1 77 69 38 81 7C 80 84 18 5D
17 0E 81 7C 06 F3 D2 77 A9 FF 80 7C 45 A0 80 7C 42 78 DA 77 17 6C DA 77 BE E9 EF 77 44 FD EF 77
25 8D EF 77 5E AE D6 77 88 9C 80 7C EF 61 EF 77 A6 51 0F 77 00 10 92 7C B8 97 80 7C 17 0E 81 7C
F2 1E 80 7C A7 A0 80 7C DA 94 D1 77 F1 AE D1 77 19 BF 80 7C 95 C5 D2 77 D6 2B 1B 5D AE A5 D2 77
64 A1 80 7C D1 4C 83 7C 13 93 D2 77 6E 2B 81 7C EA E7 D2 77 E0 10 92 7C A1 6A EF 77 5F B5 80 7C
28 1A 80 7C D7 00 D3 77 1D 9A 80 7C 1B 2C 1B 5D 40 A3 D2 77 F4 AA EF 77 5D 94 D1 77 C1 61 EF 77
6E AC 80 7C 6A 12 81 7C 9C 8F D1 77 28 8E D1 77 D7 9B 80 7C F6 97 80 7C B4 F9 D4 77 45 DF EF 77
FD 68 18 5D C5 2E 1B 5D 0C 94 D1 77 67 EE 80 7C 61 BA 80 7C EC 90 EF 77 11 12 D3 77 BD 1A D3 77
61 BA 80 7C 65 F9 D4 77 49 98 D2 77 39 FF D2 77 A5 9F EF 77 C8 98 D2 77 DD 02 83 7C 50 49 0F 77
22 2D 1B 5D 9D C2 D2 77 4B B8 EF 77 71 FE D2 77 1E 53 D6 77 A5 A4 80 7C 11 90 D2 77 28 8B EF 77
4E 97 D2 77 81 9F 80 7C 71 5A EF 77 40 1A BD 77 D8 03 18 5D FA 6B EF 77 80 8A D1 77 6A 3E 86 7C
70 5B EF 77 1A A2 EF 77 FE 98 D2 77 8C 39 81 7C 7B 1D 80 7C 79 6F EF 77 A4 AE F2 77 12 D3 D2 77
87 F7 D2 77 E6 2D 81 7C F0 48 0F 77 D5 98 D2 77 29 82 83 7C 47 9F F1 77 9B 86 EF 77 42 00 D3 77
23 AD EF 77 99 2A 81 7C E0 5F EF 77 2E 8C D1 77 73 86 D2 77 FF EB D3 77 9F AC 80 7C 01 F6 D1 77
80 48 0F 77 FD AA D2 77 F1 DF 18 5D 00 00 D3 77 74 9B 80 7C 32 86 EF 77 39 F5 D2 77 EC 87 EF 77
C6 B3 D2 77 C2 F3 D2 77 AB 8E D1 77 F2 F2 D2 77 50 F7 D2 77 90 70 F0 77 4E F2 D4 77 DA B8 81 7C
6C D0 D3 77 F6 F3 D4 77 B0 99 80 7C 6E FA D2 77 3A E3 17 5D 7D A9 D2 77 F6 99 EF 77 30 AE 80 7C
BC 70 D5 77 5E EA D2 77 40 E9 D3 77 67 F9 D1 77 A5 AB 94 7C 94 00 D3 77 6E AC 80 7C 27 CD 80 7C
2E 93 80 7C E1 82 D2 77 55 AA 0F 77 12 18 80 7C A9 2F 1B 5D 56 90 D1 77 E9 8F D2 77 2A F9 D2 77
07 D1 80 7C A5 61 EF 77 62 62 D5 77 EA FE D2 77 56 AF D2 77 CB A0 80 7C 69 D9 EF 77 A3 89 D2 77
66 97 D2 77 E6 C7 F0 77 FA CA 81 7C E1 9A 80 7C 6C B6 17 5D 22 78 D2 77 D2 03 F0 77 A5 A4 80 7C
CF 2C 1B 5D F9 BC 80 7C 3D 9E D2 77 6A 12 81 7C 46 DE D1 77 89 C6 D3 77 F6 FB D2 77 4C 7B EF 77
64 A8 80 7C 75 EE F0 77 7A 15 D3 77 B4 90 D2 775,修复IAT调用
IAT修复完了,下面要把IAT的调用格式改回原来的方式。00453DD9 B9 F0114000 mov ecx,zp_1_4.004011F0----IAT调用的起始位置
00453DDE 8039 E9 cmp byte ptr ds:,0E9
00453DE1 75 46 jnz short zp_1_4.00453E29 ;继续搜索
00453DE3 8079 05 90 cmp byte ptr ds:,90
00453DE7 75 40 jnz short zp_1_4.00453E29
00453DE9 66:8379 03 09 cmp word ptr ds:,9
00453DEE 90 nop
00453DEF 74 07 je short zp_1_4.00453DF8
00453DF1 66:8379 03 07 cmp word ptr ds:,7 ; 继续搜索
00453DF6 75 31 jnz short zp_1_4.00453E29
00453DF8 51 push ecx
00453DF9 8B59 01 mov ebx,dword ptr ds:
00453DFC 8D4C19 05 lea ecx,dword ptr ds:--------计算跳转目标地址
00453E00 8039 68 cmp byte ptr ds:,68----------------检验是不是push 提取码的指令
00453E03 75 24 jnz short zp_1_4.00453E29
==============================================================================
00453E05 FF71 01 push dword ptr ds:
00453E08 FF15 346FA500 call dword ptr ds:-----------------调用壳的IAT解密call获取IAT的地址
00453E0E 8B0D 8076A500 mov ecx,dword ptr ds:
00453E14 8D1C81 lea ebx,dword ptr ds:
==============================================================================
00453E17 59 pop ecx
00453E18 8959 02 mov dword ptr ds:,ebx
00453E1B 66:C701 FF25 mov word ptr ds:,25FF-----------------修复代码
00453E20 83C1 06 add ecx,6
00453E23^ EB B9 jmp short zp_1_4.00453DDE
00453E25 0000 add byte ptr ds:,al
00453E27 0000 add byte ptr ds:,al
00453E29 81F9 A3394200 cmp ecx,zp_1_4.004239A3
00453E2F^ 0F8F D7FEFFFF jg zp_1_4.00453D0C----------------出口,跳到OEP去
00453E35 41 inc ecx
00453E36^ EB A6 jmp short zp_1_4.00453DDE-----------------继续查找
00453E38 90 nop二进制
B9 F0 11 40 00 80 39 E9 75 46 80 79 05 90 75 40 66 83 79 03 09 90 74 07 66 83 79 03 07 75 31 51
8B 59 01 8D 4C 19 05 80 39 68 75 24 FF 71 01 FF 15 34 6F A5 00 8B 0D 80 76 A5 00 8D 1C 81 59 89
59 02 66 C7 01 FF 25 83 C1 06 EB B9 00 00 00 00 81 F9 A3 39 42 00 0F 8F D7 FE FF FF 41 EB A6 90执行完一遍之后,大部分IAT调用都被修复了。
不过由于代码忽略了一部分调用,这是要把:
00453DE9 66:8379 03 09 cmp word ptr ds:,9
这里的9 改成8,然后再执行一遍就OK了!
6,修复被模拟的GetModuleHandleA函数。
这没什么技术含量,找到GetModuleHandleA的地址,然后贴到里面就OK了!
7,挪动IAT。
恩?怎么不dump呢?
因为现在程序的IAT表还在程序外面呢,我们要把它移动回程序代码里面。
先找个地方放这些IAT。从第二个区段开始就是壳代码部分了。程序运行的时候不会用到,那我们就把IAT放在第二个区段。
然后打开UIF(Universal Import Fixer)这个工具,输入加壳程序的进程ID。和新的IAT的地址。
点击Fix,就可以把IAT表全部移回来了!
8,抓取镜像
IAT修复好了,终于到了激动人心的时刻。用LordPE(记得取消勾选“从磁盘文件粘贴文件头”这个选项哦)dump下这个程序。然后用ImportREC获取IAT,重建输入表。
运行一下,发现无法初始化。囧……
用OD载入修复后的文件,发现直接停在系统领空,提示出现内存读取错误,我晕…… 看来不是代码的问题,是PE头的问题。这个PE头也残废了…… 无语。
重新勾选“从磁盘文件粘贴文件头”这个选项,再抓一次,然后重新修复。发现这回没有出现初始化错误,但仍运行不了。果然是文件头的问题。-----可是别忘了,磁盘文件的PE头也是个残疾。
别灰心哦,还记得上次那个资源表的问题么?内存中的PE头,资源表的位置是对的,而磁盘文件的PE头,资源表是错的。那好,就先修复资源表。修复了以后发现可以找到资源了。但是程序仍运行。
9,修复程序
现在只能相信自己PE头问题,继续找不能运行的原因。
OD载入,运行。几次跟踪下来,发现程序不能运行的地方居然是Delphi程序初始化代码的部分…… 见鬼了,这应该跟PE头没什么关系了的。
仔细想一下………………
明白了!刚才为了查找IAT解密call。是单步走的。是不是某些变量被初始化了,导致无法运行呢?
用另一个OD载入加壳程序,依上面的方法到OEP去,然后复制数据,然后粘贴到脱壳程序的相应位置。再搜索一下“修改的数据”
,发现果然有很多处不同~ 看来方向对了!保存脱壳文件,果然可以运行了!!
脱壳成功!
总结:
1,Delphi程序很娇气,脱壳的时候最好在OEP处脱壳,否则变量初始化以后就很容易出问题。
2,Anti-Hook保护强度并不大,老烟应该考虑把不同dll的函数放在同一个内存段里面,这样不容易修复。
3,学会自己写patch代码
4,残疾PE头+残疾PE头=健全PE头
5,ESP定律辅助断点的设置。
6,UIF的使用。
注意:这个CrackMe的按钮事件代码被ZProtect混淆了。下次再讲如何修复这种代码混淆。
To Be Continued... 学习大牛的作品
今天是个好日子
:loveliness: 终于ZP................... 谢谢楼主分享,学习了。 佩服
膜拜大牛... 学习...... 牛 不甚明白........... 很强i。。在此拜过 学习学习~~