little vm 模型

用于逆向关键函数分析理解

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <io.h>

#define OPCODE_N 4
// 不同的虚拟机 操作码和操作函数不同 
typedef struct
{
    unsigned char opcode;  
    void (*handle)(void*);
}vm_opcode;  //对应操作码和响应的操作函数 

typedef struct
{
    unsigned long r1;    
    unsigned long r2;    
    unsigned long r3;    
    unsigned char *eip;    
    vm_opcode op_list[OPCODE_N];   
}vm_cpu;  //定义cpu的存储寄存器和eip存储器 

unsigned char vm_code[] = {  //操作码 + 对应栈偏移 
	//	stack[20] = flag 
	// write 
	0xf5,	
	//  mov r2,0x97  +6 --> 
	0xf1,0xe5,0x97,0x00,0x00,0x00,
	// mov  r1,stack[0]   +6  ---->    xor r1,(r1^r2)^0x12   +1  --->   xor stack[20],r1 
    0xf1,0xe1,0x0,0x00,0x00,0x00,0xf2,0xf1,0xe4,0x20,0x00,0x00,0x00,  
    0xf1,0xe1,0x1,0x00,0x00,0x00,0xf2,0xf1,0xe4,0x21,0x00,0x00,0x00,
    0xf1,0xe1,0x2,0x00,0x00,0x00,0xf2,0xf1,0xe4,0x22,0x00,0x00,0x00,
    0xf1,0xe1,0x3,0x00,0x00,0x00,0xf2,0xf1,0xe4,0x23,0x00,0x00,0x00,
    0xf1,0xe1,0x4,0x00,0x00,0x00,0xf2,0xf1,0xe4,0x24,0x00,0x00,0x00,
    0xf1,0xe1,0x5,0x00,0x00,0x00,0xf2,0xf1,0xe4,0x25,0x00,0x00,0x00,
    0xf1,0xe1,0x6,0x00,0x00,0x00,0xf2,0xf1,0xe4,0x26,0x00,0x00,0x00,
    0xf1,0xe1,0x7,0x00,0x00,0x00,0xf2,0xf1,0xe4,0x27,0x00,0x00,0x00,
    0xf1,0xe1,0x8,0x00,0x00,0x00,0xf2,0xf1,0xe4,0x28,0x00,0x00,0x00,
    0xf1,0xe1,0x9,0x00,0x00,0x00,0xf2,0xf1,0xe4,0x29,0x00,0x00,0x00,
    0xf1,0xe1,0xa,0x00,0x00,0x00,0xf2,0xf1,0xe4,0x2a,0x00,0x00,0x00,
    0xf1,0xe1,0xb,0x00,0x00,0x00,0xf2,0xf1,0xe4,0x2b,0x00,0x00,0x00,
	0xf9,
    0xf4
};

char data[15] = {0x1c,0x16,0x1b,0x1d,0x1,0x3f,0x4e,0x9,0x3,0x2c,0x17,0x7};    // 加密结果  &  加密算法 -->逆向 -->还原原来的值 
unsigned char flag[0x20]={0}; // 明文 
char *vm_stack;

void mov(vm_cpu *cpu);
void xor(vm_cpu *cpu);    //xor flag
void read_(vm_cpu *cpu);    
void write_(vm_cpu *cpu);

void *vm_init()  //虚拟机初始化函数 
{	
    vm_cpu *cpu = (vm_cpu*)malloc(sizeof(vm_cpu));  //初始化vvm_cpu寄存器 ,并指向要执行的opcode 
    cpu->r1 = 0;
    cpu->r2 = 0;
    cpu->r3 = 0;
    cpu->eip = (unsigned char *)vm_code;

    cpu->op_list[0].opcode = 0xf1;// 自定义操作码和操作函数绑定 
    cpu->op_list[0].handle = (void (*)(void *))mov;  // 自定义操作标号  mov-->opcode 
    cpu->op_list[1].opcode = 0xf2;
    cpu->op_list[1].handle = (void (*)(void *))xor;
    cpu->op_list[2].opcode = 0xf5;
    cpu->op_list[2].handle = (void (*)(void *))write_;
	cpu->op_list[3].opcode = 0xf9;
    cpu->op_list[3].handle = (void (*)(void *))read_;
 
    vm_stack = (char*)malloc(0x512);  // 写入op_list 初始化栈空间stack 
    memset(vm_stack,0,0x512);
	return (void*)cpu;

}



