小弟最近看了点vm   下面是一些心得体会  跟大家分享
通俗的讲 vm就是自己设计一套指令集  和一套解析这个虚拟指令集的引擎   把原本的386代码翻译成你自己的虚拟指令  然后调用你的虚拟引擎来执行这些虚拟指令。。。
这样说不知道合适不?   欢迎一起参与讨论
本文的目的是告诉大家虚拟机并不可怕    其实我们每个人都设计一套虚拟指令   这将是Cracker的噩梦。
这里感谢  jackozoo 版主提供的一个vm  CrackMe源码 作为我的参考资料
感谢 老罗的代码着色器

下面是最简单的一个vm例子  只虚拟了  push 和 call 指令

代码:
/*
    VM初探
    作者:blueapplez
    QQ:1242721xx
    Email:blueapple1987@163.com
    http://bbs.pediy.com/
*/

#include "stdafx.h"
#include "windows.h"

/* 下面是虚拟指令 我们只模拟了2条指令 */

//push 0x12345678  push一个4字节的数
#define vPushData    0x10

//call 0x12345678  call一个4字节的地址
#define vCall        0x12

//结束符
#define vEnd        0xff

//一个字符串
char *str = "Hello World";

/*
    这是我们构造的虚拟指令, 数据还不  在mian里面我们进行了修改
    push 0
    push 0
    push offset str  ;把字符串的地址入栈
    push 0
    call MessageBoxA ;
*/
BYTE bVmData[] = {    vPushData,    0x00, 0x00, 0x00,0x00, 
                    vPushData,    0x00, 0x00, 0x00,0x00,
                    vPushData,    0x00, 0x00, 0x00, 0x00,
                    vPushData,    0x00, 0x00, 0x00,0x00,
                    vCall,    0x00, 0x00, 0x00, 0x00,
                    vEnd};


//这就是简单的虚拟引擎了
_declspec(nakedvoid  VM(PVOID pvmData)
{
    __asm
    {
        //取vCode地址放入ecx
        mov ecx, dword ptr ss:[esp+4]
__vstart:
        //取第一个字节到al中
        mov al, byte ptr ds:[ecx]
        cmp al, vPushData
        je    __vPushData
        cmp al, vCall
        je    __vCall
        cmp al, vEnd
        je __vEnd
        int 3
__vPushData:
        inc ecx
        mov edx, dword ptr ds:[ecx]
        push edx
        add ecx, 4
        jmp __vstart
__vCall:
        inc ecx
        mov edx, dword ptr ds:[ecx]
        call edx
        add ecx, 4
        jmp __vstart
__vEnd:
        ret
    }
}


int main(int argc, char* argv[])
{
    //修改虚拟指令的数据
    *(DWORD *)(bVmData+10 + 1) = (DWORD)str;
    *(DWORD *)(bVmData+20 + 1) = (DWORD)MessageBoxA;
    
    //执行虚拟指令
    VM(bVmData);
    return 0;
}