Armadillo Strategic Code Splicing 手修经验小结
(本文以PassDiskProtect_C.exe为例)
一、为什么
首先,我想说,如果你只是为了脱壳。那你不需要继续看下去。
那为什么要修复这个呢?当你用IDA分析某个带有这种保护的脱壳文件的时候你就会非常想这样做,尤其是你选择使用HexRays功能的时候,当我们想对Main函数查看源代码的时候,我们就会得到一个错误,而无法查看。或者对代码段第一个过程查看源代码的时候,显示的结果会让你非常的失望。而修复了之后,一切都变得很完美。
二、我们需要什么
首先,你需要痛恨Arm的这项保护。因为像这种300K不到的程序,Arm改写了3000多处,意味着手动修复将花费你大量的时间。我现在大约可以300处/小时的样子,希望有编程高人据此文写出辅助工具,造福我们。
其次,你的文件必须起始于OEP处,不管他此时是在内存中还是在脱壳后的文件中。
再次,调整你的OD,将寄存器框缩小,堆栈框缩小。将内存框和代码框放到相似的大小。代码框定位到代码段的起始,内存框定位到被移走的代码区的起始,并调整为反汇编模式。
三、我们开始吧
具体过程没什么可说的,就是在内存框中找出每一句正确的代码,然后Shift-C,在代码框中正确的位置Shift-V。我们这里主要说下,怎么区分垃圾代码。
首先,可以确定的是,一切正确的代码都没有被变形。我猜测这是由于Arm采取的是客户端程序加密,由于目标程序的不可确定性,所以很多地方他不敢做的太过分。
第二,一切有关内存数据的读写操作语句都是正确的。
第三,一切mov reg1,reg2和xchg reg1,reg2语句在reg1=reg2的时候,都是垃圾语句。
第四,一切前面有对应的push reg语句的pop reg连同之间的语句全部是垃圾语句。没有对应的push reg/pop reg都是正确的。
第五,成对的语句及他们之间的语句都是垃圾语句,包括not reg;xchg reg1,reg2;bswap reg。
第六,一切的调转语句,除了调向程序代码段的,都是垃圾语句。
第七,Arm不会偷Call语句,相反,Call语句的上下合每个过程的开头和结束地点是最容易被偷的。
第八,Arm在偷过代码的地方使用Jmp Long 原句调转语句,再加上垃圾代码块,补足被偷的代码长度。所以,偷走的代码最少有5个字节,所以如果你看见一个单一的Jmp,再对应的块中发现了Push Imm32(Imm32>0x7f),mov reg,Imm32则被偷的必然是这一句,当然也可以是1*5,2+3,1+4之类的。还有一种情况是Jmp+nop的,这样则必然是6字节,因为Jmp占据5字节,剩余的字节用Nop无疑是最安全的。
第九、垃圾代码以块的方式存在,意味着一块的垃圾代码中不会有任何的正确代码。同样也意味着垃圾代码后面的远距调转可以跳向代码段中Jmp之后到正常代码之间的任何垃圾块的起始。
第十,被偷走的代码块中,JmpLong之前的语句貌似都是正确的(这个不敢确定,因为如果以后Arm在这边也插一点垃圾并不会影响程序的正确运行……)
文字就这么多了,我们来看些代码吧。
00521000 6A FF push -1 正确
00521002 87F3 xchg ebx, esi 对应
00521004 87F1 xchg ecx, esi
00521006 66:93 xchg ax, bx
00521008 67:E3 00 jcxz short 0052100B
0052100B 66:93 xchg ax, bx
0052100D 87F1 xchg ecx, esi
0052100F 7C 00 jl short 00521011
00521011 87F3 xchg ebx, esi 对应
00521013 68 78824200 push 00428278 正确
00521018 - E9 E8FFEDFF jmp 00401005
0052101D 50 push eax 正确
0052101E 8D4424 08 lea eax, dword ptr [esp+8] 正确
00521022 64:A3 00000000 mov dword ptr fs:[0], eax 正确
00521028 66:93 xchg ax, bx 对应
0052102A 50 push eax
0052102B 75 00 jnz short 0052102D
0052102D 58 pop eax
0052102E 8BF6 mov esi, esi
00521030 66:93 xchg ax, bx 对应
00521032 C74424 10 00000>mov dword ptr [esp+10], 0 正确
0052103A - E9 DCFFEDFF jmp 0040101B
00521159 6A 00 push 0 正确
0052115B 6A 03 push 3 正确
0052115D 6A 00 push 0 正确
0052115F 6A 02 push 2 正确
00521161 68 00000080 push 80000000 正确
00521166 87CB xchg ebx, ecx 对应
00521168 79 02 jns short 0052116C
0052116A 79 03 jns short 0052116F
0052116C 77 00 ja short 0052116E
0052116E 87CB xchg ebx, ecx
00521170 50 push eax
00521171 - E9 8AFFEDFF jmp 00401100
00521176 93 xchg eax, ebx
00521177 F7D2 not edx
00521179 66:87CB xchg bx, cx
0052117C 66:87CB xchg bx, cx
0052117F F7D2 not edx
00521181 8BDB mov ebx, ebx
00521183 93 xchg eax, ebx 对应
00521184 A3 1C6F4300 mov dword ptr [436F1C], eax 正确
00521189 0F95C0 setne al 正确
0052118C - E9 86FFEDFF jmp 00401117
00521328 97 xchg eax, edi 对应
00521329 78 00 js short 0052132B
0052132B 66:87D3 xchg bx, dx
0052132E 91 xchg eax, ecx
0052132F 87F1 xchg ecx, esi
00521331 0FCB bswap ebx
00521333 87C9 xchg ecx, ecx
00521335 0FCB bswap ebx
00521337 76 00 jbe short 00521339
00521339 87F1 xchg ecx, esi
0052133B 91 xchg eax, ecx
0052133C 66:87D3 xchg bx, dx
0052133F 97 xchg eax, edi 对应
00521340 68 81874200 push 00428781 正确
00521345 - E9 ADFFEDFF jmp 004012F7
00521374 50 push eax 对应
00521375 97 xchg eax, edi
00521376 66:87F2 xchg dx, si
00521379 97 xchg eax, edi
0052137A 66:87DB xchg bx, bx
0052137D 97 xchg eax, edi
0052137E 66:87F2 xchg dx, si
00521381 97 xchg eax, edi
00521382 58 pop eax 对应
00521383 899C24 E4000000 mov dword ptr [esp+E4], ebx 正确
0052138A - E9 A6FFEDFF jmp 00401335
00522C1A 66:92 xchg ax, dx 对应
00522C1C 0FCE bswap esi
00522C1E 0FCE bswap esi
00522C20 66:92 xchg ax, dx 对应
00522C22 8BDB mov ebx, ebx 注意!这句是垃圾语句
00522C24 68 B4CD4200 push 0042CDB4 正确
00522C29 8D4C24 24 lea ecx, dword ptr [esp+24] 正确
005260E8 FF75 0C push dword ptr [ebp+C] 正确
005260EB 8D45 F0 lea eax, dword ptr [ebp-10] 正确
005260EE 8BDB mov ebx, ebx 注意!这句是垃圾语句
005260F0 50 push eax 正确
005260F1 - E9 F752EEFF jmp 0040B3ED
例子就举这么多吧,差不多都能涵盖到了。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)