首页
社区
课程
招聘
[原创]VMProtect 简单分析1
发表于: 2007-9-12 21:30 16535

[原创]VMProtect 简单分析1

2007-9-12 21:30
16535

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期)

收藏
免费 7
支持
分享
最新回复 (7)
雪    币: 1946
活跃值: (248)
能力值: (RANK:330 )
在线值:
发帖
回帖
粉丝
2
很好,很强大。
Vmp 1.5Demo 不同于1.22的版本,它的构架比较简单,也没有代码变形,如果写unpacker,应该不会很困难,至少比1.22的简单。
Vmp的VM指令如你所说是由多条组成一条汇编语句的。
比如它会将
add eax,1234
变为
vpush 1234
vpush [ebp+EaxOffset]
vadd  [esp],[esp+4]
...

半自动的写了一段时间,累,乱。于是掉过头来根据VMP思想,实现了一下自己的虚拟机,寒~。
准备加到自己写的壳里面(写了很久的壳,还没写完)。


和我的经历一样,hehe.
虚拟机这类的文章比较少.加精鼓励下.期待你的1.5 unpacker
2007-9-13 01:21
0
雪    币: 282
活跃值: (31)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
这个Demo版的Unpacker没什么意义,也不准备写。
正式版的Unpacker理论上是可以写出来的,只要肯花时间。
但要成为全自动的比较难。
1。把所有的函数段和微指令对应起来。特定的VM手工对应就可以了,但即使是同一版本的VMP,生成的虚拟机应该也是不同的,命令流也是随机生成的加密算法,工具自动对应比较困难。
2。Unpacker必然要包含虚拟机各微指令加密算法,自动读入很难,稳定性也很难保证。所以我是手工加入程序中的,工作量不小。
3。定义宏就可以去掉大部分的无用指令,也可以将指令流恢复成CPU指令。
4。综上,写出来一个半自动的自用Unpacker是可行的,全自动的很难。等时间多了,再动手写。
写过一点代码。虽然是程序处理。但1,2步骤要自己做,3要一边分析一边加。工作量也不小,还达不到理想的实用价值。而且发现不同版本的VMP都有变化,就暂时没做了。
2007-9-13 09:11
0
雪    币: 226
活跃值: (15)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4
正版的话全自动修复可能有点困难,估计要使用编译原理优化技术了。
大部分人都是因为没时间写所以到现在都没有公开的工具。
哪位写出来,传给我的子孙吧。
2007-9-13 12:12
0
雪    币: 226
活跃值: (15)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
5
1。把所有的函数段和微指令对应起来。特定的VM手工对应就可以了,但即使是同一版本的VMP,生成的虚拟机应该也是不同的,命令流也是随机生成的加密算法,工具自动对应比较困难。
2。Unpacker必然要包含虚拟机各微指令加密算法,自动读入很难,稳定性也很难保证。所以我是手工加入程序中的,工作量不小。


如果仔细想想是可以搞定的,苦无时间啊。
2007-9-13 12:20
0
雪    币: 1919
活跃值: (901)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
6
支持哈,继续研究~~~
2007-9-13 13:34
0
雪    币: 716
活跃值: (162)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
7
烦琐,复杂,
2007-9-16 18:24
0
雪    币: 87
活跃值: (47)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
8
学习。顶。
以前看过,但没看懂,现在才懂一些。
2007-12-9 18:57
0
游客
登录 | 注册 方可回帖
返回
//