The x86 Script Instruction Virtual Machine

2016-07-26 ruki 更多博文 » 博客 » GitHub »

xmake x86 script assembly virtual

原文链接 https://waruqi.github.io/2016/07/26/x86-script-instruction-virtual-machine/
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


Introduction

This is a very simple and lightweight x86 virtual machine which can load and run the assembly code from ida pro directly.

Features

  • Supports cross-platform and it's able to run the x86 assembly code on linux, windows, maxosx, android and ios ...
  • Supports the frequently-used x86 assembly instruction (.e.g logical operations, goto, loop, call, stack operations ...)
  • Supports call the third-party library interfaces. (.e.g libc ..)
  • We can pass arguments and get the return results after running.
  • Supports thread-safe.
  • Does not support arm64 and only for 32-bits architecture

Example

We get one assemble code from ida pro first and this code will call the libc api: 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 
        dd offset loc_58A945    ; jump table for switch statement 

.code 
        ; hi
        push    ebp ;hello 
        mov ebp, esp 

    loc_6B2B50:             ; CODE XREF: sub_6B2B40+8
        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 

And we call it in c language first.

sub_hello(31415926);

The output results:

hello: 31415926
hello: 31415926

Nextly, we attempt to load this asm code using our x86 virtual machine.

static tb_void_t vm86_demo_proc_exec_hello(tb_uint32_t value)
{
    // the code
    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 \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\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\
    "
    };

    // the machine
    vm86_machine_ref_t machine = vm86_machine();
    if (machine)
    {
        // the lock
        tb_spinlock_ref_t lock = vm86_machine_lock(machine);

        // enter
        tb_spinlock_enter(lock);

        // the stack
        vm86_stack_ref_t stack = vm86_machine_stack(machine);

        // compile proc
        vm86_proc_ref_t proc = vm86_text_compile(vm86_machine_text(machine), s_code_sub_hello, sizeof(s_code_sub_hello));
        if (proc)
        {
            // add function
            vm86_machine_function_set(machine, "printf", vm86_demo_proc_func_printf);

            // init arguments
            vm86_stack_push(stack, value);

            // done proc
            vm86_proc_done(proc);

            // restore stack
            vm86_stack_pop(stack, tb_null);

            // trace
            tb_trace_i("sub_hello(%x)", value);
        }

        // leave
        tb_spinlock_leave(lock);
    } 
}

int main(int argc, char** argv)
{
    // call this function: sub_hello(0x31415926)
    vm86_demo_proc_exec_hello(0x31415926);    
}

The output results:

hello: 31415926
hello: 31415926

Source code

Compilation

Please install xmake first!

Compile project on macosx

$ sudo brew install xmake
$ xmake f -a i386
$ xmake

Compile project on linux

$ git clone https://github.com/waruqi/xmake.git
$ cd xmake
$ sudo ./install
$
$ cd vm86
$ xmake f -a i386
$ xmake

Compile project on windows

Downloads https://github.com/waruqi/xmake/archive/master.zip first.

Extracts it and run install.bat

Lastly, we start compiling vm86 project.

$ xmake

Compile project for android

$ cd vm86
$ xmake f -p android --ndk=/xxx/ndk
$ xmake

Running

$ xmake r demo

Ida scripts

The script files: export_function.idc and export_data.idc in the project directory (idc) can help us to export the given assembly function and data from the ida pro.