vm86汇编指令脚本虚拟机
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
在 macosx 上编译
$ sudo brew install xmake $ xmake f -a i386 $ xmake
在 linux 上编译
$ git clone https://github.com/waruqi/xmake.git $ cd xmake $ sudo ./install $ $ cd vm86 $ xmake f -a i386 $ xmake
在 windows 上编译
下载 https://github.com/waruqi/xmake/archive/master.zip
解压运行里面的 install.bat 安装xmake后进行编译:
$ xmake
编译android版本
$ cd vm86 $ xmake f -p android --ndk=/xxx/ndk $ xmake
运行
运行测试程序:
$ xmake r demo
后话
最后,在项目的idc目录下,有两个脚本工具:export_function.idc 和 export_data.idc 可以用来辅助我们从ida中导出指定的汇编函数和数据
评论
