作者:hyperchem
目标程序是一个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:[ebp+8],0
- 7C80B73A 74 18 je short kernel32.7C80B754<--- 在这里下F2断点.
- 7C80B73C FF75 08 push dword ptr ss:[ebp+8]
- 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:[eax+4]
- 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:[455058]
- 00453D21 8B00 mov eax,dword ptr ds:[eax]
- 00453D23 E8 74E3FFFF call zp_1_4.0045209C
- 00453D28 8B0D 38514500 mov ecx,dword ptr ds:[455138] ; zp_1_4.00456BFC
- 00453D2E A1 58504500 mov eax,dword ptr ds:[455058]
- 00453D33 8B00 mov eax,dword ptr ds:[eax]
- 00453D35 8B15 3C364500 mov edx,dword ptr ds:[45363C] ; zp_1_4.00453688
- 00453D3B E8 74E3FFFF call zp_1_4.004520B4
- 00453D40 A1 58504500 mov eax,dword ptr ds:[455058]
- 00453D45 8B00 mov eax,dword ptr ds:[eax]
- 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:[4571E4] ds:[0045716C]=00A425D0
- 00401264 $- FF25 6C714500 jmp dword ptr ds:[45716C] ds:[004571E4]=00A425D0
可见两处调用是同一个伪IAT。
IAT调用开始位置:004011F4
IAT调用结束位置:004239A3
这样可以减少查找时间。
3,接下来找IAT的解密call
F7单步走,一直走,直到走进一处IAT调用的代码后,记录下面的代码。
根据我第一篇的分析,下面就是解密call了
- 00A643E5 FF15 346FA500 call dword ptr ds:[A56F34] 这个就是解密call了~
- 00A6D63D 8B0D 8076A500 mov ecx,dword ptr ds:[A57680]--这里装的是伪IAT的地址
- 00A64674 85C9 test ecx,ecx
- 00A59940 8BF0 mov esi,eax
- 00A5AF4D /0F84 55910000 je 00A640A8
- 00A5B842 A1 8476A500 mov eax,dword ptr ds:[A57684]
- 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:[ecx+esi*4]--这里就是获得函数地址了
- 00A5C901 894C24 2C mov dword ptr ss:[esp+2C],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:[A57680]
这里给出的IAT基地址才是真正完整的IAT地址。
4,修复Anti-Hook
下面就是伪IAT了(部分,全本见附件)
- 00A85D48 00BE9719
- 00A85D4C 00BE8F1F
- 00A85D50 00DBB1DE
- 00A85D54 00BEB19C
- 00A85D58 00EAFE01
- 00A85D5C 00BE42ED
- 00A85D60 00DBB5EA
- 00A85D64 00AB2446
- 00A85D68 00BF0277
- 00A85D6C 00BE9ED9
- 00A85D70 00BED226
- 00A85D74 00AB9F81
- 00A85D78 00AE60DB
不过首先要先修复被Hook的API地址。
向上翻看下。发现这里有
这里有一连串的DLL基址
简单分析一下就会知道:
数据的结构是这样的:
Dword CopyMemorySize
Dword CopyDllBase
Dword CopyMemoryBase
需要说明的是,这里面的CopyMemorySize正好等于相应dll的镜像大小。
为什么会这样呢?继续看下就知道了~
- 00A84CF0 0011E000
- 00A84CF4 7C800000 kernel32.7C800000
- 00A84CF8 00AB0000
- 00A84CFC 00090000
- 00A84D00 77D10000 user32.77D10000
- 00A84D04 00BD0000
- 00A84D08 000A9000
- 00A84D0C 77DA0000 advapi32.77DA0000
- 00A84D10 00C60000
- 00A84D14 0008B000
- 00A84D18 770F0000 oleaut32.770F0000
- 00A84D1C 00D10000
- 00A84D20 00008000
- 00A84D24 77BD0000 version.77BD0000
- 00A84D28 00DA0000
- 00A84D2C 00049000
- 00A84D30 77EF0000 gdi32.77EF0000
- 00A84D34 00DB0000
- 00A84D38 0009A000
- 00A84D3C 5D170000 comctl32.5D170000
- 00A84D40 00E00000
- 00A84D44 00093000
- 00A84D48 7C920000 ntdll.7C920000
- 00A84D4C 00EA0000
- 00A84D50 007F4000
- 00A84D54 7D590000 shell32.7D590000
- 00A84D58 00F40000
我们现在知道了00AB0000 这里内存里面放的是Kernel32.dll的函数。那么我们就进去看看代码
在这里找一段代码,二进制复制,然后在内存中查找这段二进制
- 00AB24D6 68 C09A837C push 7C839AC0
- 00AB24DB 64:A1 00000000 mov eax,dword ptr fs:[0]
- 00AB24E1 50 push eax
- 00AB24E2 8B4424 10 mov eax,dword ptr ss:[esp+10]
- 00AB24E6 896C24 10 mov dword ptr ss:[esp+10],ebp
- 00AB24EA 8D6C24 10 lea ebp,dword ptr ss:[esp+10]
- 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:[ebp-8]
- 00AB24F6 8965 E8 mov dword ptr ss:[ebp-18],esp
- 00AB24F9 50 push eax
- 00AB24FA 8B45 FC mov eax,dword ptr ss:[ebp-4]
- 00AB24FD C745 FC FFFFFFF>mov dword ptr ss:[ebp-4],-1
- 00AB2504 8945 F8 mov dword ptr ss:[ebp-8],eax
- 00AB2507 8D45 F0 lea eax,dword ptr ss:[ebp-10]
- 00AB250A 64:A3 00000000 mov dword ptr fs:[0],eax
- 00AB2510 C3 retn
- 7C8024D6 68 C09A837C push kernel32.7C839AC0
- 7C8024DB 64:A1 00000000 mov eax,dword ptr fs:[0]
- 7C8024E1 50 push eax
- 7C8024E2 8B4424 10 mov eax,dword ptr ss:[esp+10]
- 7C8024E6 896C24 10 mov dword ptr ss:[esp+10],ebp
- 7C8024EA 8D6C24 10 lea ebp,dword ptr ss:[esp+10]
- 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:[ebp-8]
- 7C8024F6 8965 E8 mov dword ptr ss:[ebp-18],esp
- 7C8024F9 50 push eax
- 7C8024FA 8B45 FC mov eax,dword ptr ss:[ebp-4]
- 7C8024FD C745 FC FFFFFFF>mov dword ptr ss:[ebp-4],-1
- 7C802504 8945 F8 mov dword ptr ss:[ebp-8],eax
- 7C802507 8D45 F0 lea eax,dword ptr ss:[ebp-10]
- 7C80250A 64:A3 00000000 mov dword ptr fs:[0],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:[esi]
- 00453DAD 3E:3B4424 20 cmp eax,dword ptr ds:[esp+20]
- 00453DB2 72 4E jb short zp_1_4.00453E02 ; 出错口
- 00453DB4 3E:3B4424 1C cmp eax,dword ptr ds:[esp+1C]
- 00453DB9 72 52 jb short zp_1_4.00453E0D
- 00453DBB 3E:3B4424 18 cmp eax,dword ptr ds:[esp+18]
- 00453DC0 72 57 jb short zp_1_4.00453E19
- 00453DC2 3E:3B4424 14 cmp eax,dword ptr ds:[esp+14]
- 00453DC7 72 5C jb short zp_1_4.00453E25
- 00453DC9 3E:3B4424 10 cmp eax,dword ptr ds:[esp+10]
- 00453DCE 72 61 jb short zp_1_4.00453E31
- 00453DD0 3E:3B4424 0C cmp eax,dword ptr ds:[esp+C]
- 00453DD5 72 66 jb short zp_1_4.00453E3D
- 00453DD7 3E:3B4424 08 cmp eax,dword ptr ds:[esp+8]
- 00453DDC 72 6B jb short zp_1_4.00453E49
- 00453DDE 3E:3B4424 04 cmp eax,dword ptr ds:[esp+4]
- 00453DE3 72 70 jb short zp_1_4.00453E55
- 00453DE5 3E:3B0424 cmp eax,dword ptr ds:[esp]
- 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:[ebp]
- 00453DF6 290E sub dword ptr ds:[esi],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:[esp+20]
- 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:[esp+1C]
- 00453E1E BB 77000000 mov ebx,77
- 00453E23 ^ EB CD jmp short zp_1_4.00453DF2
- 00453E25 3E:8D6C24 18 lea ebp,dword ptr ds:[esp+18]
- 00453E2A BB 7E000000 mov ebx,7E
- 00453E2F ^ EB C1 jmp short zp_1_4.00453DF2
- 00453E31 3E:8D6C24 14 lea ebp,dword ptr ds:[esp+14]
- 00453E36 BB 85000000 mov ebx,85
- 00453E3B ^ EB B5 jmp short zp_1_4.00453DF2
- 00453E3D 3E:8D6C24 10 lea ebp,dword ptr ds:[esp+10]
- 00453E42 BB 8C000000 mov ebx,8C
- 00453E47 ^ EB A9 jmp short zp_1_4.00453DF2
- 00453E49 3E:8D6C24 0C lea ebp,dword ptr ds:[esp+C]
- 00453E4E BB 93000000 mov ebx,93
- 00453E53 ^ EB 9D jmp short zp_1_4.00453DF2
- 00453E55 3E:8D6C24 08 lea ebp,dword ptr ds:[esp+8]
- 00453E5A BB 9A000000 mov ebx,9A
- 00453E5F ^ EB 91 jmp short zp_1_4.00453DF2
- 00453E61 3E:8D6C24 04 lea ebp,dword ptr ds:[esp+4]
- 00453E66 BB A1000000 mov ebx,0A1
- 00453E6B ^ EB 85 jmp short zp_1_4.00453DF2
- ================================================================================================
- 00453E6D 8106 0000807C add dword ptr ds:[esi],7C800000 ; 下面是每个dll的真实基址
- 00453E73 C3 retn
- 00453E74 8106 0000D177 add dword ptr ds:[esi],77D10000
- 00453E7A C3 retn
- 00453E7B 8106 0000DA77 add dword ptr ds:[esi],77DA0000
- 00453E81 C3 retn
- 00453E82 8106 00000F77 add dword ptr ds:[esi],770F0000
- 00453E88 C3 retn
- 00453E89 8106 0000BD77 add dword ptr ds:[esi],77BD0000
- 00453E8F C3 retn
- 00453E90 8106 0000EF77 add dword ptr ds:[esi],77EF0000
- 00453E96 C3 retn
- 00453E97 8106 0000175D add dword ptr ds:[esi],5D170000
- 00453E9D C3 retn
- 00453E9E 8106 0000927C add dword ptr ds:[esi],7C920000
- 00453EA4 C3 retn
- 00453EA5 8106 0000597D add dword ptr ds:[esi],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了。
- 00A85D48 77D29719 user32.PtInRect
- 00A85D4C 77D28F1F user32.IntersectRect
- 00A85D50 77EFB1DE gdi32.GetDIBColorTable
- 00A85D54 77D2B19C user32.DestroyWindow
- 00A85D58 7C92FE01 ntdll.RtlGetLastWin32Error
- 00A85D5C 77D242ED user32.SetForegroundWindow
- 00A85D60 77EFB5EA gdi32.CreatePalette
- 00A85D64 7C802446 kernel32.Sleep
- 00A85D68 77D30277 user32.OpenClipboard
- 00A85D6C 77D29ED9 user32.GetKeyState
- 00A85D70 77D2D226 user32.GetKeyboardState
- 00A85D74 7C809F81 kernel32.InitializeCriticalSection
- 00A85D78 7C8360DB kernel32.GlobalFindAtomA
- 00A85D7C 77EF700A gdi32.CreateCompatibleBitmap
- 00A85D80 77D30D96 user32.EmptyClipboard
- 00A85D84 77D297FF user32.IsIconic
- 00A85D88 5D1B2C59 comctl32.ImageList_BeginDrag
- IAT的二进制
- 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 77
5,修复IAT调用
IAT修复完了,下面要把IAT的调用格式改回原来的方式。
- 00453DD9 B9 F0114000 mov ecx,zp_1_4.004011F0----IAT调用的起始位置
- 00453DDE 8039 E9 cmp byte ptr ds:[ecx],0E9
- 00453DE1 75 46 jnz short zp_1_4.00453E29 ;继续搜索
- 00453DE3 8079 05 90 cmp byte ptr ds:[ecx+5],90
- 00453DE7 75 40 jnz short zp_1_4.00453E29
- 00453DE9 66:8379 03 09 cmp word ptr ds:[ecx+3],9
- 00453DEE 90 nop
- 00453DEF 74 07 je short zp_1_4.00453DF8
- 00453DF1 66:8379 03 07 cmp word ptr ds:[ecx+3],7 ; 继续搜索
- 00453DF6 75 31 jnz short zp_1_4.00453E29
- 00453DF8 51 push ecx
- 00453DF9 8B59 01 mov ebx,dword ptr ds:[ecx+1]
- 00453DFC 8D4C19 05 lea ecx,dword ptr ds:[ecx+ebx+5]--------计算跳转目标地址
- 00453E00 8039 68 cmp byte ptr ds:[ecx],68----------------检验是不是push 提取码的指令
- 00453E03 75 24 jnz short zp_1_4.00453E29
- ==============================================================================
- 00453E05 FF71 01 push dword ptr ds:[ecx+1]
- 00453E08 FF15 346FA500 call dword ptr ds:[A56F34]-----------------调用壳的IAT解密call获取IAT的地址
- 00453E0E 8B0D 8076A500 mov ecx,dword ptr ds:[A57680]
- 00453E14 8D1C81 lea ebx,dword ptr ds:[ecx+eax*4]
- ==============================================================================
- 00453E17 59 pop ecx
- 00453E18 8959 02 mov dword ptr ds:[ecx+2],ebx
- 00453E1B 66:C701 FF25 mov word ptr ds:[ecx],25FF-----------------修复代码
- 00453E20 83C1 06 add ecx,6
- 00453E23 ^ EB B9 jmp short zp_1_4.00453DDE
- 00453E25 0000 add byte ptr ds:[eax],al
- 00453E27 0000 add byte ptr ds:[eax],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:[ecx+3],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的使用。