vm86匯編指令腳本虛擬機(jī)
x86匯編指令腳本虛擬機(jī)
簡介:
這是一個可以直接解釋執(zhí)行從ida pro里面提取出來的x86匯編代碼的虛擬機(jī)。
非常精簡,整體架構(gòu)上不能跟那些成熟的虛擬機(jī)相比,主要目標(biāo)是夠用、能用、輕量就行。
特性:
跨平臺運行支持,可以在windows、linux、macosx以及android, ios上運行x86的匯編代碼。。
支持常用x86匯編指令(例如,邏輯操作,跳轉(zhuǎn),循環(huán),調(diào)用,壓棧等指令)
支持函數(shù)間跳轉(zhuǎn),以及第三方api調(diào)用
支持參數(shù)傳入,以及運行結(jié)束后,返回值的獲取
虛擬機(jī)的運行粒度為單個函數(shù),函數(shù)間的跳轉(zhuǎn)可以通過多個虛擬機(jī)實例來完成(輕量的,性能影響不大)
支持線程安全
暫時不支持arm64,只能在32位下運行(有興趣的同學(xué)可以自行修改)
例子
我們先從ida中提取一段匯編代碼,這段匯編主要是printf庫函數(shù)打印外部傳入的數(shù)值
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來調(diào)用的話,就是"
sub_hello(31415926);
輸出結(jié)果:
hello: 31415926 hello: 31415926
接下來我們把這段匯編直接放到我們的虛擬機(jī)里面執(zhí)行:
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\
"
};
// 定義一個虛擬機(jī)
vm86_machine_ref_t machine = vm86_machine();
if (machine)
{
// 鎖定虛擬機(jī),保證線程安全(這個根據(jù)需要,可選)
tb_spinlock_ref_t lock = vm86_machine_lock(machine);
tb_spinlock_enter(lock);
// 獲取虛擬機(jī)的堆棧
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)
{
// 添加匯編里面需要調(diào)用到的外部庫函數(shù)
vm86_machine_function_set(machine, "printf", vm86_demo_proc_func_printf);
// 初始化調(diào)用參數(shù)
vm86_stack_push(stack, value);
// 執(zhí)行這個匯編代碼
vm86_proc_done(proc);
// 恢復(fù)堆棧,獲取返回值(這里是void的,傳null就行了)
vm86_stack_pop(stack, tb_null);
}
// 解鎖虛擬機(jī)
tb_spinlock_leave(lock);
}
}
int main(int argc, char** argv)
{
// 執(zhí)行這個匯編函數(shù):sub_hello(0x31415926)
vm86_demo_proc_exec_hello(0x31415926);
}
ok,那么輸出結(jié)果當(dāng)然也是:
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后進(jìn)行編譯:
$ xmake
編譯android版本
$ cd vm86 $ xmake f -p android --ndk=/xxx/ndk $ xmake
運行
運行測試程序:
$ xmake r demo
后話
最后,在項目的idc目錄下,有兩個腳本工具:export_function.idc 和 export_data.idc 可以用來輔助我們從ida中導(dǎo)出指定的匯編函數(shù)和數(shù)據(jù)
