虚拟机实现代码

来源:互联网 发布:51单片机怎么烧程序 编辑:程序博客网 时间:2024/06/05 07:51

!c

include

include

include

define OPCODE_NUM 7 // opcode number

define HEAP_SIZE_MAX 1024

char *heap_buf; // vm heap

/*
* opcode enum
*/
enum OPCODES
{
MOV = 0xa0, // mov 指令字节码对应 0xa0
XOR = 0xa1, // xor 指令字节码对应 0xa1
CMP = 0xa2, // cmp 指令字节码对应 0xa2
RET = 0xa3, // ret 指令字节码对应 0xa3
SYS_READ = 0xa4, // read 系统调用字节码对应 0xa4
SYS_WRITE = 0xa5, // write 系统调用字节码对应 0xa5
JNZ = 0xa6 // jnz 指令字节码对应 0xa0
};

enum REGISTERS
{
R1 = 0x10,
R2 = 0x11,
R3 = 0x12,
R4 = 0x13,
EIP = 0x14,
FLAG = 0x15
};

/*
* opcode struct
*/
typedef struct opcode_t
{
unsigned char opcode; // 字节码
void (func)(void ); // 与字节码对应的处理函数
} vm_opcode;

/*
* virtual processor
*/
typedef struct processor_t
{
int r1; // 虚拟寄存器r1
int r2; // 虚拟寄存器r2
int r3; // 虚拟寄存器r3
int r4; // 虚拟寄存器r4

int flag; // 虚拟标志寄存器flag,作用类似于eflags    unsigned char *eip; // 虚拟机寄存器eip,指向正在解释的字节码地址    vm_opcode op_table[OPCODE_NUM]; // 字节码列表,存放了所有字节码与对应的处理函数    

} vm_processor;
xvm.c

!c

include “xvm.h”

void target_func()
{
asm volatile(“.byte 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x11, 0x12, 0x00, 0x00, 0x00, 0xa4, 0xa0, 0x14, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x11, 0x29, 0x00, 0x00, 0x00, 0xa1, 0xa2, 0x20, 0xa6, 0x5b, 0xa0, 0x14, 0x01, 0x00, 0x00, 0x00, 0xa1, 0xa2, 0x21, 0xa6, 0x50, 0xa0, 0x14, 0x02, 0x00, 0x00, 0x00, 0xa1, 0xa2, 0x22, 0xa6, 0x45, 0xa0, 0x14, 0x03, 0x00, 0x00, 0x00, 0xa1, 0xa2, 0x23, 0xa6, 0x3a, 0xa0, 0x14, 0x04, 0x00, 0x00, 0x00, 0xa1, 0xa2, 0x24, 0xa6, 0x2f, 0xa0, 0x14, 0x05, 0x00, 0x00, 0x00, 0xa1, 0xa2, 0x25, 0xa6, 0x24, 0xa0, 0x14, 0x06, 0x00, 0x00, 0x00, 0xa1, 0xa2, 0x26, 0xa6, 0x19, 0xa0, 0x14, 0x07, 0x00, 0x00, 0x00, 0xa1, 0xa2, 0x27, 0xa6, 0x0f, 0xa0, 0x10, 0x30, 0x00, 0x00, 0x00, 0xa0, 0x11, 0x09, 0x00, 0x00, 0x00, 0xa5, 0xa3, 0xa0, 0x10, 0x40, 0x00, 0x00, 0x00, 0xa0, 0x11, 0x07, 0x00, 0x00, 0x00, 0xa5, 0xa3”);

/*    mov r1, 0x00000000    mov r2, 0x12    call vm_read    ; 输入        mov r1, input[0]    mov r2, 0x29    xor r1, r2      ; 异或    cmp r1, flag[0] ; 比较    jnz ERROR       ; 如果不相同就跳转到输出错误的代码        ; 同上    mov r1, input[1]    xor r1, r2    cmp r1, flag[1]    jnz ERROR        mov r1, input[2]    xor r1, r2    cmp r1, flag[2]    jnz ERROR        mov r1, input[3]    xor r1, r2    cmp r1, flag[3]    jnz ERROR        mov r1, input[4]    xor r1, r2    cmp r1, flag[4]    jnz ERROR        mov r1, input[5]    xor r1, r2    cmp r1, flag[5]    jnz ERROR        mov r1, input[6]    xor r1, r2    cmp r1, flag[6]    jnz ERROR        mov r1, input[7]    xor r1, r2    cmp r1, flag[7]    jnz ERROR*/

}

/*
* xor 指令解释函数
*/
void vm_xor(vm_processor *proc)
{
// 异或的两个数据分别存放在r1,r2寄存器中
int arg1 = proc->r1;
int arg2 = proc->r2;

// 异或结果存在r1中proc->r1 = arg1 ^ arg2;    // xor指令只占一个字节,所以解释后,eip向后移动一个字节proc->eip += 1;

}

/*
* cmp 指令解释函数
*/
void vm_cmp(vm_processor *proc)
{
// 比较的两个数据分别存放在r1和buffer中
int arg1 = proc->r1;、
// 字节码中包含了buffer的偏移
char arg2 = (proc->eip + 1) + heap_buf;

// 比较并对flag寄存器置位,1为相等,0为不等if (arg1 == *arg2) {    proc->flag = 1;} else {    proc->flag = 0;}    // cmp指令占两个字节,eip向后移动2个字节proc->eip += 2;

}

