gravity552642 发表于 2014-11-7 11:31

Zprotect Vm代码的2种处理方法

Zp的VM比较简单,只模拟PUSH和JCC这2种类型指令,其他的全部都是明文保留,用乱序JMP连接.由于没有ANTI DUMP,所以可以补区段,把ZP的SHELL DLL所在区段以及后面的几个段一起补到DUMP+FIX IAT之后之后的程序中即可,包括VISO引擎处理过的代码也可以这样处理,一般脱壳这样也就可以了,如果被处理的代码中有我们感兴趣的地方,于是不得不寻求修复代码的方法.

由于我对VM一无所知,所以我将其当做代码变形来处理.

用DELPHI7编译个空窗体,用ZP1.49 VM掉第三个CALL
原代码如下:
0044B168 $ 55 push ebp
0044B169 . 8BEC mov ebp,esp
0044B16B . 51 push ecx
0044B16C . 53 push ebx
0044B16D . 56 push esi
0044B16E . 57 push edi



VM过后:
0044B168 /E9 9A5E0100 jmp 00461007 ; 00461007
0044B16D |CC int3
0044B16E |CC int3
0044B16F |CC int3
0044B170 |CC int3
0044B171 |CC int3
0044B172 |CC int3



原始地址指令用一个JMP代码 并用CC填充,然后通过一个PUSH/JMP 跳往VM主函数.
009D0E0A 9C pushfd
009D0E0B 83EC 3E sub esp,3E
009D0E0E 892424 mov dword ptr ss:,esp
009D0E11 894424 36 mov dword ptr ss:,eax
009D0E15 8B4424 42 mov eax,dword ptr ss:
009D0E19 894424 2E mov dword ptr ss:,eax
009D0E1D 8B4424 3E mov eax,dword ptr ss:
009D0E21 894424 0C mov dword ptr ss:,eax
009D0E25 894C24 26 mov dword ptr ss:,ecx
009D0E29 895424 3A mov dword ptr ss:,edx
009D0E2D 895C24 18 mov dword ptr ss:,ebx
009D0E31 896C24 08 mov dword ptr ss:,ebp
009D0E35 897424 14 mov dword ptr ss:,esi
009D0E39 897C24 10 mov dword ptr ss:,edi
009D0E3D 830424 46 add dword ptr ss:,46
009D0E41 54 push esp
009D0E42 E8 18FFFFFF call 009D0D5F ; 009D0D5F
009D0E47 C3 retn



这里原本是乱序过的 跟起来比较累,处理方法有2种,一是修改主程序,强迫它不变形;第二种是提取主程序中的功能DLL,这个DLL是裸体的,修改下重定位,把对应代码贴过来即可.
把VM主函数中的乱序代码修复过后,单步跟.

关键部分如下:
009D0BAB /75 29 jnz short 009D0BD6 ; 009D0BD6
009D0BAD |8B0D A4669D00 mov ecx,dword ptr ds: ; dumped_2.00A14258
009D0BB3 |03C1 add eax,ecx
009D0BB5 |56 push esi
009D0BB6 |8946 1C mov dword ptr ds:,eax
009D0BB9 |FF15 70669D00 call dword ptr ds: ; dumped_2.00A50744
009D0BBF |8B46 20 mov eax,dword ptr ds:
009D0BC2 |85C3 test ebx,eax
009D0BC4 |74 05 je short 009D0BCB ; 009D0BCB
009D0BC6 |23C5 and eax,ebp
009D0BC8 |8946 20 mov dword ptr ds:,eax
009D0BCB |807E 24 01 cmp byte ptr ds:,1
009D0BCF |74 15 je short 009D0BE6 ; 009D0BE6
009D0BD1 |8B46 20 mov eax,dword ptr ds:
009D0BD4 ^|EB D3 jmp short 009D0BA9 ; 009D0BA9



009D0BAB是模拟标志,如果需要模拟的代码处理完毕,这里就会跳转通过.009D0BB9这里的FF15指向的是一个分配流程,前文提到,壳只模拟2种指令,PUSH和JCC
通过
00A5A863 8BFF mov edi,edi
00A5A865 E9 7A210000 jmp 00A5C9E4 ; 00A5C9E4

连续4个mov edi,edi 分支判断是哪种指令,分别跳往各自的处理流程.

PUSH 流程
009D07FC 83F9 19 cmp ecx,19
009D07FF 7F 72 jg short 009D0873 ; 009D0873
009D0801 74 6C je short 009D086F ; 009D086F
009D0803 83F9 07 cmp ecx,7
009D0806 7F 3B jg short 009D0843 ; 009D0843
009D0808 74 34 je short 009D083E ; 009D083E
009D080A 49 dec ecx
009D080B 74 2C je short 009D0839 ; 009D0839
009D080D 49 dec ecx
009D080E 74 24 je short 009D0834 ; 009D0834
009D0810 49 dec ecx
009D0811 74 1C je short 009D082F ; 009D082F
009D0813 49 dec ecx
009D0814 74 14 je short 009D082A ; 009D082A
009D0816 49 dec ecx
009D0817 74 0C je short 009D0825 ; 009D0825
009D0819 49 dec ecx
009D081A 0F85 99000000 jnz 009D08B9 ; 009D08B9

