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 -->跳出
}