由于加了这个壳让很多人无法使用,病毒误报情况严重,而且运行效率也慢很多。
鉴于此,决定把壳脱了,彻底解决病毒误报,提高运行效率。现把脱壳过程总结一下,作为教程发上来,供大家交流和参详。
工具篇:
OllyICE, PEiD, LoadPE, ImportRec
脱壳篇:
1. PEiD查壳, 是SVKP 1.3x -> Pavol Cerven,如图所示
2. 寻找OEP
打开OD, 调试设置里忽略全部异常,SFX页设置“选择块方式跟踪真正的入口点”,确定后加载游戏程序文件。
由于SFX的设置,所以程序不会停在SVPK壳的入口点:
00802000 TtT-cn.<模块入口点> 60 pushad
00802001 E8 00000000 call 00802006
而是直接来到这个壳有名的特征异常处:
0012E37E 6285 1E220000 bound eax, qword ptr [ebp+221E]
0012E384 EB 02 jmp short 0012E388
下硬件执行断点: he GetModuleHandleA 然后shift+F9运行,约20秒后,程序断在GetModuleHandleA入口处。
77E692A5 kernel32.GetModuleHandleA 8BFF mov edi, edi
77E692A7 55 push ebp
接下来为了让脱壳过程更加简单直接和系统化,我们在到达OEP前先解决API的重定向。
2. 修复IAT
删除前面的硬件断点,Alt+F9回到程序领空,ctrl+F 寻找SVPK壳的特征命令
cmp dword ptr [ebx], 2D66B1C5
来到这里:
019B5784 813B C5B1662D cmp dword ptr [ebx], 2D66B1C5
019B578A 0F84 62180000 je 019B6FF2
019B5790 813B 9404B2D9 cmp dword ptr [ebx], D9B20494
019B5796 0F84 AA1C0000 je 019B7446
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
019B5838 813B B8B8B2FB cmp dword ptr [ebx], FBB2B8B8
019B583E 0F84 56320000 je 019B8A9A
019B5844 813B 8E5D2D57 cmp dword ptr [ebx], 572D5D8E
019B584A 0F84 86320000 je 019B8AD6
019B5850 60 pushad
019B5851 8B03 mov eax, dword ptr [ebx]
019B5853 8985 D8550200 mov dword ptr [ebp+255D8], eax
上面这段是壳加密关键API的地方,我们跳过这些代码不让他加密,方法是把 019B578A 的 je 019B6FF2 修改成 jmp 019B5850 直接跳到019B5850 的 pushad处。
Ctrl+S 继续搜索第二处特征码
mov dword ptr ds:[edi],eax
popad
来到这里:
019B5B4F 8907 mov dword ptr [edi], eax
019B5B51 61 popad
我们颠倒这两句为
019B5B4F 61 popad
019B5B50 8907 mov dword ptr [edi], eax
经过以上处理,壳对API的重定向已经几乎形同虚设。
然后F9一下就直接停在程序的OEP了
00514E14 90 nop
00514E15 90 nop
00514E16 90 nop
。。。。。。。。。。。。。。。。。。。。。。
00514E6A 90 nop
00514E6B 90 nop
00514E6C 90 nop
00514E6D . E8 774C0000 call 00519AE9 ; SFX 代码真正入口点
00514E72 . 59 pop ecx
00514E73 . 85C0 test eax, eax
00514E75 . 75 08 jnz short 00514E7F
00514E77 . 6A 1C push 1C
00514E79 . E8 C3000000 call 00514F41
3. 修补Stolen code
如大家所见,程序开头处被偷换了N多代码,数了数从00514E14 到00514E6C 共有0x58个nop, 即88个字节的代码被偷换了~ORZ
这么大的偷换量还原起来还是有一定的难度地。幸运的是,我们知道这是汉化版程序,是从日文原版修改来的,所以修复程序OEP的Stolen code可以直接拿日文原版的来用。
OD打开日文版程序复制OEP处88个字节:
00514B94 TtTjp.<模块入口点> /$ 55 push ebp
00514B95 |. 8BEC mov ebp, esp
00514B97 |. 6A FF push -1
00514B99 |. 68 104E5300 push 00534E10
00514B9E |. 68 F04C5100 push 00514CF0 ; SE 处理程序安装
00514BA3 |. 64:A1 00000000 mov eax, dword ptr fs:[0]
00514BA9 |. 50 push eax
00514BAA |. 64:8925 00000000 mov dword ptr fs:[0], esp
00514BB1 |. 83EC 58 sub esp, 58
00514BB4 |. 53 push ebx
00514BB5 |. 56 push esi
00514BB6 |. 57 push edi
00514BB7 |. 8965 E8 mov [local.6], esp
00514BBA |. FF15 24625200 call near dword ptr [<&KERNEL32.GetVersion>; kernel32.GetVersion
00514BC0 |. 33D2 xor edx, edx
00514BC2 |. 8AD4 mov dl, ah
00514BC4 |. 8915 44DE7A00 mov dword ptr [7ADE44], edx
00514BCA |. 8BC8 mov ecx, eax
00514BCC |. 81E1 FF000000 and ecx, 0FF
00514BD2 |. 890D 40DE7A00 mov dword ptr [7ADE40], ecx
00514BD8 |. C1E1 08 shl ecx, 8
00514BDB |. 03CA add ecx, edx
00514BDD |. 890D 3CDE7A00 mov dword ptr [7ADE3C], ecx
00514BE3 |. C1E8 10 shr eax, 10
00514BE6 |. A3 38DE7A00 mov dword ptr [7ADE38], eax
00514BEB |. 6A 01 push 1 ; 复制到这里
00514BED |. E8 774C0000 call 00519869
二进制复制粘贴覆盖那些nop得到
00514E14 55 push ebp ; OEP
00514E15 8BEC mov ebp, esp
00514E17 6A FF push -1
00514E19 68 104E5300 push 00534E10
00514E1E 68 F04C5100 push 00514CF0
00514E23 64:A1 00000000 mov eax, dword ptr fs:[0]
00514E29 50 push eax
00514E2A 64:8925 00000000 mov dword ptr fs:[0], esp
00514E31 83EC 58 sub esp, 58
00514E34 53 push ebx
00514E35 56 push esi
00514E36 57 push edi
00514E37 8965 E8 mov dword ptr [ebp-18], esp
00514E3A FF15 24625200 call near dword ptr [526224] ; 注意这个API是GetVersion
00514E40 33D2 xor edx, edx
00514E42 8AD4 mov dl, ah
00514E44 8915 44DE7A00 mov dword ptr [7ADE44], edx
00514E4A 8BC8 mov ecx, eax
00514E4C 81E1 FF000000 and ecx, 0FF
00514E52 890D 40DE7A00 mov dword ptr [7ADE40], ecx
00514E58 C1E1 08 shl ecx, 8
00514E5B 03CA add ecx, edx
00514E5D 890D 3CDE7A00 mov dword ptr [7ADE3C], ecx
00514E63 C1E8 10 shr eax, 10
00514E66 A3 38DE7A00 mov dword ptr [7ADE38], eax
00514E6B 6A 01 push 1
00514E6D . E8 774C0000 call 00519AE9 ; SFX 代码真正入口点
注意stolen code中有个API的调用也被偷换了 即00514E3A call near dword ptr [526224]
这句查看日文版应该是GetVersion。我们需要手动修复之。
4. dump程序,重建IAT
先运行ImportRec, 选择游戏进程,在OEP 处先填入SFX得到的入口VA地址 00114E6D = 00514E6D - 00400000, 点击自动查找IAT, 获取输入表, 点击显示无效函数发现只有一个地址是无效的,如图所示:
那么,他到底是什么呢? 呵呵 经验告诉我们,SVKP有一个特征API是无法修复的,那就是: "ExitProcess", 这个API的位置正好就在图上 TerminateProcess之后。我们双击这个地址,手动输入ExitProcess即可全部修复完毕。这里顺便在列表中查看一下GetVersion的地址,得到RVA是 00127224 即 VA 00527224
我们再来到OD的那句需要修改的00514E3A 处,改为 call near dword ptr [527224],现在这个API也正常显示了。再请出LoadPE, 先修正下镜像大小,然后完整转存。
接下来我们修复IAT,刚才那个ImportRec窗口大家还没有关吧,呵呵~~
把OEP的地址改为00114E14 (即修补偷换代码后的真正的OEP,第一个nop的地址), 然后直接点击修复转存文件(添加新段打钩)。
这样我们就一步到位的把脱壳和修复完成了。双击修复后的程序运行一切正常。
优化篇:
5. 脱壳后的优化
若你不需要优化,其实也没有什么问题,只是这个脱壳后的文件体积比较大,有4.15M,所以接下来我们做下简单的优化。说到优化,其实也可以一步到位,在刚才最后一步转存完毕,但还没有修复IAT的时候,我们先把转存的文件用LoadPE的PE编辑器打开,把区段表中最后一个区段.svkp删掉(或者在刚才转存时选择部分转存),这个是壳的代码段,我们是不需要的。保存后,再对这个文件修复IAT。修复后双击文件还是正常运行的。这次得到的文件尺寸和刚才相比变化不大,只是去掉了壳的代码(最好把他们去掉,因为这个段即没有用,而且又会让很多杀软兴奋的 ~~)。现在可以使用LoadPE的重建功能重建PE了。重建后大小优化89%,尺寸是3.7M,运行一切正常,杀软也不再误报了。
至此SVPK脱壳优化步骤完毕。关于进一步对文件尺寸和结构的优化问题这里就不多说了,大家有兴趣的可以深入研究。
kaien
2010/09/08
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)