实践ASProtect 2.1x SKE脱壳(街头篮球客户端)
纯粹的照猫画虎,高手就不用浪费时间看了。
感谢loveboom的教程《ASPROTECT 2.x 脱壳系列》!
感谢mirrormask的《学习ASProtect 2.1x SKE 脱壳》一文!
感谢shoooo的指教!
工具:OllyICE,Lord-PE,ImportREC.
声明:这个脱文几乎就是loveboom的《ASPROTECT 2.x 脱壳系列之一》的翻版。
好,现在切入正题,我尽可能说的详细一些。有些地方,我还是一知半解,所以可能解释有误,还望高手斧正。
首先,因为街头篮球使用的HackShield系统。HackSield系统的反调试功能很强。
所以,如果让其加载了Hackshield的系统,那么客户端主程序FreeStyle.exe在OD下就跑不起来了.
我没有能力去搞掉hackShield系统,所以我把HackShield的目录改名,让其无法加载HackShield.
然后,可以用OD加载Freestyle.exe,忽略所有异常。看看能不能跑起来。
我这里能够跑起来,运行后加载HackShield的时候,程序会告知无法加载,等待你点一下确定,然后就退出了。
最后提醒一点:如果加载了HackShield用OD调试,好像会引起死机.
不过,这时候程序已经完全从壳里面解了出来.所以脱壳的目的是可以达到的.
用OD加载Freestyle.exe.
会停在这里:
///////////////////////////////////////////////////////////////////////
00401000 >/$ 68 01F06E00 push 006EF001
00401005 |. E8 01000000 call 0040100B
0040100A \. C3 retn
0040100B $ C3 retn
0040100C E4 db E4
0040100D 24 db 24 ; CHAR '$'
0040100E 2A db 2A ; CHAR '*'
...后面全是乱七八糟的数据,不用管.
/////////////////////////////////////////////////////////////////////////////////
!!!:记住隐藏OD.(用HideOD插件)
脱壳的第一步,就是找到OEP.
帮助找到OEP的方法很多,比如ESP定律,2次内存映射断点等等.
这里可以使用这个方法.
先忽略除非法访问内存异常外的所有异常.然后按F9(运行程序).应该会有异常出现按shift+F9忽略.注意记住你忽略了多少次异常后程序开始运行.(可以设置忽略所有异常,清空LOG,然后然程序跑,跑起来后,看LOG数一数异常纪录的个数就能知道有几次异常)(我这是22次,如果没数错~)
然后重新加载.忽略除非法访问内存异常外的所有异常,最后一次异常发生时,给代码段下断点(方法:ALT+M,然后找到freestyle的代码段,选中后按一下F2),然后shift+F9忽略异常.
这时就停在了OEP了:
///////////////////////////////////////////////////////////////////////////
00626777 . 55 push ebp ; FreeStyl.0046637E
00626778 . 8BEC mov ebp, esp
0062677A . 6A FF push -1
0062677C . 68 18B16500 push 0065B118
00626781 . 68 B0B46200 push 0062B4B0 ; SE 处理程序安装
00626786 . 64:A1 0000000>mov eax, fs:[0]
0062678C . 50 push eax
0062678D . 64:8925 00000>mov fs:[0], esp
00626794 . 83EC 58 sub esp, 58
00626797 . 53 push ebx
00626798 . 56 push esi
00626799 . 57 push edi
0062679A . 8965 E8 mov [ebp-18], esp
0062679D . FF15 B0206500 call [6520B0] ; kernel32.GetVersion
////////////////////////////////////////////////////////////////////////////
记下OEP备以后用:这里是00626777.
好了OEP就找到了.
然后就是IAT了.
看到上面的call [6520B0] ;kernel32.GetVersion那么就去去006520B0,向上看找找以一大堆00结尾在哪里,在向下看同样找找零结尾在哪里.发现IAT从00652000开始到0065247C结束,而且没有加密.
判断加密的方法,我是去看代码段最后面的一些整齐排列jmp [xxxxxxx]看看有没有被一定数量的相同call xxxxxxxx(xxxxxxxx一般是同一个数)隔开.如果没有,8成是没加密.因为call xxxxxxx就是壳的解密函数.
这个程序没有。而且IAT地址看起来都没有问题:
//////////////////////////////////////////////////////////////////////////////
这个就是IAT:
00652000 1B C4 DC 77 83 78 DA 77 F0 6B DA 77 00 00 00 00 能w?邝痣邝....
00652010 26 D9 18 6D 00 00 00 00 24 49 37 00 00 00 00 00 &?m....$I7.....
00652020 98 6E EF 77 8A 5A EF 77 D6 E8 EF 77 00 60 EF 77 ?秣?秣骤秣.`秣
00652030 52 D4 EF 77 90 5B EF 77 97 5D EF 77 49 5E EF 77 R燥w?秣?秣I^秣
00652040 7C 8B F0 77 1D 8E F0 77 B3 BF F0 77 2D 6C EF 77 |?w?w晨瘅-l秣
00652050 60 B2 F1 77 B8 85 EF 77 33 8C EF 77 FB 5E EF 77 `柴w?秣3?w?秣
00652060 49 92 EF 77 00 00 00 00 B3 22 30 76 A6 3A 30 76 I?w....?0v?0v
00652070 66 55 30 76 F3 29 30 76 82 5B 30 76 F8 6F 30 76 fU0v?0v?0v?0v
00652080 8E 4D 30 76 2B 47 30 76 00 00 00 00 53 30 82 7C ?0v+G0v....S0?
00652090 A9 26 82 7C FB 2C 82 7C 7C 36 81 7C 3D 04 93 7C ????|6?=?
006520A0 D4 05 93 7C 0D E0 80 7C 16 1E 80 7C A2 CA 81 7C ??.?|€|⑹?
006520B0 AB 14 81 7C EE 1E 80 7C 5C E8 81 7C 94 22 82 7C ???€|\?|??
006520C0 E1 EA 81 7C 40 7A 95 7C 5D 99 80 7C E0 C6 80 7C 彡?@z?]?|嗥€|
006520D0 52 70 82 7C 8B C2 85 7C 84 E5 81 7C 7C 2F 81 7C Rp?????|/?
006520E0 6E 9C 80 7C 3F FF 81 7C 28 9C 80 7C BD E4 81 7C n?|??(?|戒?
006520F0 A9 2C 81 7C 64 B6 80 7C F4 97 80 7C AC 92 80 7C ??d?|?€|?€|
00652100 86 03 81 7C FD 79 93 7C 59 35 81 7C E6 2B 81 7C ????Y5???
00652110 43 99 80 7C 2A E8 81 7C 0E 18 80 7C 19 90 83 7C C?|*?|€|?|
00652120 D7 EF 80 7C EC E9 80 7C 66 EA 80 7C 4E A3 80 7C 罪€|扉€|f?|N?|
00652130 93 D2 80 7C 94 97 80 7C 42 24 80 7C 57 B3 80 7C ?€|?€|B$€|W?|
00652140 C1 C9 80 7C 79 E0 81 7C 77 9B 80 7C 8D 3A 86 7C 辽€|y?|w?|??
00652150 B7 47 86 7C 63 4C 81 7C A1 97 83 7C AD 9C 80 7C 非?cL????€|
00652160 A1 9F 80 7C 8A 18 93 7C ED 10 92 7C 05 10 92 7C ?€|?????
00652170 90 72 DD 00 C4 2F 88 7C 66 AA 80 7C 7B 97 80 7C ????f?|{?|
00652180 5C 9B 85 7C 8D 2C 81 7C 29 B5 80 7C 9F 0F 81 7C \?|??)?|??
00652190 31 03 93 7C 8F 0C 81 7C 8D B7 80 7C 6C 94 80 7C 1????€|l?|
006521A0 24 1A 80 7C 76 09 81 7C C7 A0 80 7C 51 28 81 7C $€|v.?沁€|Q(?
006521B0 FC B7 80 7C B2 AC 80 7C ED CB 81 7C 17 A4 80 7C ?€|铂€|硭??|
006521C0 DA 56 82 7C 6B 17 80 7C 72 17 81 7C 50 F8 81 7C 谥?k€|r?P?|
006521D0 C0 9F 80 7C ED 70 83 7C 7E D4 80 7C E3 12 81 7C ?€|眇?~?|??
006521E0 53 C1 81 7C AE 94 83 7C 80 A4 80 7C B9 8C 83 7C S?|??€?|??
006521F0 58 CD 80 7C CB D8 81 7C 57 BB 80 7C C4 CE 80 7C X?|素?W?|奈€|
00652200 2B 2E 83 7C 29 9F 80 7C 81 9A 80 7C 14 9B 80 7C +.?)?|?€|?|
00652210 29 29 81 7C 10 11 81 7C 6A 48 81 7C 78 2C 81 7C ))??jH?x,?
00652220 23 CC 81 7C 5F 48 81 7C 19 62 82 7C B3 9E 80 7C #?|_H?b??€|
00652230 2F 08 81 7C 37 97 80 7C F5 9B 80 7C 50 97 80 7C /?7?|?€|P?|
00652240 A9 CC 80 7C 3F DC 81 7C 8A 2B 86 7C 69 10 81 7C ┨€|??|??i?
00652250 CF C6 80 7C A6 0D 81 7C ED 09 93 7C 49 AA 80 7C 掀€|????I?|
00652260 0F 2B 81 7C 40 03 93 7C 00 3C 86 7C 00 00 00 00 +?@?.<?....
00652270 60 9A 00 10 30 9B 00 10 50 96 00 10 90 96 00 10 `?0?P??.
00652280 80 91 00 10 F0 93 00 10 C0 96 00 10 80 99 00 10 €??.?.€?
00652290 20 99 00 10 A0 3A 00 10 A0 3A 00 10 A0 90 00 10 ??.?._?.
006522A0 10 93 00 10 40 92 00 10 00 40 00 10 E0 38 00 10 ?@?.@.?.
006522B0 B0 94 00 10 A0 91 00 10 10 94 00 10 50 9A 00 10 ?._?.?P?
006522C0 90 9A 00 10 B0 9A 00 10 D0 99 00 10 40 97 00 10 ?.?.?.@?
006522D0 80 95 00 10 70 96 00 10 20 97 00 10 10 9B 00 10 €?p? ??
006522E0 F0 9A 00 10 A0 40 00 10 70 3B 00 10 00 10 00 10 ?._@.p;...
006522F0 F0 10 00 10 40 10 00 10 B0 11 00 10 80 3F 00 10 ?.@.?.€?.
00652300 D0 3A 00 10 A0 39 00 10 A0 96 00 10 F0 96 00 10 ?.?._?.?.
00652310 C0 3B 00 10 A0 3E 00 10 30 3C 00 10 80 3E 00 10 ?.?.0<.€>.
00652320 40 40 00 10 40 40 00 10 40 40 00 10 60 3E 00 10 @@.@@.@@.`>.
00652330 20 38 00 10 D0 3A 00 10 D0 3A 00 10 00 3B 00 10 8.?.?..;.
00652340 90 38 00 10 10 9A 00 10 30 9A 00 10 00 00 00 00 ?.?0?....
00652350 20 49 0F 77 C2 4B 0F 77 50 48 0F 77 95 D2 11 77 Iw滤wPHw?w
00652360 D9 66 0F 77 C0 48 0F 77 3B 4C 0F 77 A8 4C 0F 77 冁w廊w;Lwㄌw
00652370 C3 CA 11 77 55 4C 0F 77 00 00 00 00 85 CB D1 77 檬wULw....?痒
00652380 9A F3 D2 77 60 DA D1 77 33 B9 D1 77 AE B6 D1 77 ?吟`谘w3寡w?痒
00652390 1B C0 D1 77 9D 8F D1 77 EA 04 D5 77 AD A8 D1 77 姥w?痒?征?痒
006523A0 C2 D7 D1 77 DA C6 D3 77 09 B6 D1 77 1D B6 D1 77 伦痒谄喻.堆w堆w
006523B0 F6 8B D1 77 6C C9 D1 77 B8 96 D1 77 24 13 D2 77 ?痒l裳w?痒$吟
006523C0 3E 0B D2 77 0D D6 D1 77 F9 D7 D1 77 5D 94 D1 77 >吟.盅w?痒]?w
006523D0 6C BF D1 77 5E 02 D2 77 A4 D8 D1 77 E6 37 D2 77 l垦w^吟へ痒?吟
006523E0 EA DA D1 77 EE D4 D1 77 41 BD D1 77 C6 B5 D1 77 贲痒钤痒A窖w频痒
006523F0 11 12 D2 77 00 00 00 00 FF 19 BD 77 50 1A BD 77 吟....谨P谨
00652400 BA 18 BD 77 00 00 00 00 5B 4E B1 76 00 00 00 00 ?谨....[N宾....
00652410 66 2B A2 71 41 3F A2 71 D4 4F A2 71 00 00 00 00 f+ⅠA?Ⅰ韵Ⅰ....
00652420 80 E8 D3 6D 00 00 00 00 10 AA 11 21 70 A0 11 21 €栌m....?!p?!
00652430 20 A6 12 21 20 A2 11 21 30 A1 11 21 60 A8 11 21 ?! ?!0?!`?!
00652440 A0 A5 11 21 00 A5 11 21 90 B5 11 21 70 34 11 21 _?!.?!?!p4!
00652450 60 AC 11 21 70 AE 11 21 00 AB 11 21 A0 A4 11 21 `?!p?!.?!_?!
00652460 C0 36 11 21 00 00 00 00 36 EE 9A 76 37 2A 9B 76 ?!....6?v7*?
00652470 C3 FA 9A 76 BA 61 A0 76 00 00 00 00 00 00 00 00 铭?横_v........
/////////////////////////////////////////////////////////////////////////////////
好了,知道了IAT从00652000开了,大小为:047C
纪录下来。
现在到了脱壳最困难麻烦的地方了.
大家知道vc的程序,一般OEP后面就是GetVersion后接着就是GetStartInfo.我们看看这个程序的OEP处了代码.
///////////////////////////////////////////////////////////////////////////////////////////////
00626777 . 55 push ebp ; FreeStyl.0046637E
00626778 . 8BEC mov ebp, esp
0062677A . 6A FF push -1
0062677C . 68 18B16500 push 0065B118
00626781 . 68 B0B46200 push 0062B4B0 ; SE 处理程序安装
00626786 . 64:A1 0000000>mov eax, fs:[0]
0062678C . 50 push eax
0062678D . 64:8925 00000>mov fs:[0], esp
00626794 . 83EC 58 sub esp, 58
00626797 . 53 push ebx
00626798 . 56 push esi
00626799 . 57 push edi
0062679A . 8965 E8 mov [ebp-18], esp
0062679D . FF15 B0206500 call [6520B0] ; kernel32.GetVersion
006267A3 . 33D2 xor edx, edx
006267A5 . 8AD4 mov dl, ah
006267A7 . 8915 8CA86E00 mov [6EA88C], edx
006267AD . 8BC8 mov ecx, eax
006267AF . 81E1 FF000000 and ecx, 0FF
006267B5 . 890D 88A86E00 mov [6EA888], ecx
006267BB . C1E1 08 shl ecx, 8
006267BE . 03CA add ecx, edx
006267C0 . 890D 84A86E00 mov [6EA884], ecx
006267C6 . C1E8 10 shr eax, 10
006267C9 . A3 80A86E00 mov [6EA880], eax
006267CE . 6A 01 push 1
006267D0 . E8 3F750000 call 0062DD14
006267D5 . 59 pop ecx
006267D6 . 85C0 test eax, eax
006267D8 . 75 08 jnz short 006267E2
006267DA . 6A 1C push 1C
006267DC . E8 C3000000 call 006268A4
006267E1 . 59 pop ecx
006267E2 > E8 E53E0000 call 0062A6CC
006267E7 . 85C0 test eax, eax
006267E9 . 75 08 jnz short 006267F3
006267EB . 6A 10 push 10
006267ED . E8 B2000000 call 006268A4
006267F2 . 59 pop ecx
006267F3 > 33F6 xor esi, esi
006267F5 . 8975 FC mov [ebp-4], esi
006267F8 . E8 DE6B0000 call 0062D3DB
006267FD . E8 FE979B00 call 00FE0000 ;!!!!!!!!!到壳里面去了
00626802 . 91 xchg eax, ecx
00626803 . A3 D4CD6E00 mov [6ECDD4], eax
00626808 . E8 60720000 call 0062DA6D
0062680D . A3 70A86E00 mov [6EA870], eax
00626812 . E8 09700000 call 0062D820
00626817 . E8 4B6F0000 call 0062D767
0062681C . E8 0E040000 call 00626C2F
00626821 . 8975 D0 mov [ebp-30], esi
00626824 . 8D45 A4 lea eax, [ebp-5C]
00626827 . 50 push eax
00626828 . E8 D3979B00 call 00FE0000 ;!!!!!!!!到壳里面去了
0062682D . C7 E8 DC 6E 0>ascii "氰茴",0
00626832 00 db 00
00626833 89 db 89
00626834 45 db 45 ; CHAR 'E'
00626835 9C db 9C
后面又是乱七八糟的数据,不用管
///////////////////////////////////////////////////////////////////////////////////////////////
看到了GetVersion了,但是GetStartInfo在哪呢?没有~
但是你应改发现有两个call 00FE0000.
给据loveboom的教导,知道这是壳把原来CALL API改成了CALL xxxxxxxx,这个call xxxxxxxx会到壳代码里面.
(不同机器上面好像xxxxxxxx都不一样).我这里是00FE0000.
现在就是要修复成CALL 正确的API.怎么才能得到这个正确的地址呢.当然只有跟进去看.
不过由于被改了的地方实在太多,人工修复几乎不可能.所以必须写个程序来修复.
这就是Patch.
下面大概讲一下patch的原理.后面会将详细的操作.
patch的方法很多,下面是loveboom提供的方法.
先来整理一下思路,我们要把call xxxxxxxx改称正确的call API.
就必须有一张表.里面一一对应记录着call xxxxxxxx的地址->正确的API的地址.
有了这个表,我们就可以快速的把所有call xxxxxxxx改称正确的call api了.
所以,第一次patch就是为了得到这张表.
怎么得到呢,对于ASPr壳,当进入call xxxxxxxx后,壳会把这个call xxxxxxxx改成正确的call API然后跳回原地,就地进入api.
当然这中间有复杂的算法和繁多的花指令.所以想要逆向得到这个正确的API太麻烦.可以借用壳的代码,在它解出来正确的地址的时候我们把它截取,保存下来.
patch的准备工作:
先重新载入freestyle.exe
先来到OEP,找一个call xxxxxxxx(这里是call 00FE0000)
因为aspr要把call xxxxxxxx改成正确的所以我们在上面下内存写入断点(这里是在006267FD上面下内存写入断点).
F9运行
断在了这里:
///////////////////////////////////////////////////
00DE5C9B 57 push edi
00DE5C9C 6A 00 push 0
00DE5C9E 8D4D E0 lea ecx, [ebp-20]
00DE5CA1 8B45 F4 mov eax, [ebp-C]
00DE5CA4 8B40 3C mov eax, [eax+3C]
00DE5CA7 8B55 FC mov edx, [ebp-4]
00DE5CAA E8 D1130000 call 00DE7080 ;**********
00DE5CAF 8945 FC mov [ebp-4], eax
00DE5CB2 8B45 E0 mov eax, [ebp-20]
00DE5CB5 8B00 mov eax, [eax]
00DE5CB7 E8 D0E6FFFF call 00DE438C
00DE5CBC 8BD0 mov edx, eax
00DE5CBE 0255 DF add dl, [ebp-21]
00DE5CC1 8B4D FC mov ecx, [ebp-4]
00DE5CC4 8B45 F4 mov eax, [ebp-C]
00DE5CC7 E8 80040000 call 00DE614C
00DE5CCC 8945 FC mov [ebp-4], eax
00DE5CCF 8B45 F4 mov eax, [ebp-C]
00DE5CD2 8B40 24 mov eax, [eax+24]
00DE5CD5 8B55 F4 mov edx, [ebp-C]
00DE5CD8 0382 E0000000 add eax, [edx+E0]
00DE5CDE 0145 1C add [ebp+1C], eax
00DE5CE1 8B45 FC mov eax, [ebp-4]
00DE5CE4 2B45 1C sub eax, [ebp+1C]
00DE5CE7 83E8 05 sub eax, 5
00DE5CEA 8B55 1C mov edx, [ebp+1C]
00DE5CED 42 inc edx
00DE5CEE 8902 mov [edx], eax ;断在了这里!!!!
00DE5CF0 EB 01 jmp short 00DE5CF3
00DE5CF2 E8 8B45F883 call 84D6A282
///////////////////////////////////////////////////
向上看,找到:
//////////////////////////////////////////////////////
00DE5C9E 8D4D E0 lea ecx, [ebp-20]
00DE5CA1 8B45 F4 mov eax, [ebp-C]
00DE5CA4 8B40 3C mov eax, [eax+3C]
00DE5CA7 8B55 FC mov edx, [ebp-4]
00DE5CAA E8 D1130000 call 00DE7080
//////////////////////////////////////////////////////
跟随进入call 00DE7080
/////////////////////////////////////////////////////
00DE7080 55 push ebp
00DE7081 8BEC mov ebp, esp
00DE7083 83C4 E4 add esp, -1C
00DE7086 53 push ebx
00DE7087 56 push esi
00DE7088 57 push edi
00DE7089 894D F4 mov [ebp-C], ecx
00DE708C 8955 F8 mov [ebp-8], edx
00DE708F 8945 FC mov [ebp-4], eax
00DE7092 33C0 xor eax, eax
00DE7094 8945 F0 mov [ebp-10], eax
00DE7097 B8 00070000 mov eax, 700
00DE709C E8 A3B4FDFF call 00DC2544 ;**********
00DE70A1 8945 E4 mov [ebp-1C], eax
//////////////////////////////////////////////////////
再跟随进入call 00DC2544
///////////////////////////////////////////////////////
00DC2544 85C0 test eax, eax
00DC2546 74 0A je short 00DC2552
00DC2548 FF15 1890DE00 call [DE9018] ;***!!!!****
00DC254E 09C0 or eax, eax
00DC2550 74 01 je short 00DC2553
00DC2552 C3 retn
//////////////////////////////////////////////////////
看见 call [DE9018]了吗?为什么要跟这么深,因为修改这里的代码不会被壳查出来.
这个地方的call [DE9018]我们就能把它改成其他的call从而改变程序的流程.
纪录call [DE9018]的地址,这里是:
00DC2548 FF15 1890DE00 call [DE9018]
这个是第一次patch的操作:
重新载入,断GetModuleHandleA(用硬件断点).当第二次断下后.清除硬件断点.F8一路返回,遇见jmp就F4到下一行代码.一会就能看见,如下的代码:
////////////////////////////////////////
00DF15C1 61 popad
00DF15C2 75 08 jnz short 00DF15CC
00DF15C4 B8 01000000 mov eax, 1
00DF15C9 C2 0C00 retn 0C
00DF15CC 68 DC89DE00 push 0DE89DC
00DF15D1 C3 retn
///////////////////////////////////////
retn执行以后,到了
///////////////////////////////////////////
00DE89DC 55 push ebp ; 壳的OEP
00DE89DD 8BEC mov ebp, esp
00DE89DF 83C4 B4 add esp, -4C
00DE89E2 B8 D487DE00 mov eax, 0DE87D4
00DE89E7 E8 50CCFDFF call 00DC563C
00DE89EC E8 DBAAFDFF call 00DC34CC
//////////////////////////////////////////
停在了壳的OEP处,搜索如下指令:
MOV [EBP],EAX
PUSH 0A
会找到一处:
00DE5F7B 8945 00 mov [ebp], eax ;在这里下硬件执行断点,断在这里.EIP现在指向这里
00DE5F7E 6A 0A push 0A
00DE5F80 E8 8FCEFEFF call 00DD2E14
00DE5F85 8BC8 mov ecx, eax
00DE5F87 038B E4000000 add ecx, [ebx+E4]
然后F9运行,会断在00DE5F7B mov [ebp], eax;
(不过有时候断不下来,直接就跑飞了,下F2断点反而能断下了,不知道是什么原因,哪位牛人能解释一下.)
断下了后,就开始第一次patch了:
为了方便写程序,就近选个地方写代码,当然要先保存原来的代码,不过OD有撤销修改的功能,就不用专门保存了.
用插件申请一块内存,作为保存上面提到的那张表的空间,有这种功能的插件很多.HideOD也有.我申请到的是01020000
/////////////////////////////////////////////////
00DE5F7B EB 43 jmp 00DE5FC0 ; 注意这里被修改指向我们自己写的代码.EIP还是指向这里
00DE5F7D 90 nop
00DE5F7E 6A 0A push 0A
00DE5F80 E8 8FCEFEFF call 00DD2E14
00DE5F85 8BC8 mov ecx, eax
00DE5F87 038B E4000000 add ecx, [ebx+E4]
00DE5F8D 8BD6 mov edx, esi
00DE5F8F 8BC3 mov eax, ebx
00DE5F91 E8 9EE5FFFF call 00DE4534
00DE5F96 FF0C24 dec dword ptr [esp]
00DE5F99 03B3 E4000000 add esi, [ebx+E4]
00DE5F9F 833C24 00 cmp dword ptr [esp], 0
00DE5FA3 ^ 0F87 55FEFFFF ja 00DE5DFE
00DE5FA9 53 push ebx ;改完,写完代码后这里下F2断点
00DE5FAA E8 5D000000 call 00DE600C
00DE5FAF 0183 EC000000 add [ebx+EC], eax
00DE5FB5 B0 01 mov al, 1
00DE5FB7 83C4 24 add esp, 24
00DE5FBA 5D pop ebp
00DE5FBB 5F pop edi
00DE5FBC 5E pop esi
00DE5FBD 5B pop ebx
00DE5FBE C3 retn
00DE5FBF 90 nop
00DE5FC0 53 push ebx ;选的这里,最近的地方. 开这开始写
00DE5FC1 51 push ecx
00DE5FC2 B9 00415100 mov ecx, 01020000 ;这里数字,填写你想保存这个表的地址.我申请到的地址是01020000,我就保存这
00DE5FC7 8339 00 cmp dword ptr [ecx], 0
00DE5FCA 75 06 jnz short 00DE5FD2
00DE5FCC C701 10415100 mov dword ptr [ecx], 01020010;这里填写保存地址+10h,这里就是01020000h+10h=01020010h
00DE5FD2 8B19 mov ebx, [ecx]
00DE5FD4 4D dec ebp
00DE5FD5 892B mov [ebx], ebp
00DE5FD7 83C3 04 add ebx, 4
00DE5FDA 8919 mov [ecx], ebx
00DE5FDC 45 inc ebp
00DE5FDD 59 pop ecx
00DE5FDE 5B pop ebx
00DE5FDF 8945 00 mov [ebp], eax
00DE5FE2 ^ EB 9A jmp short 00DE5F7E ;这里就写完了
///////////////////////////////////////////////////
写完代码,下好断点.F9运行.停在了
00DE5FA9 53 push ebx
这时把保存的数据复制一份保存备用.我从01020000复制的数据如下:
///////////////////////////////////////////////////////////////////////////////////////////////
3C 02 04 01 00 00 00 00 00 00 00 00 00 00 00 00 89 8A 48 00 D0 D1 48 00 8A D3 48 00 67 1F 49 00
06 20 49 00 20 20 49 00 39 20 49 00 75 20 49 00 E3 20 49 00 92 21 49 00 C4 24 49 00 3E EA 4B 00
59 EB 4B 00 E0 C0 4E 00 87 16 4F 00 C9 46 55 00 7A 47 55 00 88 A0 55 00 3D 16 56 00 A8 16 56 00
C7 16 56 00 E7 16 56 00 98 2A 56 00 BE C6 56 00 D2 C6 56 00 E2 C6 56 00 E2 C7 56 00 57 C8 56 00
62 C8 56 00 E0 C8 56 00 F8 C8 56 00 0B C9 56 00 B6 CA 56 00 BB DA 58 00 BB DB 58 00 07 38 59 00
73 38 59 00 9A F7 59 00 F5 F7 59 00 2D F8 59 00 9D BF 5A 00 FC C3 5A 00 42 D3 5B 00 61 D3 5B 00
30 8B 5F 00 36 8B 5F 00 3C 8B 5F 00 F2 F4 60 00 BC 06 61 00 64 0F 61 00 6B 0F 61 00 79 94 61 00
02 9A 61 00 2E 9B 61 00 88 9B 61 00 B3 9B 61 00 19 9C 61 00 44 9C 61 00 51 9C 61 00 6A 9C 61 00
95 9C 61 00 A2 9C 61 00 AF 9C 61 00 D6 9C 61 00 E4 9D 61 00 F1 9D 61 00 FE 9D 61 00 54 3D 62 00
EF 3F 62 00 2E 63 62 00 58 63 62 00 FD 67 62 00 28 68 62 00 4B 68 62 00 93 6C 62 00 9A 6C 62 00
5F 73 62 00 73 73 62 00 F6 73 62 00 1A 74 62 00 30 74 62 00 74 74 62 00 5C 79 62 00 91 79 62 00
A3 79 62 00 15 7B 62 00 26 83 62 00 BC 83 62 00 40 84 62 00 C3 8A 62 00 0B A7 62 00 78 A7 62 00
0E C6 62 00 84 C7 62 00 99 C7 62 00 24 C8 62 00 90 CD 62 00 F5 CD 62 00 39 D4 62 00 E4 D4 62 00
47 D5 62 00 55 D5 62 00 8C D5 62 00 43 D8 62 00 8C DB 62 00 A9 DB 62 00 20 DC 62 00 80 DC 62 00
17 DE 62 00 ED DE 62 00 F4 DE 62 00 15 09 63 00 5E 09 63 00 E0 13 63 00 FC 13 63 00 14 14 63 00
F5 18 63 00 74 19 63 00 A7 1A 63 00 C7 1C 63 00 1B 1E 63 00 4F 1E 63 00 3F 27 63 00 86 39 63 00
7E 3C 63 00 94 3C 63 00 D5 3D 63 00 39 40 63 00 2D 41 63 00 D3 41 63 00 7E 48 63 00 AB 4E 63 00
D9 4F 63 00 6A 55 63 00 50 58 63 00 62 8F 63 00 83 8F 63 00 93 8F 63 00 AE 8F 63 00 00 00 00 00
///////////////////////////////////////////////////////////////////////////////////////////////
然后撤销所有修改,F9继续运行.来到OEP
如果不幸跑飞,也没有关系.反正表已经拿到了.
重新加载freestyle.exe,来到OEP处,停在这里.
第二次patch准备:
要得到两行代码及其地址的信息.
第一个就是上面提到的:
00DC2548 FF15 1890DE00 call [DE9018]
这个地址有可能变化,但是几率不大.
第二个有点烦:
用了多态技术,一旦重新加所在地址就会变.不过还好,变化的范围不是很大.
第二个代码是:
00FF00BA 9D popfd
00FF00BB 5C pop esp
00FF00BC FF6424 FC JMP DWORD PTR SS:[ESP-4]
不能直接搜索,因为用了多态技术,可能搜不到.
第一次找这个指令可以这样(以后就直接到附近找,注意识别花指令):
回忆在call xxxxxxxx上,下内存写入断点那里
我们断在了(不记得了就去看看前面):
//////////////////////////////////////////////
00DE5C9B 57 push edi
00DE5C9C 6A 00 push 0
00DE5C9E 8D4D E0 lea ecx, [ebp-20]
00DE5CA1 8B45 F4 mov eax, [ebp-C]
00DE5CA4 8B40 3C mov eax, [eax+3C]
00DE5CA7 8B55 FC mov edx, [ebp-4]
00DE5CAA E8 D1130000 call 00DE7080 ;**********
00DE5CAF 8945 FC mov [ebp-4], eax
00DE5CB2 8B45 E0 mov eax, [ebp-20]
00DE5CB5 8B00 mov eax, [eax]
00DE5CB7 E8 D0E6FFFF call 00DE438C
00DE5CBC 8BD0 mov edx, eax
00DE5CBE 0255 DF add dl, [ebp-21]
00DE5CC1 8B4D FC mov ecx, [ebp-4]
00DE5CC4 8B45 F4 mov eax, [ebp-C]
00DE5CC7 E8 80040000 call 00DE614C
00DE5CCC 8945 FC mov [ebp-4], eax
00DE5CCF 8B45 F4 mov eax, [ebp-C]
00DE5CD2 8B40 24 mov eax, [eax+24]
00DE5CD5 8B55 F4 mov edx, [ebp-C]
00DE5CD8 0382 E0000000 add eax, [edx+E0]
00DE5CDE 0145 1C add [ebp+1C], eax
00DE5CE1 8B45 FC mov eax, [ebp-4]
00DE5CE4 2B45 1C sub eax, [ebp+1C]
00DE5CE7 83E8 05 sub eax, 5
00DE5CEA 8B55 1C mov edx, [ebp+1C]
00DE5CED 42 inc edx
00DE5CEE 8902 mov [edx], eax ;断在了这里!!!!
00DE5CF0 EB 01 jmp short 00DE5CF3
00DE5CF2 E8 8B45F883 call 84D6A282
//////////////////////////////////////////////
这个时候用条件跟踪,当遇到POPFD的时候暂停.就能跟到
////////////////////////////////////////////
00FF00BA 9D popfd
00FF00BB 5C pop esp
00FF00BC FF6424 FC JMP DWORD PTR SS:[ESP-4] ;纪录这行代码
////////////////////////////////////////
下面就是第二次patch:
重新载入,来到OEP ,先确定上面提到的两行代码的信息:
直接去00DC2548发现代码没有变:
00DC2548 FF15 1890DE00 call [DE9018]
然后去00FF00BC,应该已经变了.
果然JMP [ESP-4]变到了00FF00AE;
信息已经足够了.
开始写代码.
找代码段后面的空白处写patch代码,现在EIP指向OEP
///////////////////////////////////////////////////////////////////////////////////////
00651100 60 pushad
00651101 B9 10000201 mov ecx, 1020010 ;这里的数填那张表保存的地址+10h
00651106 8B19 mov ebx, [ecx]
00651108 83FB 00 cmp ebx, 0
0065110B 74 15 je short 00651122
0065110D FFE3 jmp ebx
0065110F 8B15 08000201 mov edx, [1020008]
00651115 66:C703 FF15 mov word ptr [ebx], 15FF
0065111A 8953 02 mov [ebx+2], edx
0065111D 83C1 04 add ecx, 4
00651120 ^ EB E4 jmp short 00651106
00651122 33C0 xor eax, eax
00651124 B0 E8 mov al, 0E8
00651126 BF 00104000 mov edi, <模块入口点>
0065112B B9 00102500 mov ecx, 251000 ;这里填代码段的大小
00651130 F2:AE repne scas byte ptr es:[edi]
00651132 83F9 00 cmp ecx, 0
00651135 74 3C je short 00651173
00651137 8B1F mov ebx, [edi]
00651139 8D5C3B 04 lea ebx, [ebx+edi+4]
0065113D 81FB 00104000 cmp ebx, <模块入口点>
00651143 ^ 72 EB jb short 00651130
00651145 81FB 02106600 cmp ebx, 00661002 ;这里填代码段结束的地址
0065114B ^ 77 E3 ja short 00651130
0065114D 66:813B FF15 cmp word ptr [ebx], 15FF
00651152 ^ 75 DC jnz short 00651130
00651154 817B 02 00206>cmp dword ptr [ebx+2], 00652000 ;IAT的起始地址
0065115B ^ 72 D3 jb short 00651130
0065115D 817B 02 78246>cmp dword ptr [ebx+2], 00652478 ;IAT的结束地址-4
00651164 ^ 77 CA ja short 00651130
00651166 66:C703 FF25 mov word ptr [ebx], 25FF
0065116B 83C7 04 add edi, 4
0065116E 83E9 04 sub ecx, 4
00651171 ^ EB BD jmp short 00651130
00651173 61 popad
.......
00651178 dd 83116500 ;这里的数字就是下面函数的第一句指令的地址(小头顺序)
........
00651180 90 nop
00651181 90 nop
00651182 90 nop
00651183 60 pushad
00651184 8BC2 mov eax, edx
00651186 B9 80040000 mov ecx, 480 ;IAT的大小+4
0065118B BF 00206500 mov edi, 00652000 IAT的起始地址
00651190 F2:AF repne scas dword ptr es:[edi]
00651192 83EF 04 sub edi, 4
00651195 893D 08000201 mov [1020008], edi;保存表的地址+8
0065119B 61 popad
0065119C FF15 1890DE00 call [DE9018] ;刚才00DC2548 FF15 1890DE00 call [DE9018] 中被call寻址的地址
006511A2 C3 retn
006511A3 90 nop
/////////////////////////////////////////////////////////////////////////////////////
这些patch程序都是loveboom所写,根据需要修改相应的数值,如果不清楚有些数是怎么来的,可以去看看上面.和去看看loveboom的文章.
当然,问问别人是最快的解决方式.
然后:
把上面提到的
00DC2548 FF15 1890DE00 call [DE9018]
代码改成:
00DC2548 FF15 1890DE00 call [651178]
就是让他进入我们的patch代码的第二个函数。
写一段ODScript:
////////////////////////////////////////////////////////////////////////
//fixed aspr 2.x
var addr
start:
run
l1:
cmp eip,00FF00AE ;这里的数字是上面提到的jmp [esp-4]的地址,这里是00ff00AE
jne l2
mov addr,esp
sub addr,4
mov [addr],0065110F 这个数字是上面patch2代码中jmp ebx后面那句的地址,这里是
jmp start
l2:
ret
/////////////////////////////////////////////////////////////////////////
保存成OD脚本.
然后把EIP从哦OEP改向我们patch代码的第一句,这里是:
00651100 60 pushad
然后要在上面提到的jmp [esp-4]的地址,这里是00ff00AE上面下硬件执行断点。
其次,在patch结束句,这里是
00651173 61 popad上面
下F2断点。
最后运行脚本。等待一段时间,脚本运行完毕后,清除掉所有的修改。
dump,修复IAT.
就大功告成了。
PS:
我从看教程到脱壳成功一共用了30小时的时间,分4天。
前几个小时,都是学习PE文件。通过这次脱壳,让我对PE文件有了比较深的认识。原来都是一知半解。
脱壳对我等菜鸟来说是个很艰苦的工程,关键要有毅力和耐心。
现在目标是绕过加载HackShield.
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)