一
了解 Code Splicing
00401031 E9 CA 4F 0D 00 jmp loc_4D6000 ; WinMain函数头,Jmp后面的地址在脱壳后新加的区段,
00401031 sub_401031 endp ; 未脱壳的话是在壳程序申请的一段内存中,
00401031 ; 对付 Code Splicing 就要把这段代码拷贝到
00401031 ; 我们程序新开辟一个区段,然后将jmp后面的地址
00401031 ; 修改成我们的开辟的区段对应的地址中
00401036 loc_401036: ; CODE XREF: .spliced:loc_4D601F↓j
00401036 52 push edx ; 垃圾指令
00401037 5A pop edx ; 垃圾指令
00401038 E8 50 00 00 00 call sub_40108D
004D6000 loc_004D6000: ; CODE XREF: sub_401031↑j
004D6000 F7 D0 not eax ; 垃圾指令
004D6002 0F CF bswap edi ; 垃圾指令
004D6004 66 91 xchg ax, cx ; 垃圾指令
004D6006 7A 02 jp short loc_004D600A ; 垃圾指令
004D6008 7A 17 jp short near ptr loc_004D601F+2 ; 垃圾指令
004D600A
004D600A loc_004D600A: ; CODE XREF: 004D6006↑j
004D600A 0F CF bswap edi ; 垃圾指令
004D600C 0F CF bswap edi ; 垃圾指令
004D600E 7B 02 jnp short loc_004D6012 ; 垃圾指令
004D6010 7B 09 jnp short loc_004D601B ; 垃圾指令
004D6012
004D6012 loc_004D6012: ; CODE XREF: 004D600E↑j
004D6012 66 91 xchg ax, cx ; 垃圾指令
004D6014 0F CF bswap edi ; 垃圾指令
004D6016 F7 D0 not eax ; 垃圾指令
004D6018 55 push ebp ; 被偷走的正常指令
004D6019 8B EC mov ebp, esp ; 被偷走的正常指令
004D601B
004D601B loc_004D601B: ; CODE XREF: 004D6010↑j
004D601B 6A 00 push 0 ; 被偷走的正常指令
004D601D 6A 00 push 0 ; 被偷走的正常指令
004D601F
004D601F loc_004D601F: ; CODE XREF: 004D6008↑j
004D601F E9 12 B0 F2 FF jmp loc_401036 ; 跳回去
二
设置OD
三
寻找OEP
004E43B1 /72 29 jb short GameJack.004E43DC
004E43B3 |F3:A5 rep movs dword ptr es:[edi],dword ptr ds>
004E43B5 |FF2495 C8444E00 jmp dword ptr ds:[edx*4+0x4E44C8]
接着在代码段下F2断点,F9,这时候断在了00DF0338,
00DF0338 8B0C3A mov ecx,dword ptr ds:[edx+edi]
00DF033B 5B pop ebx ; GameJack.004E54D3
00DF033C 03D7 add edx,edi ; GameJack.00402000
00DF033E A1 A410E000 mov eax,dword ptr ds:[0xE010A4]
00DF0343 3148 58 xor dword ptr ds:[eax+0x58],ecx
00DF0346 A1 A410E000 mov eax,dword ptr ds:[0xE010A4]
00DF034B 3148 58 xor dword ptr ds:[eax+0x58],ecx
00DF034E A1 A410E000 mov eax,dword ptr ds:[0xE010A4]
00DF0353 8B16 mov edx,dword ptr ds:[esi]
00DF0355 8B48 74 mov ecx,dword ptr ds:[eax+0x74]
00DF0358 3348 6C xor ecx,dword ptr ds:[eax+0x6C]
00DF035B 3348 50 xor ecx,dword ptr ds:[eax+0x50]
00DF035E 030D BC10E000 add ecx,dword ptr ds:[0xE010BC] ; GameJack.00400000
00DF0364 85D2 test edx,edx
00DF0366 75 18 jnz short 00DF0380
00DF0368 8B50 70 mov edx,dword ptr ds:[eax+0x70]
00DF036B FF76 18 push dword ptr ds:[esi+0x18]
00DF036E 3350 6C xor edx,dword ptr ds:[eax+0x6C]
00DF0371 FF76 14 push dword ptr ds:[esi+0x14]
00DF0374 3350 04 xor edx,dword ptr ds:[eax+0x4]
00DF0377 FF76 10 push dword ptr ds:[esi+0x10]
00DF037A 2BCA sub ecx,edx
00DF037C FFD1 call ecx
四
修复IAT
00DECC4E 8B8D 68CAFFFF mov ecx,dword ptr ss:[ebp-0x3598]
00DECC54 8908 mov dword ptr ds:[eax],ecx
00DECC56 8B85 10D9FFFF mov eax,dword ptr ss:[ebp-0x26F0] ; GameJack.0047A000
00DECC54 8908 mov dword ptr ds:[eax],ecx
0047A000 77DAEAF4 advapi32.RegCreateKeyExA
0047A018 77DCD5BB advapi32.RegCreateKeyA
0047A71C 7C8137D9 kernel32.FindFirstFileA
0047A720 7C801E16 kernel32.TerminateProcess
0047A724 7C810B8E kernel32.SetFilePointer
0047A72C 7C8111DA kernel32.GetVersion
0047A754 7C801D4F kernel32.LoadLibraryExA
0047A764 7C82F7A0 kernel32.FormatMessageA
0047A76C 7C812F1D kernel32.GetCommandLineA
0047A778 7C80FE82 kernel32.GlobalUnlock
0047A77C 7C80FF19 kernel32.GlobalLock
0047A784 7C80FD2D kernel32.GlobalAlloc
0047A78C 7C810D87 kernel32.WriteFile
0047A790 7C80180E kernel32.ReadFile
0047A798 7C810A77 kernel32.GetFileSize
0047A7A0 7C809B47 kernel32.CloseHandle
0047A7A4 7C801A24 kernel32.CreateFileA
0047A7A8 7C80ABDE kernel32.FreeLibrary
0047A7AC 7C80ADA0 kernel32.GetProcAddress
0047A7B0 7C801D77 kernel32.LoadLibraryA
0047A7C4 7C809915 kernel32.GetACP
0047A7CC 7C81CDDA kernel32.ExitProcess
0047A7E4 7C80B6A1 kernel32.GetModuleHandleA
0047A7EC 7C80BE89 kernel32.FindResourceA
0047A7F4 7C80CC97 kernel32.SetHandleCount
0047A804 7C813093 kernel32.IsDebuggerPresent
0047A81C 7C81CE03 kernel32.TerminateThread
0047A874 7C80945C kernel32.CreateFileMappingA
0047A878 7C80B905 kernel32.MapViewOfFile
0047A87C 7C80B974 kernel32.UnmapViewOfFile
0047B6B0 77D3212B USER32.GetWindowTextA
0047B7F0 77D5058A USER32.MessageBoxA
00DECC54 8908 mov dword ptr ds:[eax],ecx ;往IAT某个项目写入
00DECC56 8B85 10D9FFFF mov eax,dword ptr ss:[ebp-0x26F0]
00DECC5C 83C0 04 add eax,0x4 ;计算出下一个需要写入的IAT
00DECC5F 8985 10D9FFFF mov dword ptr ss:[ebp-0x26F0],eax
00DECC65 ^ E9 4DFCFFFF jmp 00DEC8B7 ; 跳回起点解密下一个IAT
00DECA99 FF15 8863DF00 call dword ptr ds:[0xDF6388] ; msvcrt._stricmp 字符串比较函数,比较函数名是不是一样
00DECA9F 59 pop ecx
00DECAA0 59 pop ecx
00DECAA1 85C0 test eax,eax
00DECAA3 75 11 jnz short 00DECAB6 函数名相同则不跳
00DECAA5 8B85 58C2FFFF mov eax,dword ptr ss:[ebp-0x3DA8]
00DECAAB 8B40 08 mov eax,dword ptr ds:[eax+0x8]
00DECAAE 8985 68CAFFFF mov dword ptr ss:[ebp-0x3598],eax
00DECAB4 EB 02 jmp short 00DECAB8 运行到这原IAT将被替换
00DECAB6 ^ EB 9C jmp short 00DECA54 函数名不同则回循环
00DECAA3 75 11 jmp short 00DECAB6 ,是不是就可以还原IAT了,这时我们重新载入程序,在刚刚记住的这个地址0047A8C0下硬件写入断点HW 0047A8C0,F9运行,程序断下,接着F9运行,程序断下,这时程序刚好还原第一个IAT,这时我们将将00DECAA3 75 11 jnz short 00DECAB6 ,这个地址的代码改成 00DECAA3 EB 11 jmp short 00DECAB6 ,现在我们有个疑问代码是改了,但是我们不知道IAT什么时候全部被还原完了,根据壳的特性,代码执行前会先解密,执行完又会加密,我们就在00DECAA3 75 11 jmp short 00DECAB6,这个代码处,下个硬件写入断点HR 00DECAA3 ,F9运行,程序断在了00DC13C4这个地址。
00DC13C2 8B12 mov edx,dword ptr ds:[edx]
00DC13C4 8955 E4 mov dword ptr ss:[ebp-0x1C],edx
858B1175,这样就可以骗过壳的校验,同时我们还要把00DECAA3 EB 11 jmp short 00DECAB6 ,这个地址的代码改回 00DECAA3 75 11 jnz short 00DECAB6 ,删除所有断点,这时候我们按照前面找OEP的方法,在代码段下F2断点,F9运行,程序断下,单步到OEP,这时候我们再翻看IAT,可以看到没有被还原的统统被还原了,只是不同模块之前的分隔00000000,变成了别的地址,这个不影响程序运行,这个时候是不是忘了Code Splicing没有修复,这个先不着急,我们先按照正常脱壳流程走一边,先用ImportRec获取IAT表,再用LordPe Dump出来,再用ImportRec获取的IAT表,修复Dump出来的文件,最后用再用LordPe 重建PE。
OD上显示已终止,可以看到现在EIP是035CDBB4,通过堆栈回溯,找到这段代码!
00DEB833 E8 2EA00000 call 00DF5866 ; jmp 到 msvcrt.memcpy
01625514下个硬件写入断点HW 01625514,F9运行,现在EIP在00DEB613。
00F97950 0040299F 代码段jmpXXXXXXXX的位置
00F97954 038CD65D 代码段jmp后面的字节码
00F97958 03CD0009 内存中jmpXXXXXXXX的位置
00F9795C FC732996 内存中jmp后面的字节码
00F97960 004029C4 代码段jmpXXXXXXXX的位置
00F97964 038CD645 代码段jmp后面的字节码
00F97968 03CD003B 内存中jmpXXXXXXXX的位置
00F9796C FC732989 内存中jmp后面的字节码
.text:00DEB53C mov eax, [ebp-2A4Ch] ; 第一次取出表头地址00F97950 开始 一次循环 加 8个字节
.text:00DEB542 cmp dword ptr [eax], 0 ; 判断是否为0,为0就是结束的修改
.text:00DEB545 jz loc_DEB628
.text:00DEB54B mov eax, [ebp-2A4Ch]
.text:00DEB551 mov eax, [eax]
.text:00DEB553 mov [ebp-2A54h], eax
.text:00DEB559 mov eax, [ebp-2A4Ch]
.text:00DEB55F add eax, 4
.text:00DEB562 mov [ebp-2A4Ch], eax
.text:00DEB568 mov eax, [ebp-2A4Ch]
.text:00DEB56E mov eax, [eax]
.text:00DEB570 mov [ebp-2A50h], eax
.text:00DEB576 mov eax, [ebp-2A4Ch]
.text:00DEB57C add eax, 4
.text:00DEB57F mov [ebp-2A4Ch], eax
.text:00DEB585 mov eax, [ebp-27F4h] ; 取出400000
.text:00DEB58B add eax, [ebp-2A38h] ; 得到00402000
.text:00DEB591 cmp [ebp-2A54h], eax
.text:00DEB597 jbe short loc_DEB615 ; 取出第三项当做地址
.text:00DEB599 mov eax, [ebp-27F4h]
.text:00DEB59F add eax, [ebp-2A38h] ; 得到00402000
.text:00DEB5A5 add eax, [ebp-2A34h]
.text:00DEB5AB cmp [ebp-2A54h], eax
.text:00DEB5B1 jnb short loc_DEB615 ; 取出第三项当做地址
.text:00DEB5B3 mov eax, [ebp-27F4h]
.text:00DEB5B9 add eax, [ebp-2A38h]
.text:00DEB5BF mov ecx, [ebp-2A54h]
.text:00DEB5C5 sub ecx, eax ; 获取到的第一项的地址减去402000得到偏移地址
.text:00DEB5C7 mov [ebp-2A58h], ecx
.text:00DEB5CD mov al, byte_E0107C
.text:00DEB5D2 mov [ebp-55F8h], al
.text:00DEB5D8 movzx eax, byte ptr [ebp-55F8h]
.text:00DEB5DF test eax, eax
.text:00DEB5E1 jz short loc_DEB5FF ; eax等于 01600020
.text:00DEB5E3 mov eax, [ebp-2A50h]
.text:00DEB5E9 xor eax, [ebp-2A48h]
.text:00DEB5EF mov ecx, [ebp-2A30h]
.text:00DEB5F5 add ecx, [ebp-2A58h]
.text:00DEB5FB mov [ecx], eax
.text:00DEB5FD jmp short loc_DEB613
.text:00DEB5FF ; ---------------------------------------------------------------------------
.text:00DEB5FF
.text:00DEB5FF loc_DEB5FF: ; CODE XREF: sub_DEB53C+A5↑j
.text:00DEB5FF mov eax, [ebp-2A30h] ; eax等于 01600020
.text:00DEB605 add eax, [ebp-2A58h] ; 将偏移偏移再加上EAX得到要修改字节的地址
.text:00DEB60B mov ecx, [ebp-2A50h] ; 取出第二项的值当做字节码
.text:00DEB611 mov [eax], ecx ; 修改代码段jmp指令后面的地址的字节码
.text:00DEB613
.text:00DEB613 loc_DEB613: ; CODE XREF: sub_DEB53C+C1↑j
.text:00DEB613 jmp short loc_DEB623 ; 跳回继续循环修改
.text:00DEB615 ; ---------------------------------------------------------------------------
.text:00DEB615
.text:00DEB615 loc_DEB615: ; CODE XREF: sub_DEB53C+5B↑j
.text:00DEB615 ; sub_DEB53C+75↑j
.text:00DEB615 mov eax, [ebp-2A54h] ; 取出第三项当做地址
.text:00DEB61B mov ecx, [ebp-2A50h] ; 取出第四项当做字节码
.text:00DEB621 mov [eax], ecx ; 修改内存中jmp指令后面的地址的字节码
.text:00DEB623
.text:00DEB623 loc_DEB623: ; CODE XREF: sub_DEB53C:loc_DEB613↑j
.text:00DEB623 jmp sub_DEB53C ; 跳回继续循环修改
.text:00DEB628 ; ---------------------------------------------------------------------------
00DEA75F ^E9 C8FEFFFF jmp 00DEA62C
00DEA62C 8B85 4CD7FFFF mov eax,dword ptr ss:[ebp-0x28B4]
00F81014 000029C4 A的偏移地址 - 1
00F81018 0000000D D的偏移地址
00F8101C 0000003B C的偏移地址
00F81020 000029F6 A的偏移地址 - 1
00F81024 0000003F D的偏移地址
00F81028 00000052 C的偏移地址
.text:00DEA62C mov eax, [ebp-28B4h] ; 取出读取表的位置 和
.text:00DEA62C ; 表的结尾00f87944比较
.text:00DEA62C ; 到结尾就结束循环
.text:00DEA632 cmp eax, [ebp-28A0h]
.text:00DEA638 jnb loc_DEA764
.text:00DEA63E mov eax, [ebp-28B4h]
.text:00DEA644 mov eax, [eax] ; 第一项的偏移地址放到EAX
.text:00DEA646 mov [ebp-29D4h], eax ; 保存eax
.text:00DEA64C mov eax, [ebp-28B4h]
.text:00DEA652 add eax, 4
.text:00DEA655 mov [ebp-28B4h], eax
.text:00DEA65B mov eax, [ebp-28B4h]
.text:00DEA661 mov eax, [eax] ; 取出第二项的值放到EAX
.text:00DEA663 mov [ebp-29D8h], eax ; 保存
.text:00DEA669 mov eax, [ebp-28B4h]
.text:00DEA66F add eax, 4
.text:00DEA672 mov [ebp-28B4h], eax
.text:00DEA678 mov eax, [ebp-28B4h]
.text:00DEA67E mov eax, [eax] ; 取出第三项的值放到EAX
.text:00DEA680 mov [ebp-29D0h], eax
.text:00DEA686 mov eax, [ebp-28B4h]
.text:00DEA68C add eax, 4
.text:00DEA68F mov [ebp-28B4h], eax
.text:00DEA695 mov eax, lpAddress ; 关键,申请的内存基址
.text:00DEA69A add eax, [ebp-29D8h] ; 计算得到地址D
.text:00DEA6A0 mov ecx, [ebp-29D4h] ; 第一项的值放到ecx
.text:00DEA6A6 mov edx, [ebp-27F4h] ; 基址400000放到edx
.text:00DEA6AC lea ecx, [edx+ecx+4] ; 计算JMP指令后面的字节码1
.text:00DEA6B0 sub eax, ecx ; 计算JMP指令后面的字节码2
.text:00DEA6B2 mov [ebp-29CCh], eax ; 存放字节码
.text:00DEA6B8 mov eax, [ebp-27F4h] ; 基址400000放到eax
.text:00DEA6BE add eax, [ebp-29D4h] ; 计算得到地址A
.text:00DEA6C4 mov ecx, [ebp-28ACh] ; 得到表格数组的第一项目地址
.text:00DEA6CA mov [ecx], eax ; 第一项写入
.text:00DEA6CC mov eax, [ebp-28ACh]
.text:00DEA6D2 add eax, 4
.text:00DEA6D5 mov [ebp-28ACh], eax
.text:00DEA6DB mov eax, [ebp-28ACh]
.text:00DEA6E1 mov ecx, [ebp-29CCh]
.text:00DEA6E7 mov [eax], ecx ; 第二项写入
.text:00DEA6E9 mov eax, [ebp-28ACh]
.text:00DEA6EF add eax, 4
.text:00DEA6F2 mov [ebp-28ACh], eax
.text:00DEA6F8 mov eax, [ebp-29D4h] ; 得到jmp指令相对基址的偏移
.text:00DEA6FE mov ecx, [ebp-27F4h] ; 得到基址400000
.text:00DEA704 lea eax, [ecx+eax+4] ; 得到jmp指令下一句指令地址
.text:00DEA708 mov ecx, [ebp-29D0h]
.text:00DEA70E mov edx, lpAddress ; 关键,申请的内存基址
.text:00DEA714 lea ecx, [edx+ecx+4] ; 计算JMP指令后面的字节码1
.text:00DEA718 sub eax, ecx ; 计算JMP指令后面的字节码2
.text:00DEA71A mov [ebp-29CCh], eax ; 存放 结果
.text:00DEA720 mov eax, lpAddress ; 关键,申请的内存基址
.text:00DEA725 add eax, [ebp-29D0h]
.text:00DEA72B mov ecx, [ebp-28ACh]
.text:00DEA731 mov [ecx], eax ; 第三项写入
.text:00DEA733 mov eax, [ebp-28ACh]
.text:00DEA739 add eax, 4
.text:00DEA73C mov [ebp-28ACh], eax ; 存放第四项的地址
.text:00DEA742 mov eax, [ebp-28ACh]
.text:00DEA748 mov ecx, [ebp-29CCh]
.text:00DEA74E mov [eax], ecx ; 第四项写入
.text:00DEA750 mov eax, [ebp-28ACh]
.text:00DEA756 add eax, 4
.text:00DEA759 mov [ebp-28ACh], eax
.text:00DEA75F jmp loc_DEA62C ; 跳回循环
.text:00DEA764 ; ---------------------------------------------------------------------------
.text:00DEA764
.text:00DEA764 loc_DEA764: ; CODE XREF: sub_DE9ED4+764↑j
.text:00DEA764 mov eax, [ebp-28ACh]
.text:00DEA76A and dword ptr [eax], 0
.text:00DEA76D mov eax, [ebp-28ACh]
.text:00DEA773 add eax, 4
.text:00DEA776 mov [ebp-28ACh], eax
.text:00DEA77C call ds:GetTickCount
.text:00DEA782 sub eax, [ebp-28B0h]
.text:00DEA788 cmp eax, 0BB8h
.text:00DEA78D jbe short loc_DEA7C1 ; 时间反调试改为jmp,走过这条指令再改回来
00DEA78D /76 32 jbe short 00DEA7C1
00F97950 0040299F
00F97954 003D165D
00F97958 007D4009 这个地址现在还不存在
00F9795C FFC2E996
00DEB615 8B85 ACD5FFFF mov eax,dword ptr ss:[ebp-0x2A54]
00DEB61B 8B8D B0D5FFFF mov ecx,dword ptr ss:[ebp-0x2A50]
在刚刚申请的内存中这样改。
01690000 8B85 ACD5FFFF mov eax,dword ptr ss:[ebp-0x2A54] 还原刚才被覆盖的指令
01690006 2D 00407D00 sub eax,0x7D4000 减去区段基址得到偏移
0169000B 05 0000B903 add eax,0xAAA AAA为刚才记住的内存基址
01690010 - E9 06B675FF jmp 00DEB61B 跳回执行
01690015 90 nop
00DEB623 ^E9 14FFFFFF jmp 00DEB53C
00DEB628 6A 01 push 0x1
00DEB62A 58 pop eax ; 00E00A58
00DEB615 8B85 ACD5FFFF mov eax,dword ptr ss:[ebp-0x2A54]
看雪ID:学逆向混口饭
https://bbs.kanxue.com/user-home-1004848.htm
# 往期推荐
2、恶意木马历险记
球分享
球点赞
球在看
点击阅读原文查看更多
原文始发于微信公众号(看雪学苑):学习脱壳穿山甲Armadillo 4.30a 的详细笔记