ECX中对应的是寄存器类型参数,对应关系如下

eax 25
ecx 26
edx 27
ebx 28
esp 29
ebp 2a
esi 2b
edi 2c

如果PUSH 后面的操作数是常数则不执行此流程,直接在FF15后给出数值.

jcc流程:
009D08CF 55 push ebp
009D08D0 8BEC mov ebp,esp
009D08D2 8B45 0C mov eax,dword ptr ss:
009D08D5 3D DF000000 cmp eax,0DF
009D08DA 75 0F jnz short 009D08EB ; 009D08EB
009D08DC 8B45 08 mov eax,dword ptr ss:
009D08DF 0FB640 0D movzx eax,byte ptr ds:
009D08E3 C1E8 03 shr eax,3
009D08E6 83E0 01 and eax,1
009D08E9 5D pop ebp
009D08EA C3 retn
009D08EB 3D E0000000 cmp eax,0E0
009D08F0 75 0E jnz short 009D0900 ; 009D0900
009D08F2 8B45 08 mov eax,dword ptr ss:
009D08F5 0FB640 0D movzx eax,byte ptr ds:
009D08F9 C1E8 03 shr eax,3
009D08FC F7D0 not eax
009D08FE ^ EB E6 jmp short 009D08E6 ; 009D08E6
009D0900 3D E1000000 cmp eax,0E1
009D0905 75 09 jnz short 009D0910 ; 009D0910
009D0907 8B45 08 mov eax,dword ptr ss:
009D090A 0FB640 0C movzx eax,byte ptr ds:
009D090E ^ EB D6 jmp short 009D08E6 ; 009D08E6
009D0910 3D E2000000 cmp eax,0E2

EAX中对应的是JCC的类型参数,对应关系如下
jo DF
jno E0
jb E1
jnb E2
je E3
jnz E4
jbe E5
ja E6
js E7
jns E8
jpe E9
jpo EA
jl EB
jge EC
jle ED
jg EE

总共有10种类型JCC,我全部列出来了.紧接着通过
00A59957 85C0 test eax,eax

判断EAX是否为0 为0则跳转未实现.在修复的过程中可以强制其为0,这样方便跟踪下面的代码,记录一下跳转地址,在全部找到之后改改即可.

009D0BF8 8328 08 sub dword ptr ds:,8
009D0BFB 8B08 mov ecx,dword ptr ds:
009D0BFD FF70 04 push dword ptr ds:
009D0C00 8F41 04 pop dword ptr ds:
009D0C03 FF70 0C push dword ptr ds:
009D0C06 8F01 pop dword ptr ds:
009D0C08 FF30 push dword ptr ds:
009D0C0A FF70 10 push dword ptr ds:
009D0C0D FF70 14 push dword ptr ds:
009D0C10 FF70 08 push dword ptr ds:
009D0C13 FF70 18 push dword ptr ds:
009D0C16 FF70 3A push dword ptr ds:
009D0C19 FF70 26 push dword ptr ds:
009D0C1C FF70 36 push dword ptr ds:
009D0C1F 8B48 2A mov ecx,dword ptr ds:
009D0C22 C701 00000000 mov dword ptr ds:,0
009D0C28 58 pop eax
009D0C29 59 pop ecx
009D0C2A 5A pop edx
009D0C2B 5B pop ebx
009D0C2C 5D pop ebp
009D0C2D 5E pop esi
009D0C2E 5F pop edi
009D0C2F 5C pop esp
009D0C30 9D popfd
009D0C31 C3 retn



还原真实寄存器和堆栈,退出VM,返回未模拟的保留指令,当有PUSH或者JCC出现时,重新跳往VM.

由此可见,只需在VM_RETN以及分支判断处下断,就可以收集全部被VM的代码了.

懒惰的上帝 发表于 2014-11-7 11:35

感觉好神秘的东西

ww1113330 发表于 2014-11-7 11:54

感觉很高大尚,完全看不懂{:301_992:}

amscracker 发表于 2014-11-7 12:01

又是去复制别人的东西来当自己的脸

yyz219 发表于 2014-11-7 12:26

manbajie 发表于 2014-11-7 21:10

来看看都有啥方法

sdzzb 发表于 2014-11-7 21:31

感觉随便copy来的。。。小耗子

stereo2010 发表于 2014-11-8 06:17

小雨细无声 发表于 2014-11-8 21:54

现在不玩ZP了

lovesqzyl 发表于 2014-11-9 17:32

来看一看了 呵
页: [1]
查看完整版本: Zprotect Vm代码的2种处理方法