x86汇编指令脚本虚拟机
这是一个可以直接解释执行从ida pro里面提取出来的x86汇编代码的虚拟机。
非常精简,整体架构上不能跟那些成熟的虚拟机相比,主要目标是够用、能用、轻量就行。
跨平台运行支持,可以在windows、linux、macosx以及android, ios上运行x86的汇编代码。。
支持常用x86汇编指令(例如,逻辑操作,跳转,循环,调用,压栈等指令)
支持函数间跳转,以及第三方api调用
支持参数传入,以及运行结束后,返回值的获取
虚拟机的运行粒度为单个函数,函数间的跳转可以通过多个虚拟机实例来完成(轻量的,性能影响不大)
支持线程安全
暂时不支持arm64,只能在32位下运行(有兴趣的同学可以自行修改)
我们先从ida中提取一段汇编代码,这段汇编主要是printf库函数打印外部传入的数值
sub_hello proc near arg_0 = dword ptr 8 .data format db \"hello: %x\", 0ah, 0dh, 0 off_5A74B0 dd offset loc_6B2B50 ; DATA XREF: sub_589100+1832�r dd offset loc_58A945 ; jump table for switch statement .code ; hi push ebp ;hello mov ebp, esp loc_6B2B50: ; CODE XREF: sub_6B2B40+8�j push eax mov eax, [ebp+arg_0] push eax mov eax, offset format push eax call printf add esp, 4 pop eax mov ecx, 1 jmp ds:off_5A74B0[ecx*4] loc_58A945: push eax mov eax, [ebp+arg_0] push eax mov eax, offset format push eax call printf add esp, 4 pop eax end: mov esp, ebp pop ebp retn sub_hello endp
如果用c来调用的话,就是"
sub_hello(31415926);
输出结果:
hello: 31415926 hello: 31415926
接下来我们把这段汇编直接放到我们的虚拟机里面执行:
static tb_void_t vm86_demo_proc_exec_hello(tb_uint32_t value) { // 上述汇编代码的字符串表示 static tb_char_t const s_code_sub_hello[] = { "sub_hello proc near \n\ arg_0 = dword ptr 8 \n\ .data \n\ format db \"hello: %x\", 0ah, 0dh, 0 \n\ \n\ off_5A74B0 dd offset loc_6B2B50 ; DATA XREF: sub_589100+1832�r \n\ dd offset loc_58A945 ; jump table for switch statement \n\ \n\ .code \n\ ; hi\n\ push ebp ;hello \n\ mov ebp, esp \n\ \n\ loc_6B2B50: ; CODE XREF: sub_6B2B40+8�j\n\ push eax \n\ mov eax, [ebp+arg_0] \n\ push eax \n\ mov eax, offset format \n\ push eax \n\ call printf \n\ add esp, 4 \n\ pop eax \n\ \n\ mov ecx, 1\n\ jmp ds:off_5A74B0[ecx*4]\n\ \n\ loc_58A945:\n\ push eax \n\ mov eax, [ebp+arg_0] \n\ push eax \n\ mov eax, offset format \n\ push eax \n\ call printf \n\ add esp, 4 \n\ pop eax \n\ \n\ end:\n\ mov esp, ebp \n\ pop ebp \n\ retn \n\ sub_hello endp \n\ " }; // 定义一个虚拟机 vm86_machine_ref_t machine = vm86_machine(); if (machine) { // 锁定虚拟机,保证线程安全(这个根据需要,可选) tb_spinlock_ref_t lock = vm86_machine_lock(machine); tb_spinlock_enter(lock); // 获取虚拟机的堆栈 vm86_stack_ref_t stack = vm86_machine_stack(machine); // 编译上面的汇编代码,并生成一个过程对象的引用 vm86_proc_ref_t proc = vm86_text_compile(vm86_machine_text(machine), s_code_sub_hello, sizeof(s_code_sub_hello)); if (proc) { // 添加汇编里面需要调用到的外部库函数 vm86_machine_function_set(machine, "printf", vm86_demo_proc_func_printf); // 初始化调用参数 vm86_stack_push(stack, value); // 执行这个汇编代码 vm86_proc_done(proc); // 恢复堆栈,获取返回值(这里是void的,传null就行了) vm86_stack_pop(stack, tb_null); } // 解锁虚拟机 tb_spinlock_leave(lock); } } int main(int argc, char** argv) { // 执行这个汇编函数:sub_hello(0x31415926) vm86_demo_proc_exec_hello(0x31415926); }
ok,那么输出结果当然也是:
hello: 31415926 hello: 31415926
需要先安装xmake
$ sudo brew install xmake $ xmake f -a i386 $ xmake
$ git clone https://github.com/waruqi/xmake.git $ cd xmake $ sudo ./install $ $ cd vm86 $ xmake f -a i386 $ xmake
下载 https://github.com/waruqi/xmake/archive/master.zip
解压运行里面的 install.bat 安装xmake后进行编译:
$ xmake
$ cd vm86 $ xmake f -p android --ndk=/xxx/ndk $ xmake
运行测试程序:
$ xmake r demo
最后,在项目的idc目录下,有两个脚本工具:export_function.idc 和 export_data.idc 可以用来辅助我们从ida中导出指定的汇编函数和数据
花了两天时间,MyOS终于可以支持VM86了,这样以后就可以在保护模式下实现一些以前只能在实模式下实现的功能。 其实,按照我的预期,MyOS是不准备支持16位的程序的,所以刚开始也就不打算支持VM86模式。不过,为了在系统运行过程中可以随时修改系统的分辨率,所以现在还是加入了对VM86的支持。这样,系统就可以通过VM86来调用int 10h,通过VESA来设置显卡的工作模式。 以前,MyOS只能在
Oracle VM 概述 Oracle VM 是一个平台,它提供配备齐全的环境,其中包含虚拟化技术的所有最新优点。Oracle VM 允许您在受支持的虚拟化环境内部署操作系统和应用程序软件。Oracle VM 体系结构包括 Oracle VM Manager 和 Oracle VM Server。 Oracle VM Manager 用于管理 Oracle VM Server、虚拟机和资源。它由许
编译过内核的话,一般都会看到在根目录下有个文件vmlinux,这个就是通常所说的内核了。但是用了这么久,倒是从来没看过是怎么编译出来的。那今天我们就来探索一下。 那些七大姑八大姨们 一切的一切都是make读取makefile编译链接的,就好像孙悟空逃不出如来佛祖的手掌,vmlinux的出世也是在makefile的安排之下。那就现在看看makefile # SHELL used by kbuild
按照这个路径查找 C:\windows\system32\drivers vmx86.sys文件 ,重命名为别的任何你喜欢的名称,只要不叫wmx86就行,然后重启电脑。 开机后 然后在控制面板 找到卸载和更改程序 选中VMware 选择修复 ,修复完成 用管理员启动就ok了
修复VM tools无法安装问题 1.如果在安装VM的过程中出现windows安全等信息,大概率是少了补丁包,需要到下面这个网址下载安装 https://www.catalog.update.microsoft.com/search.aspx?q=kb4474419 (后面的kb4474419是编号,对应的是不同操作系统需要安装的补丁包,这个编号可以去百度搜索) windows 7 x86版本编号
转载于 https://book.2cto.com/201309/33426.html 构建vmlinux.bin的规则在arch/x86/boot目录下的Makefile中: /arch/x86/boot/Makefile: OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S $(obj)/vmlinux.bin: $(ob
伪指令 DW 定义字(2字节). PROC 定义过程. ENDP 过程结束. SEGMENT 定义段. ASSUME 建立段寄存器寻址. ENDS 段结束. END 程序结束.
串指令 DS:SI 源串段寄存器 :源串变址. ES:DI 目标串段寄存器:目标串变址. CX 重复次数计数器. AL/AX 扫描值. D标志 0表示重复操作中SI和DI应自动增量; 1表示应自动减量. Z标志 用来控制扫描或比较操作的结束. MOVS 串传送. ( MOVSB 传送字符. MOVSW 传送字. MOVSD 传送双字. ) CMPS 串比较. ( CMPSB 比较字符. CMPSW
算术运算指令 ADD 加法. ADC 带进位加法. INC 加 1. AAA 加法的ASCII码调整. DAA 加法的十进制调整. SUB 减法. SBB 带借位减法. DEC 减 1. NEC 求反(以 0 减之). CMP 比较.(两操作数作减法,仅修改标志位,不回送结果). AAS 减法的ASCII码调整. DAS 减法的十进制调整. MUL 无符号乘法. IMUL 整数乘法. 以上两条,结
数据传输指令 它们在存贮器和寄存器、寄存器和输入输出端口之间传送数据. 1. 通用数据传送指令. MOV 传送字或字节. MOVSX 先符号扩展,再传送. MOVZX 先零扩展,再传送. PUSH 把字压入堆栈. POP 把字弹出堆栈. PUSHA 把AX,CX,DX,BX,SP,BP,SI,DI依次压入堆栈. POPA 把DI,SI,BP,SP,BX,DX,CX,AX依次弹出堆栈. PUSHAD
逻辑运算指令 AND 与运算. OR 或运算. XOR 异或运算. NOT 取反. TEST 测试.(两操作数作与运算,仅修改标志位,不回送结果). SHL 逻辑左移. SAL 算术左移.(=SHL) SHR 逻辑右移. SAR 算术右移.(=SHR) ROL 循环左移. ROR 循环右移. RCL 通过进位的循环左移. RCR 通过进位的循环右移. 以上八种移位指令,其移位次数可达255次. 移
程序转移指令 1>无条件转移指令 (长转移) JMP 无条件转移指令 CALL 过程调用 RET/RETF过程返回. 2>条件转移指令 (短转移,-128到+127的距离内) ( 当且仅当(SF XOR OF)=1时,OP1循环控制指令(短转移) LOOP CX不为零时循环. LOOPE/LOOPZ CX不为零且标志Z=1时循环. LOOPNE/LOOPNZ CX不为零且标志Z=0时循环. JCX
9.5 条件汇编伪指令 条件汇编伪指令是告诉汇编程序:根据某种条件确定一组程序段是否加入到目标程序中。使用条件汇编伪指令的主要目的是:同一个源程序能根据不同的汇编条件生成不同功能的目标程序,增强宏定义的使用范围。 条件汇编伪指令与高级语言(如:C/C++)的条件编译语句在书写形式上相似,在所起作用方面是完全一致的。 9.5.1 条件汇编伪指令的功能 条件汇编伪指令的一般格式如下: IFnnnn 条
9.4.2 伪指令IRP 伪指令IRP的作用是用每个参数创建一组语句,其重复次数由伪指令后面参数表中参数的个数来确定。其一般使用格式如下: IRP 形式参数, <实参1, 实参2, ……, 实参n> 重复的语句组 ENDM 例9.11 把16位通用寄存器之值相加,并把结果存入寄存器AX。 解:由于16位通用寄存器名是一些不同的符号,不能用计数的方法来依次访问它们,所以,我们需要用伪指令IRP来实现