跳转至

Unicorn Engine

什麼是Unicorn引擎

Unicorn是一個輕量級, 多平臺, 多架構的CPU模擬器框架. 我們可以更好地關注CPU操作, 忽略機器設備的差異. 想象一下, 我們可以將其應用於這些情景: 比如我們單純只是需要模擬代碼的執行而非需要一個真的CPU去完成那些操作, 又或者想要更安全地分析惡意代碼, 檢測病毒特徵, 或者想要在逆向過程中驗證某些代碼的含義. 使用CPU模擬器可以很好地幫助我們提供便捷.

它的亮點(這也歸功於Unicorn是基於qemu而開發的)有:

  • 支持多種架構: Arm, Arm64 (Armv8), M68K, Mips, Sparc, & X86 (include X86_64).
  • 對Windows和nix系統(已確認包含Mac OSX, Linux, BSD & Solaris)的原生支持
  • 具有平臺獨立且簡潔易於使用的API
  • 使用JIT編譯技術, 性能表現優異

你可以在Black Hat USA 2015獲悉有關Unicorn引擎的更多技術細節. Github項目主頁: unicorn

儘管它不同尋常, 但它無法模擬整個程序或系統, 也不支持系統調用. 你需要手動映射內存並寫入數據進去, 隨後你才能從指定地址開始模擬.

應用的情景

什麼時候能夠用到Unicorn引擎呢?

  • 你可以調用惡意軟件中一些有趣的函數, 而不用創建一個有害的進程.
  • 用於CTF競賽
  • 用於模糊測試
  • 用於gdb插件, 基於代碼模擬執行的插件
  • 模擬執行一些混淆代碼

如何安裝

安裝Unicorn最簡單的方式就是使用pip安裝, 只要在命令行中運行以下命令即可(這是適合於喜愛用python的用戶的安裝方法, 對於那些想要使用C的用戶, 則需要去官網查看文檔編譯源碼包):

pip install unicorn

但如果你想用源代碼進行本地編譯的話, 你需要在下載頁面中下載源代碼包, 然後可以按照以下命令執行:

  • *nix 平臺用戶
$ cd bindings/python
$ sudo make install
  • Windows平臺用戶
cd bindings/python
python setup.py install

對於Windows, 在執行完上述命令後, 還需要將下載頁面的Windows core engine的所有dll文件複製到C:\locationtopython\Lib\site-packages\unicorn位置處.

使用unicorn的快速指南

我們將會展示如何使用python調用unicorn的api以及它是如何輕易地模擬二進制代碼. 當然這裏用的api僅是一小部分, 但對於入門已經足夠了.

 1 from __future__ import print_function
 2 from unicorn import *
 3 from unicorn.x86_const import *
 4 
 5 # code to be emulated
 6 X86_CODE32 = b"\x41\x4a" # INC ecx; DEC edx
 7 
 8 # memory address where emulation starts
 9 ADDRESS = 0x1000000
10 
11 print("Emulate i386 code")
12 try:
13     # Initialize emulator in X86-32bit mode
14     mu = Uc(UC_ARCH_X86, UC_MODE_32)
15 
16     # map 2MB memory for this emulation
17     mu.mem_map(ADDRESS, 2 * 1024 * 1024)
18 
19     # write machine code to be emulated to memory
20     mu.mem_write(ADDRESS, X86_CODE32)
21 
22     # initialize machine registers
23     mu.reg_write(UC_X86_REG_ECX, 0x1234)
24     mu.reg_write(UC_X86_REG_EDX, 0x7890)
25 
26     # emulate code in infinite time & unlimited instructions
27     mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32))
28 
29     # now print out some registers
30     print("Emulation done. Below is the CPU context")
31 
32     r_ecx = mu.reg_read(UC_X86_REG_ECX)
33     r_edx = mu.reg_read(UC_X86_REG_EDX)
34     print(">>> ECX = 0x%x" %r_ecx)
35     print(">>> EDX = 0x%x" %r_edx)
36 
37 except UcError as e:
38     print("ERROR: %s" % e)

運行結果如下:

$ python test1.py 
Emulate i386 code
Emulation done. Below is the CPU context
>>> ECX = 0x1235
>>> EDX = 0x788f

樣例裏的註釋已經非常直觀, 但我們還是對每一行代碼做出解釋:

  • 行號2~3: 在使用Unicorn前導入unicorn模塊. 樣例中使用了一些x86寄存器常量, 所以也需要導入unicorn.x86_const模塊

  • 行號6: 這是我們需要模擬的二進制機器碼, 使用十六進製表示, 代表的彙編指令是: "INC ecx" 和 "DEC edx".

  • 行號9: 我們將模擬執行上述指令的所在虛擬地址

  • 行號14: 使用Uc類初始化Unicorn, 該類接受2個參數: 硬件架構和硬件位數(模式). 在樣例中我們需要模擬執行x86架構的32位代碼, 我 們使用變量mu來接受返回值.

  • 行號17: 使用mem_map方法根據在行號9處聲明的地址, 映射2MB用於模擬執行的內存空間. 所有進程中的CPU操作都應該只訪問該內存區域. 映射的內存具有默認的讀,寫和執行權限.

  • 行號20: 將需要模擬執行的代碼寫入我們剛剛映射的內存中. mem_write方法接受2個參數: 要寫入的內存地址和需要寫入內存的代碼.

  • 行號23~24: 使用reg_write方法設置ECXEDX寄存器的值

  • 行號27: 使用emu_start方法開始模擬執行, 該API接受4個參數: 要模擬執行的代碼地址, 模擬執行停止的內存地址(這裏是 X86_CODE32的最後1字節處), 模擬執行的時間和需要執行的指令數目. 如果我們像樣例一樣忽略後兩個參數, Unicorn將會默認以無窮時間和無窮指令數目的條件來模擬執行代碼.

  • 行號32~35: 打印輸出ECXEDX寄存器的值. 我們使用函數reg_read來讀取寄存器的值.

要想查看更多的python示例, 可以查看文件夾bindings/python下的代碼. 而C的示例則可以查看sample文件夾下的代碼.

參考鏈接