VMProtect系列保护的分析,还是需要动静结合,就这个低版本来说,我们测试被保护的代码很少,基本可以单独跟踪一遍,那就废话不说,我们把test.vmp.exe载入OllyDBG,然后找到testVMP的位置(可以根据前面记录下来的地址,也可以根据VC程序的特征来寻找testVMP函数),于是进入了VMProtect的核心流程,我贴出虚拟机的核心代码块:

这里是这个版本的虚拟机本身的代码了,总共30行左右的代码,VMProtect也是费心了,为了那一句 mov eax,1生生的加了这么多的代码,这段代码本身比较简单, 可以在OD里面单步跟踪下来,总体上就是:
- 压入两个常量(具体代码就是1、6两行), 使用这两个值计算出被虚拟的伪码的起始位置(esi)
- 从某一个内存地址开始(第8行)作为虚拟机运行过程中的私有堆栈和临时变量存放区域
- 引擎进入一个循环,这个循环从上面计算出来的esi的位置开始,不断的从esi中取出数据,执行虚拟逻辑
- 执行完所有的esi指向的伪码,退出虚拟机(退出到虚拟机之外,具体来说就是第一张图的第18行代码,return 0;)
上面提到的结果,只要是有些汇编功底的人,都可以比较容易的跟踪出上面的结果,那么为什么这样的一段30行的虚拟机代码就可以达到虚拟的目的了呢,要彻底明白这样的问题,还需要看下被VMProtect加壳虚拟之后,程序变成了什么样了。于是我们继续前面载入OllyDBG之后的流程,Alt+M 打开程序的内存视图,我们发现程序在原本的基础上增加了2个段:
- 地址=011EF000 大小=00005000 (20480.) 属主=test_vmp 01140000 区段=.vmp0 初始访问=RWE
地址=011F4000 大小=00005000 (20480.) 属主=test_vmp 01140000 区段=.vmp1 初始访问=RWE
- 先来看第2个段,0x11F4000 正是引擎代码的第8行,也就是说这个段的内存主要是用来给VMProtect运行时内存使用,如VM_Context
- 第一个段,0x11EF000的地址,根据前面的代码跟踪,我们发现,28行代码 lea edx,dword ptr ds:[eax*4+11EF10F]中,这个0x11EF10F就是VMProtect Handler数组啊, 那我们直接Ctrl+G跳转到0x11EF000这个段的最开头,查看汇编代码,看汇编形式,很容易认出来这些就是各个Handler的实现,这些一个个的小函数的代码一直持续到 0x11EF10F的位置未知,接下来的内存,就是一个函数指针数组,也称为跳转表,总共256项,为什么是256项呢,从26 27 28行可以知道,28行中的函数索引eax是 al 这个单字节扩展来的,最大是FF=255,加上0这一项,那总共最大就是256了,再接着往下,就到了我们看到的虚拟机引擎代码的位置了,接着的内存就是大量的伪码存放的位置了,为了直观,还是上一张图:

搞清楚了内存结构,再来理解一下虚拟机代码就简单一些了,通过跟踪流程,我们可以简单的归纳成一个上图色块部分之间的交互如下(大家俗称这个过程为dispatcher):
这就是最著名的VMProtect解码循环了