/*
* jnz 指令解释函数
*/
void vm_jnz(vm_processor *proc)
{
// 获取字节码中需要的地址相距eip当前地址的偏移
unsigned char arg1 = *(proc->eip + 1);

// 通过比较flag的值来判断之前指令的结果,如果flag为零说明之前指令不想等,jnz跳转实现if (proc->flag == 0) {    // 跳转可以直接修改eip,偏移就是上面获取到的偏移    proc->eip += arg1;} else {    proc->flag = 0;}    // jnz 指令占2个字节,所以eip向后移动两个字节proc->eip += 2;

}

/*
* ret 指令解释函数
*/
void vm_ret(vm_processor *proc)
{

}

/*
* read 系统调用解释函数
*/
void vm_read(vm_processor *proc)
{
// read系统调用有两个参数,分别存放在r1,r2寄存器中,r1中是保存读入数据的buf的偏移,r2为希望读入的长度
char *arg2 = heap_buf + proc->r1;
int arg3 = proc->r2;

// 直接调用readread(0, arg2, arg3);    // read系统调用占1个字节,所以eip向后移动1个字节proc->eip += 1;

}

/*
* write 系统调用解释函数
*/
void vm_write(vm_processor *proc)
{
// 与read系统调用相同,r1中是保存写出数据的buf的偏移,r2为希望写出的长度
char *arg2 = heap_buf + proc->r1;
int arg3 = proc->r2;

// 直接调用writewrite(1, arg2, arg3);    // write系统调用占1个字节,所以eip向后移动1个字节proc->eip += 1;

}

/*
* mov 指令解释函数
*/
void vm_mov(vm_processor *proc)
{
// mov 指令两个参数都隐含在字节码中了,指令标识后的第一个字节是寄存器的标识,指令标识后的第二到第五个字节是要mov的立即数,目前只实现了mov一个立即数到一个寄存器中和mov一个buffer中的内容到一个r1寄存器
unsigned char *dest = proc->eip + 1;
int src = (int ) (proc->eip + 2);

// 前4个case分别对应r1~r4,最后一个case中,*src保存的是buffer的一个偏移,实现了把buffer中的一个字节赋值给r1switch (*dest) {    case 0x10:        proc->r1 = *src;        break;        case 0x11:        proc->r2 = *src;        break;        case 0x12:        proc->r3 = *src;        break;        case 0x13:        proc->r4 = *src;        break;        case 0x14:        proc->r1 = *(heap_buf + *src);        break;}    // mov指令占6个字节,所以eip向后移动6个字节proc->eip += 6;

}

/*
* 执行字节码
*/
void exec_opcode(vm_processor *proc)
{
int flag = 0;
int i = 0;

// 查找eip指向的正在解释的字节码对应的处理函数while (!flag && i < OPCODE_NUM) {    if (*proc->eip == proc->op_table[i].opcode) {        flag = 1;        // 查找到之后,调用本条指令的处理函数,由处理函数来解释        proc->op_table[i].func((void *) proc);    } else {        i++;    }}    

}

/*
* 虚拟机的解释器
*/
void vm_interp(vm_processor *proc)
{
/* eip指向被保护代码的第一个字节
* target_func + 4是为了跳过编译器生成的函数入口的代码
*/
proc->eip = (unsigned char *) target_func + 4;

// 循环判断eip指向的字节码是否为返回指令,如果不是就调用exec_opcode来解释执行while (*proc->eip != RET) {    exec_opcode(proc);}

}

/*
* 初始化虚拟机处理器
*/
void init_vm_proc(vm_processor *proc)
{
proc->r1 = 0;
proc->r2 = 0;
proc->r3 = 0;
proc->r4 = 0;
proc->flag = 0;

// 把指令字节码与解释函数关联起来proc->op_table[0].opcode = MOV;proc->op_table[0].func = (void (*)(void *)) vm_mov;    proc->op_table[1].opcode = XOR;proc->op_table[1].func = (void (*)(void *)) vm_xor;    proc->op_table[2].opcode = CMP;proc->op_table[2].func = (void (*)(void *)) vm_cmp;    proc->op_table[3].opcode = SYS_READ;proc->op_table[3].func = (void (*)(void *)) vm_read;    proc->op_table[4].opcode = SYS_WRITE;proc->op_table[4].func = (void (*)(void *)) vm_write;    proc->op_table[5].opcode = RET;proc->op_table[5].func = (void (*)(void *)) vm_ret;    proc->op_table[6].opcode = JNZ;proc->op_table[6].func = (void (*)(void *)) vm_jnz;    // 创建bufferheap_buf = (char *) malloc(HEAP_SIZE_MAX);// 初始化buffermemcpy(heap_buf + 0x20, "syclover", 8);memcpy(heap_buf + 0x30, "success!n", 9);memcpy(heap_buf + 0x40, "error!n", 7);

}

// flag: ZPJEF_L[
int main()
{
vm_processor proc = {0};

// initial vm processorinit_vm_proc(&proc);    // execute target funcvm_interp(&proc);return 0;

}

0 0