void vm_dispatcher(vm_cpu *cpu)  // vm分发器 ,解析opcode
{
    int i;
    for(i = 0; i < OPCODE_N; i++)
    {    
        if(*cpu->eip == cpu->op_list[i].opcode)// 与自定义操作码进行对比
        {
            cpu->op_list[i].handle(cpu);//  分发到相应的操作函数执行 
            break;
        }
    }
}
void vm_start(vm_cpu *cpu)  // vm执行函数 
{
    cpu->eip = (unsigned char*)vm_code;  
    while((*cpu->eip) != 0xf4)  //  读opcode 
    {
        vm_dispatcher(cpu);
    }
}

//1C 16 1B 1D 01 3F 4E 09 03 2C 17 07 02
//1C 16 1B 1D 01 3F 4E 09 03 2C 17 07 00  
int main()  
{
	printf("Please input:");
	gets((char*)flag);
	vm_cpu *cpu = (vm_cpu*)vm_init(); //初始化虚拟机  使vm_cpu的eip指向要执行的opcode 
	vm_start(cpu);
/*
	for(int i=0;flag[i];i++){
		if(i!=0 && i%10==0) putchar('\n');
		printf("0x%x,",flag[i]);
	}
	putchar('\n');
*/
	if(!strcmp(data,(char*)flag) )  // 执行虚拟机  将用户输入的flag与vm虚拟机计算的结果对比  判断正误  (看不见加密内容,) 
		printf("Right!\n");
	else
		printf("error!\n");

	putchar('\n');
	system("pause");
	return 0;
}




//cpu->r1 = (~(cpu->r1 ^ cpu->r2))^0x12
//cpu->r1=flag[i];
//cpu->r2=0x97;
void xor(vm_cpu *cpu)
{
    int temp;
    temp = ~(cpu->r1 ^ cpu->r2);  // 操作取反 
    temp ^= 0x12;
    cpu->r1 = temp;
    cpu->eip += 1;    // 指令寄存器+1 指向下一条指令 
}

void write_(vm_cpu *cpu)
{
    char *dest = vm_stack; // 栈操作 
    memcpy(dest,flag,0x20);    
    cpu->eip += 1;   
}

void read_(vm_cpu *cpu)
{
    char *dest = vm_stack;
    memcpy(flag,dest+0x20,0x20);    // 将加密后的结果覆盖到原来的flag 
    cpu->eip += 1;    
}

void mov(vm_cpu *cpu)
{
    unsigned char *res = cpu->eip + 1;    
    int *offset = (int *)(cpu->eip + 2);    
    unsigned char *dest = 0;
    dest = (unsigned char *)vm_stack;
 
    switch (*res) {  // 操作码后的内容 :偏移 
        case 0xe1:
            cpu->r1 = *(dest + *offset);  // offset 偏移量 
            break;   
 
        case 0xe2:
            cpu->r2 = *(dest + *offset); // 将栈上偏移offset的量取出给 r2 
            break;   
 
        case 0xe3:
            cpu->r3 = *(dest + *offset);
            break;   
        case 0xe4:
        {
            int x = cpu->r1;
            *(dest + *offset) = x;
            break;
 
        }
        case 0xe5:
            cpu->r2 = *offset;
            break;   
    }   
    
    cpu->eip += 6;  // mov操作占6字节 --> +6 -->跳出 
}

  

posted @ 2023-06-23 17:18  44556677  阅读(10)  评论(0)    收藏  举报