x86彙編指令腳本虛擬機

簡介

這是一個能夠直接解釋執行從ida pro裏面提取出來的x86彙編代碼的虛擬機。linux

很是精簡,總體架構上不能跟那些成熟的虛擬機相比,主要目標是夠用、能用、輕量就行,若是以爲代碼架構設計的不是很好的話,也不用過於吐槽哈。。android

雖然我還有寫過兩個比較成熟的虛擬機項目(jvm和avm),雖然架構上比這個更完善,更容易擴展,功能也更強大ios

可是畢竟是給公司寫的,無法拿出來分享。。c++

背景

先說說,爲何要寫這個東西。。git

以前有段時間,我在用ida逆向分析某些程序的算法,而且要把它提取出來將其跨平臺運行,這個時候我首先考慮到是ida的F5插件github

畢竟這個能夠直接反成c/c++代碼,仍是很強大的,基本上98%的x86彙編代碼,我在經過f5還原成c/c++代碼後,都能正常運行。算法

本來我覺得能夠萬事大吉了,不過就在當我沾沾自喜的時候,發現其中某個彙編函數的c代碼,死活就是運行不正常,輸出結果不對。macos

並且那個函數恰恰代碼量出奇的大,光c代碼就有上萬行,並且裏面還對數據結構和明文都作了變換和加密,要是慢慢調試的話,得痛苦死。。哎。。windows

沒辦法,只好另想出路,既然ida還原c有時候不必定徹底準確,可是其彙編代碼的準確度仍是能夠保證的,而且從ida中提取的彙編代碼 基本上,不用怎麼改,就能編譯經過,所以,我先驗證了下直接編譯彙編代碼,運行看看結果對不對。。api

結果跟我想的同樣,是ok的。。那麼問題來了。。

既然彙編運行結果正常,那怎麼把它整成跨平臺運行呢,直接從編譯後x86的指令集進行模擬?工做量有點大,得不償失。。

有沒有取巧些辦法呢?固然有,那就是直接解析和運行源碼級的x86彙編代碼,至關於寫個輕量級的精簡版x86的腳本虛擬機,來把它運行起來。。

聽上去,貌似更麻煩了,其實因爲這裏只要可以跑通部分須要的彙編指令就好了,所以寫個精簡版的仍是很方便,不須要多少工做量

我前先後後,也就花了一個禮拜就搞定了,很是精簡,固然也不完善(也不必哈,不能跟那些大部頭相比)

個人目標就是夠用就行,所以我寫的差很少厚,就嘗試去加載以前有問題的彙編代碼,若是發現有指令沒實現,那就去實現它,直到跑通爲主。。

最後測試結果:

能夠正常跑通那個十幾萬行的彙編代碼,而且在arm下運行的性能還算ok,至少知足個人我的需求了。。: )

特性

  • 跨平臺運行支持,能夠在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
		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

若是用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 \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\ " }; // 定義一個虛擬機 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中導出指定的彙編函數和數據

 

http://www.tboox.org/cn/2016/07/26/x86-script-instruction-virtual-machine/

相關文章
相關標籤/搜索