写一个虚拟机的模型

代码虚拟化:

我认为代码虚拟化是将native转换为字节码,但是字节码是不能被机器识别的,所以就需要有对应的解释器来解释他。因为字节码是我们定义的,所以一般的工具不能正确的识别它。就因为这样,虚拟机保护的代码比较难以识别破解,但是解释器一般情况下都是native 因为这样才能使解释器运行起来并解释字节码。

#define EXor 0x77//xor
#define ERetn 0xCC//retn
#define ECmp 0x78//cmp
#define EJnz 0x79//jnz
#define EJmp 0x80//jmp
#define EMov 0xC4//mov
#define ECall 0xEE//call
#define ERetn 0xFE//retn
#define EAdd 0xFF//add
#define ENot 0xEC//not
然后是虚拟寄存器的值(用来判断寄存器的)
因为数值可能被占用,所以我选的都是些不常用的。

#define VMyEax 0xF1//eax
#define VMyEcx 0xF2//ecx
#define VMyEdx 0xF3//edx
#define VMyEbx 0xF4//ebx
#define VMyEsp 0xF5//esp
#define VMyEbp 0xF6//ebp
#define VMyEsi 0xF7//esi
#define VMyEdi 0xF8//edi
#define VMyEip 0xF9//eip
然后定义虚拟寄存器(16位)
struct MyVM
{
        DWORD MyEax;
        DWORD MyEcx;
        DWORD MyEdx;
        DWORD MyEbx;
        DWORD MyEsp;
        DWORD MyEbp;
        DWORD MyEsi;
        DWORD MyEdi;
        DWORD MyEip;
        DWORD MyC;
        DWORD MyP;
        DWORD MyA;
        DWORD MyZ;
        DWORD MyS;
        DWORD MyT;
        DWORD MyD;
        DWORD MyO;
}MyVM={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
typedef struct MyVM *pMyEasyVM,MyEasyVM;
MyEasyVM VM;//初始化虚拟寄存器

除了这些以外,我还自定义了一个寄存器。。。
然后自己根据自定义的字节码写出一个小程序。
因为这字节码都是用数组存放的,所以call jmp jnz的偏移都用数组下标就可以了(为了方便起见)(call到API的话就不太适用了,你可以做记号来判断等等)
因为这只是一个模型,还有很多功能没有实现,谁让我技术太烂了。。以后我会补上的。
编译环境:XP下的VC++6.0
EasyVm.h
//
/* 字节码可以自己定义,只要用到的函数中的代号在指令集里!   */
/* 也可以自己添加哦                                         */
//
#include <stdio.h>
#include <windows.h>

/*/// 指令集 */
/
#define EXor 0x77//xor
#define ERetn 0xCC//retn
#define ECmp 0x78//cmp
#define EJnz 0x79//jnz
#define EJmp 0x80//jmp
#define EMov 0xC4//mov
#define ECall 0xEE//call
#define ERetn 0xFE//retn
#define EAdd 0xFF//add
#define ENot 0xEC//not
//输入信息
#define vm_read 0xEA//自定义函数
//输出信息
#define vm_write_err 0xCE//自定义函数
#define vm_write_success 0xCF//自定义函数

///
/*/// 虚拟寄存器值 /*/
/
#define VMyEax 0xF1//eax
#define VMyEcx 0xF2//ecx
#define VMyEdx 0xF3//edx
#define VMyEbx 0xF4//ebx
#define VMyEsp 0xF5//esp
#define VMyEbp 0xF6//ebp
#define VMyEsi 0xF7//esi
#define VMyEdi 0xF8//edi
#define VMyEip 0xF9//eip
#define VMyAddr 0xFA
/
struct MyVM
{
        DWORD MyEax;
        DWORD MyEcx;
        DWORD MyEdx;
        DWORD MyEbx;
        DWORD MyEsp;
        DWORD MyEbp;
        DWORD MyEsi;
        DWORD MyEdi;
        DWORD MyEip;
        DWORD MyAddr;//自定义的地址寄存器
        DWORD MyC;
        DWORD MyP;
        DWORD MyA;
        DWORD MyZ;
        DWORD MyS;
        DWORD MyT;
        DWORD MyD;
        DWORD MyO;
}MyVM={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
typedef struct MyVM *pMyEasyVM,MyEasyVM;
MyEasyVM VM;//初始化虚拟寄存器
/* 字节码 */
unsigned char MyCode[]={EMov,VMyEbx,89,vm_read,ECmp,VMyAddr,VMyEbx,EJnz,/*8*/11,vm_write_success,ERetn,vm_write_err,ERetn};//代码
int MyRead;//写进去的信息
/* 有时为了方便调试,会用到这些函数 */
void pEax()
{
        printf("eax=%xH\n",VM.MyEax);
}
void pEcx()
{
        printf("ecx=%xH\n",VM.MyEcx);
}
void pEdx()
{
        printf("edx=%xH\n",VM.MyEdx);
}
void pEbx()
{
        printf("ebx=%xH\n",VM.MyEbx);
}
void pEsp()
{
        printf("esp=%xH\n",VM.MyEsp);
}
void pEbp()
{
        printf("ebp=%xH\n",VM.MyEbp);
}
void pEsi()
{
        printf("esi=%xH\n",VM.MyEsi);
}
void pEdi()
{
        printf("edi=%xH\n",VM.MyEdi);
}
void pEip()
{
        printf("eip(指令执行处)=%xH(%u)\n",VM.MyEip,VM.MyEip);
}

void RunCode()
{
        int i,k=1;
        BOOL Jnz=FALSE,Jmp=FALSE,Call=FALSE,Retn=FALSE;
Run:
        for(i=VM.MyEip;i<sizeof(MyCode);i++)
        {
                if(MyCode[i]==vm_write_success)
                {
                        VM.MyEax=printf("ok\n");//返回值
                        VM.MyEip+=2;//这里在数组中占用一个字节
                }
                if(MyCode[i]==vm_write_err)
                {
                        VM.MyEax=printf("error!\n");//返回值
                        VM.MyEip+=2;//这里在数组中占用一个字节
                }
                if(MyCode[i]==vm_read)
                {
                        //输入信息
                        VM.MyEax=scanf("%d",&VM.MyAddr);//返回值
                        VM.MyEip+=2;//这里在数组中占用一个字节
                }
                if(MyCode[i]==EXor)
                {
                        int j;
                        DWORD MyArgc,argc1;
                        MyArgc=MyCode[i+1];
                        argc1=MyCode[i+2];
                        VM.MyEdx=MyArgc;
                        VM.MyEbx=argc1;
                        VM.MyEdx=VM.MyEdx^VM.MyEbx;
                        printf("xor %u,%u = %u\n",MyArgc,argc1,VM.MyEdx);
                        VM.MyEip+=4;
                }
                if(MyCode[i]==EAdd)
                {
                        int j;
                        DWORD MyArgc,argc1;
                        MyArgc=MyCode[i+1];
                        argc1=MyCode[i+2];
                        VM.MyEdx=MyArgc;
                        VM.MyEbx=argc1;
                        VM.MyEdx=VM.MyEdx+VM.MyEbx;
                        printf("add %u,%u = %u\n",MyArgc,argc1,VM.MyEdx);
                        VM.MyEip+=4;
                }
                if(MyCode[i]==ENot)
                {
                        int j;
                        DWORD MyArgc;
                        MyArgc=MyCode[i+1];
                        VM.MyEdx=MyArgc;
                        VM.MyEdx=~VM.MyEdx;
                        printf("not %u = %u\n",MyArgc,VM.MyEdx);
                        VM.MyEip+=3;
                }
                if(MyCode[i]==EMov)
                {
                        DWORD r,r1;
                        r=MyCode[i+1];
                        r1=MyCode[i+2];
                        /* 将值拷贝到虚拟寄存器中,原数据被覆盖 */
                        if(r==VMyEax)
                                VM.MyEax=r1;
                        if(r==VMyEcx)
                                VM.MyEcx=r1;
                        if(r==VMyEdx)
                                VM.MyEdx=r1;
                        if(r==VMyEbx)
                                VM.MyEbx=r1;
                        if(r==VMyEsp)
                                VM.MyEsp=r1;
                        if(r==VMyEbp)
                                VM.MyEbp=r1;
                        if(r==VMyEsi)
                                VM.MyEsi=r1;
                        if(r==VMyEdi)
                                VM.MyEdi=r1;
                        VM.MyEip+=4;
                }
                if(MyCode[i]==ECmp)
                {
                        DWORD r3,r4,r5,r6;
                        r3=MyCode[i+1];
                        r4=MyCode[i+2];
                        if(r3==VMyEax)
                                r5=VM.MyEax;
                        else if(r3==VMyEcx)
                                r5=VM.MyEcx;
                        else if(r3==VMyEdx)
                                r5=VM.MyEdx;
                        else if(r3==VMyEbx)
                                r5=VM.MyEbx;
                        else if(r3==VMyEsp)
                                r5=VM.MyEsp;
                        else if(r3==VMyEbp)
                                r5=VM.MyEbp;
                        else if(r3==VMyEsi)
                                r5=VM.MyEsi;
                        else if(r3==VMyEdi)
                                r5=VM.MyEdi;
                        else if(r3==VMyAddr)
                                r5=VM.MyAddr;
                        else
                                r5=r3;
                        if(r4==VMyEax)
                                r6=VM.MyEax;
                        else if(r4==VMyEcx)
                                r6=VM.MyEcx;
                        else if(r4==VMyEdx)
                                r6=VM.MyEdx;
                        else if(r4==VMyEbx)
                                r6=VM.MyEbx;
                        else if(r4==VMyEsp)
                                r6=VM.MyEsp;
                        else if(r4==VMyEbp)
                                r6=VM.MyEbp;
                        else if(r4==VMyEsi)
                                r6=VM.MyEsi;
                        else if(r4==VMyEdi)
                                r6=VM.MyEdi;
                        else if(r4==VMyAddr)
                                r6=VM.MyAddr;
                        else
                                r6=r4;
                        if(r6==r5)
                                VM.MyZ=0;
                        else
                                VM.MyZ=1;
                        VM.MyEip+=4;//Eip的值加4
                }
                if(MyCode[i]==EJnz)
                {
                        if(VM.MyZ==1)//读取标志位
                        {
                                int JnzAddress;
                                JnzAddress=MyCode[i+1];
                                VM.MyEip=JnzAddress;//从虚拟寄存器中的EIP指向处开始执行
                                Jnz=TRUE;
                                break;
                        }
                        else
                                VM.MyEip+=3;
                }
                if(MyCode[i]==EJmp)
                {
                        //直接跳转
                        int JmpAddress;
                        JmpAddress=MyCode[i+1];
                        VM.MyEip=JmpAddress;//从虚拟寄存器中的EIP指向处开始执行
                        Jmp=TRUE;
                        break;        
                }
                if(MyCode[i]==ECall)
                {
                        int CallAddress;
                        CallAddress=MyCode[i+1];
                        VM.MyEsp=i+2;//call返回地址
                        VM.MyEip=CallAddress;
                        Call=TRUE;
                        break;
                }
                if(MyCode[i]==ERetn)
                {
                        VM.MyEip=VM.MyEsp;
                        Retn=TRUE;
                        break;
                }
        }
        if(Jnz)
        {
                Jnz=FALSE;
                goto Run;
        }
        if(Jmp)
        {
                Jmp=FALSE;
                goto Run;
        }
        if(Call)
        {
                Call=FALSE;
                goto Run;
        }
        if(Retn)
        {
                if(VM.MyEsp<=0)
                        return;
                Retn=FALSE;
                k+=1;
                goto Run;
        }
}

EV.c

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "EasyVm.h"
#define pause system("pause")
int main(void)
{
        printf("Hello World\n");
        printf("Address:%xH\n",&MyCode);
        RunCode();
        pause;
        return 0;
}
这里的字节码是一个简单的CrackMe。注册成功的图片:

注册失败的图片:


虚拟机保护效果:
OD中查看:


如果在OD中查看字节码,并且不知道每个字节码的意思,不分析解释器的话,谁能看出这是什么意思呢?

因为这是字节码,机器不能识别,只有对应的解释器才能识别,一般的工具都是没有效果的!因为字节码是我们自己定义的。
动态调试:
也是一样,并不会被识别,因为处理器并不会理会这些字节码,理会这些字节码的只有我们的解释器!而且调试也是在调试解释器哦。其实我们还可以分析解释器,来分析字节码。不过解释器中的控制流会复杂很多,也能增加分析难度。
如果要爆破的话,把解释器中的jnz解释函数nop掉就行了,如果字节码有很多jnz的话。嘿嘿嘿嘿大笑 卵用~~~
刚刚我就nop掉了,结果破解成功了,不过我是依照OD搜索出来的EasyVm.h中的内容才破解出来的。
注意:如果写出这样的CM给别人破解的话,千万别原封不动的发出去哦~如果是我的话我就会给代码绕一大圈然后乱序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值