【文章标题】: 某外挂 SVKP 1.4x -> Pavol Cerven脱壳
【作 者】: chasgone(阳离子)
【加壳方式】: SVKP 1.4x -> Pavol Cerven
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
用 peid查壳为SVKP 1.3x -> Pavol Cerven
其实是高版本的壳
一、oep
od载入,忽略所有异常,在resource段下断点 f9, 然后在code段下断点 再f9 就到oep了
00401000 /EB 10 jmp short hx.00401012
00401002 |66:623A bound di,dword ptr ds:[edx]
00401005 |43 inc ebx
00401006 |2B2B sub ebp,dword ptr ds:[ebx]
00401008 |48 dec eax
00401009 |4F dec edi
0040100A |4F dec edi
0040100B |4B dec ebx
0040100C |90 nop
0040100D -|E9 40744700 jmp 00878452
00401012 \A1 33744700 mov eax,dword ptr ds:[477433]
00401017 C1E0 02 shl eax,2
0040101A A3 37744700 mov dword ptr ds:[477437],eax
二、搞定iat
od重新载入 下断点bp GetModuleHandleA+5
shift+f9断下,取消断点,ctrl+f9返回主程序。
ctrl+f搜索特征码
cmp dword ptr ds:[ebx],251097CC
把这下面的所有的比较和跳转全部nop掉
然后在搜索特征码
mov dword ptr ds:[edi],eax
popad
改成:
popad
mov dword ptr ds:[edi],eax
然后在code段下断点f2,然后f9就到oep了
拿起importrec 填oep=1000,自动搜索iat 全部有效 保存为树文件 后面有用
三、搞定replaced code
前面的两步和svkp 1.3x的一样,所以说的不详细,现在详细分析replaced code,这是难点。
用上面得到的iat修复 ,fixdump后 ,程序不能运行,od载入脱壳后的文件,发现有很多的
004011B4 E8 674F0700 call <jmp.&kernel32.ExitProcess>
和
00411879 E8 A04F0600 call <jmp.&user32.MessageBoxA>
原来程序把kernel32中的函数都换成ExitProcess公共接口了
把user32.dll里的函数换成MessageBoxA了
现在就是要把这些ExitProcess换成本来的函数。
00401000 /EB 10 jmp short hx.00401012
00401002 |66:623A bound di,dword ptr ds:[edx]
00401005 |43 inc ebx
00401006 |2B2B sub ebp,dword ptr ds:[ebx]
00401008 |48 dec eax
00401009 |4F dec edi
0040100A |4F dec edi
0040100B |4B dec ebx
0040100C |90 nop
0040100D -|E9 40744700 jmp 00878452
00401012 \A1 33744700 mov eax,dword ptr ds:[477433]
00401017 C1E0 02 shl eax,2
0040101A A3 37744700 mov dword ptr ds:[477437],eax
0040101F 52 push edx
00401020 6A 00 push 0
00401022 E8 F9500700 call hx.00476120 新建eip
00401027 8BD0 mov edx,eax
00401029 E8 9EB80600 call hx.0046C8CC
0040102E 5A pop edx
0040102F E8 FCB70600 call hx.0046C830
00401034 E8 D3B80600 call hx.0046C90C
00401039 6A 00 push 0
0040103B E8 F0CA0600 call hx.0046DB30
00401040 59 pop ecx
00401041 68 DC734700 push hx.004773DC
00401046 6A 00 push 0
00401048 E8 D3500700 call hx.00476120
在00401022 处新建eip 然后f7 进去:
00476120 - FF25 FC834800 jmp dword ptr ds:[4883FC]
此时ds:[004883FC]=0DE076A9
正常情况下 004883FC应该是api的入口 但是这里却指向壳中
f8 进去 用f8和f7 单步跟踪 可以跟到这里
0012FE25 58 pop eax
0012FE26 74 07 je short 0012FE2F
0012FE28 83E9 08 sub ecx,8
0012FE2B 74 2A je short 0012FE57
0012FE2D ^ EB DA jmp short 0012FE09
0012FE2F 8B4431 FC mov eax,dword ptr ds:[ecx+esi-4]
此时ds:[0DE0933F]=00488464 (hx.00488464)
eax=00401022 (hx.00401022)
在命令窗口 输入d 0DE0933F
此时可以看到有很大一张表
0DE086CF 004884D0 hx.004884D0
0DE086D3 0046BFD6 hx.0046BFD6
0DE086D7 004884CC hx.004884CC
0DE086DB 0046BF7C hx.0046BF7C
0DE086DF 004884DC hx.004884DC
0DE086E3 0046BCF9 hx.0046BCF9
。。。。。。。
。。。。。。。
0DE09337 00488464 hx.00488464
0DE0933B 00401048 hx.00401048
0DE0933F 00488464 hx.00488464
0DE09343 00401022 hx.00401022
这一张表的含义是什么呢?
奇数行表示正确的函数在iat中的位置
偶数行就是需要修复所在的地址
(可能我表达不大清楚,见笑了)
比如第一行和第二行为
0DE086CF 004884D0 hx.004884D0
0DE086D3 0046BFD6 hx.0046BFD6
我们去0046BFD6看看。结果如下:
0046BFD6 E8 45A10000 call hx.00476120
我们再看看另一张表
00476240 - FF25 BC844800 jmp dword ptr ds:[<&kernel32.GlobalUnloc>; kernel32.GlobalUnlock
00476246 - FF25 C0844800 jmp dword ptr ds:[<&kernel32.HeapAlloc>] ; ntdll.RtlAllocateHeap
0047624C - FF25 C4844800 jmp dword ptr ds:[<&kernel32.HeapFree>] ; ntdll.RtlFreeHeap
00476252 - FF25 C8844800 jmp dword ptr ds:[<&kernel32.InitializeC>; kernel32.InitializeCriticalSection
00476258 - FF25 CC844800 jmp dword ptr ds:[<&kernel32.Interlocked>; kernel32.InterlockedDecrement
0047625E - FF25 D0844800 jmp dword ptr ds:[<&kernel32.Interlocked>; kernel32.InterlockedIncrement
ds:[004884D0]=77E5A660 (kernel32.InterlockedIncrement)
...............
即0047625E 对应的就是004884D0
根据这一张表,我们就知道0046BFD6 处应该怎么改了,应该改为 call 0047625E
此dll的开始地址为 4760E4 结束地址为476342 下面会用到这两个地址
现在的任务就是写代码来修复了
申请一块内存,我申请的是10000000 大小为10000
写如下代码:
10000000 60 pushad
10000001 9C pushfd
10000002 C705 00010010 CF86E>mov dword ptr ds:[10000100],0DE086CF
1000000C A1 00010010 mov eax,dword ptr ds:[10000100]
10000011 8B18 mov ebx,dword ptr ds:[eax]
10000013 83C0 08 add eax,8
10000016 A3 00010010 mov dword ptr ds:[10000100],eax
1000001B 8B50 FC mov edx,dword ptr ds:[eax-4]
1000001E E8 1A000000 call 1000003D
10000023 83EB 05 sub ebx,5
10000026 2BDA sub ebx,edx
10000028 895A 01 mov dword ptr ds:[edx+1],ebx
1000002B A1 00010010 mov eax,dword ptr ds:[10000100]
10000030 3D 3F93E00D cmp eax,0DE0933F
10000035 ^ 7E D5 jle short 1000000C
10000037 9D popfd
10000038 61 popad
10000039 - EB FE jmp short 10000039
1000003B 90 nop
1000003C 90 nop
1000003D B8 E4604700 mov eax,4760E4
10000042 3958 02 cmp dword ptr ds:[eax+2],ebx
10000045 74 0C je short 10000053
10000047 83C0 06 add eax,6
1000004A 3D 42634700 cmp eax,476342
1000004F ^ 7E F1 jle short 10000042
10000051 - EB FE jmp short 10000051
10000053 8BD8 mov ebx,eax
10000055 C3 retn
在10000000 新建eip f9执行, 此时就全部替换了kernel32中以ExitProcess为公共接口的函数了
下面就是要替换user32.dll中以MessageBoxA为公共接口的函数,还是要找出那两张表,然后写一段代码就行了
下面我们开始找user32.dll中以MessageBoxA的地址表 ,步骤和上面一样
可以跟到这里
0012FF13 8B4431 FC mov eax,dword ptr ds:[ecx+esi-4] ; hx.00488D9C
ds:[0DE2BD0A]=00488D9C (hx.00488D9C)
eax=00402F76 (hx.00402F76)
于是可以找到这张表为:
0DE2B09A 00488D60 hx.00488D60
0DE2B09E 0043FFBC hx.0043FFBC
0DE2B0A2 00488B38 hx.00488B38
0DE2B0A6 0043FF68 hx.0043FF68
0DE2B0AA 00488BE8 hx.00488BE8
0DE2B0AE 0043FF1D hx.0043FF1D
。。。。。。。。
。。。。。。。。
0DE2BCEE 0040B25E hx.0040B25E
0DE2BCF2 00488B6C hx.00488B6C
0DE2BCF6 0040B244 hx.0040B244
0DE2BCFA 00488B80 hx.00488B80
0DE2BCFE 0040B1C2 hx.0040B1C2
0DE2BD02 00488B80 hx.00488B80
0DE2BD06 004084B6 hx.004084B6
0DE2BD0A 00488D9C hx.00488D9C
0DE2BD0E 00402F76 hx.00402F76
开始地址 0DE2B09A
结束地址 0DE2BD0A
再看看另一张表
004765A8 - FF25 2C8B4800 jmp dword ptr ds:[<&user32.ActivateKeybo>; user32.ActivateKeyboardLayout
004765AE - FF25 308B4800 jmp dword ptr ds:[<&user32.AdjustWindowR>; user32.AdjustWindowRectEx
004765B4 - FF25 348B4800 jmp dword ptr ds:[<&user32.BeginPaint>] ; user32.BeginPaint
004765BA - FF25 388B4800 jmp dword ptr ds:[<&user32.CallNextHookE>; user32.CallNextHookEx
。。。。。。。。。。
00476938 - FF25 8C8D4800 jmp dword ptr ds:[<&user32.UpdateWindow>>; user32.UpdateWindow
0047693E - FF25 908D4800 jmp dword ptr ds:[<&user32.WaitMessage>] ; user32.WaitMessage
00476944 - FF25 948D4800 jmp dword ptr ds:[<&user32.WinHelpA>] ; user32.WinHelpA
0047694A - FF25 988D4800 jmp dword ptr ds:[<&user32.WindowFromPoi>; user32.WindowFromPoint
00476950 - FF25 9C8D4800 jmp dword ptr ds:[<&user32.wsprintfA>] ; user32.wsprintfA
00476956 - FF25 A08D4800 jmp dword ptr ds:[<&user32.GetSystemMenu>; user32.GetSystemMenu
修复代码为
10000000 60 pushad
10000001 9C pushfd
10000002 C705 00010010 9AB0E>mov dword ptr ds:[10000100],0DE2B09A
1000000C A1 00010010 mov eax,dword ptr ds:[10000100]
10000011 8B18 mov ebx,dword ptr ds:[eax]
10000013 83C0 08 add eax,8
10000016 A3 00010010 mov dword ptr ds:[10000100],eax
1000001B 8B50 FC mov edx,dword ptr ds:[eax-4]
1000001E E8 1A000000 call 1000003D
10000023 83EB 05 sub ebx,5
10000026 2BDA sub ebx,edx
10000028 895A 01 mov dword ptr ds:[edx+1],ebx
1000002B A1 00010010 mov eax,dword ptr ds:[10000100]
10000030 3D 0ABDE20D cmp eax,0DE2BD0A
10000035 ^ 7E D5 jle short 1000000C
10000037 9D popfd
10000038 61 popad
10000039 - EB FE jmp short 10000039
1000003B 90 nop
1000003C 90 nop
1000003D B8 A8654700 mov eax,4765A8
10000042 3958 02 cmp dword ptr ds:[eax+2],ebx
10000045 74 0C je short 10000053
10000047 83C0 06 add eax,6
1000004A 3D 56694700 cmp eax,476956
1000004F ^ 7E F1 jle short 10000042
10000051 - EB FE jmp short 10000051
10000053 8BD8 mov ebx,eax
10000055 C3 retn
在10000000 新建eip ,f9
到这里,代码就修复完了。
这个程序没有mov 类的replaced code。否则还要继续写代码修复,其实知道方法也不难。
现在可以拿起lordpe ,修正imagesize,dump,用第二步得到的iat ,fixdump ,运行成功
脱壳人:chasgone(阳离子)
2006年6月5日
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)