VMProtect 简单分析1
前些时间简单分析过VMP,一直没有记笔记的习惯,也没有记下什么文档。
从论坛下了一个VMProtect 1.55 Demo下来,加密了记事本的入口,简单分析一下。
VMP强度很高,其原因在于自己实现了一系列微指令,将实际的CPU指令间接实现。而每个微指令自身都简单。由于CPU指令都由一套微指令实现,这样在微指令中下断点大部分是没有意义的,除了少部分,如退出VM微指令。这个版本在栈中分配了大小为0xC0的空间,用Ebp指向空间首地址。使用方法参考堆栈的使用。这样的用法避免早期版本申请固定大小空间,支持并发线程数量有限的缺点。VMP利用同一个堆栈进行操作,如果简单的看,大部分都是入栈,出栈操作。
废话少说,先分析几条指令。
(1)
01013106 66:8B45 00 mov ax, word ptr [ebp]
0101310A 66:8B55 02 mov dx, word ptr [ebp+2]
0101310E F6D0 not al
01013110 F6D2 not dl
01013112 83ED 02 sub ebp, 2
01013115 20D0 and al, dl
01013117 66:8945 04 mov word ptr [ebp+4], ax
0101311B 9C pushfd
0101311C 8F45 00 pop dword ptr [ebp]
这个实现的是 (Not8 A) And8 (Not8 B)
这个是一个非常重要的微指令。
带CPU开头的是现实的CPU指令
CPU_Not8 A = (Not8 A) And8 (Not8 A)
A CPU_And8 B = (Not8 (CPU_Not8 A)) And8 (Not8 (CPU_Not8 B))
A CPU_Or8 B = CPU_Not8 ( (CPU_Not8 A) And8 (CPU_Not8 B))
这样 CPU_Not32,CPU_Not16可以由CPU_Not8实现(还需要其他指令的支持)
这样 CPU_And32,CPU_And16,CPU_Or32,CPU_Or16就都可以实现了
这些指令配合组合,成为了大量无用指令的主力。
如 0 = ((CPU_Not EAX) OR (CPU_Not EAX)) CPU_AND EAX 这个用微指令实现的话,指令是很长的,而
且很难跳过。
(2)
010130DA 8B45 00 mov eax, dword ptr [ebp]
010130DD 8B55 04 mov edx, dword ptr [ebp+4]
010130E0 8A4D 08 mov cl, byte ptr [ebp+8]
010130E3 83C5 02 add ebp, 2
010130E6 0FA5D0 shld eax, edx, cl
010130E9 8945 04 mov dword ptr [ebp+4], eax
010130EC 9C pushfd
010130ED 8F45 00 pop dword ptr [ebp]
这个指令更重要,移位指令都是由他为基础实现的
举例,(实际要复杂一些,因为还要保证EFL的正确)
Shl EAX,cl shld EAX,0,cl
rol EAX,cl shld EAX,EAX,cl
因为CF参与循环,rcl指令实现的要复杂很多,不细说,反正都是可以实现的。在纸上演算就可以了。:
)
(3)比较简单的几条指令
16位加法,减法也是由加法实现的(-X) = Not (X) + 1,INC,DEC,NEG也就都实现了。
010130A3 66:8B45 00 mov ax, word ptr [ebp]
010130A7 83ED 02 sub ebp, 2
010130AA 66:0145 04 add word ptr [ebp+4], ax
010130AE 9C pushfd
010130AF 8F45 00 pop dword ptr [ebp]
还没有细看,8位加法和32位加法也是可以用16位加法实现的,可能这样实现的
伪寄存器入栈微指令 Edi指向Context
01013076 80E0 3C and al, 3C
01013079 8B1407 mov edx, dword ptr [edi+eax]
0101307C 83ED 04 sub ebp, 4
0101307F 8955 00 mov dword ptr [ebp], edx
存数据到内存变量
010130F5 8B45 00 mov eax, dword ptr [ebp]
010130F8 8B55 04 mov edx, dword ptr [ebp+4]
010130FB 83C5 08 add ebp, 8
010130FE 36:8910 mov dword ptr ss:[eax], edx
相当于可理解Push Esp
01013096 89E8 mov eax, ebp
01013098 83ED 04 sub ebp, 4
0101309B 8945 00 mov dword ptr [ebp], eax
通过Push Esp,来配合很多运算
Push Esp
Add [esp],xxx
LoadData 实现数据复制,对很多指令必不可少。
感觉Demo版少了很多指令集,代码的变形很少,虚拟命令也没有加密。即使这样强度也是很高的。
这些微指令组合起来,嵌套加入了大量无用指令。汗~
对VMP加密的几种建议处理办法
1.能放弃就放弃,等待工具出现。:)
2.Dump出来指令序列,在Switch的入口
01013058 8A06 mov al, byte ptr [esi]
0101305A 46 inc esi
0101305B 0FB6C0 movzx eax, al
0101305E FF2485 37310101 jmp dword ptr [eax*4+1013137]
跳转的地方可以加入修改指令,将指令序列和参数Dump出来,非Demo版也可以这样做。
然后去花,去花,去花。再恢复成原始CPU指令。
我还没有写出全自动的工具。全自动的比较难,因为加密代码、变形。使得确定微指令类型都有难度。
而且加密代码还需要提取出来。
半自动的写了一段时间,累,乱。于是掉过头来根据VMP思想,实现了一下自己的虚拟机,寒~。
准备加到自己写的壳里面(写了很久的壳,还没写完)。
以上分析如有错误,请指正。
一直不会写文章,写的不好,请大家海涵。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)