虚拟机实现代码

虚拟机实现代码欢迎使用Markdown编辑器写博客本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦:Markdown和扩展Markdown简洁的语法代码块高亮图片链接和图片上传LaTex数学公式UML序列图和流程图离线写博客导入导出Markdown文件丰富的快捷键快捷键加粗Ctrl+B斜体Ctrl+I引用Ctrl

虚拟机实现代码"

!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;

// 直接调用read
read(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;

// 直接调用write
write(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中的一个字节赋值给r1
switch (*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;    

// 创建buffer
heap_buf = (char *) malloc(HEAP_SIZE_MAX);

// 初始化buffer
memcpy(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 processor
init_vm_proc(&proc);    

// execute target func
vm_interp(&proc);
return 0;

}

今天的文章虚拟机实现代码分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/32102.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注