一、簡介
libemu是一款用C語言實現的基於x86的shellcode檢測的庫。
它可以支援:
1、解析x86指令、寄存器類比、FPU類比
2、靜態分析、動態分析、Win32API hook
使用libemu你可以:
1、判斷一段字串是不是shellcode
2、可以用libemu得到指令執行流程圖(類似於IDA等調試工具)
libemu可以被用於IDS、蜜罐等安全產品中
二、使用
下面是一個使用libemu的例子
/*libemu test*/#include <emu/emu.h>#include <emu/emu_shellcode.h>#include <emu/emu_memory.h>struct emu *emu;char shellcode[] = "\xbe\x1f\x5e\x89\x76\x09\x31\xc0\x88\x46\x08\x89\x46\x0d\xb0\x0b" "\x89\xf3\x8d\x4e\x09\x8d\x56\x0d\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff\x2f\x62\x69\x6e\x2f\x6c\x73\x00\xc9\xc3"; int main(){emu = emu_new();if ( emu_shellcode_test(emu, (uint8_t *)shellcode, 48) >= 0 ) { fprintf(stderr, "suspecting shellcode\n"); }emu_free(emu);return 0;}
在上例中,執行過程中會列印 suspecting shellcode,表示這個是一段可以字串,而實際上這段字串是linux下的shellcode,完成的功能是在當前路徑下執行“/bin/ls”。
三、實現原理
libemu是基於對x86組合語言的解析和類比執行。和Bochs、qemu不同的是libemu只是模擬器,不是虛擬機器。只能完成對記憶體和CPU的簡單類比,不能完全類比執行。
3.1 一個基本假設
libemu的一個基本假設是,如果字串是一段shellcode,那麼其中一定包含”call”(0xe8)或者“fnstenv”(0xd9)指令(GetPC code)。
這裡邊涉及到shellcode的編寫技巧,在shellcode的編寫一般都要進行地址定位,而地址定位就很難繞過call/ret或者類fnstenv的浮點數指令。比如說:
一個例子:
jmp 0x2a popl %esi movl %esi,0x9(%esi) movb $0x0,0x8(%esi) movl $0x0,0xd(%esi) movl $0xb,%eax movl %esi,%ebx leal 0x9(%esi),%ecx leal 0xd(%esi),%edx int $0x80 movl $0x1, %eax movl $0x0, %ebx int $0x80 call -0x2f .string \"/bin/ksh\"
上邊這段彙編實際上就是執行了兩個系統調用exec和exit,但是這執行過程中需要把字串"/bin/ksh"的地址傳遞給exec,但是這個地址在編寫shellcode的時候是不知道的。
這裡就是利用了"call"指令的特性:call的時候push eip(實際上就是call指令的下一條指令的地址入棧,在這個shellcode中就是符串"/bin/ksh"的地址),然後跳轉到"popl %esi"指令處,執行之後就是把剛剛push進棧的地址,pop給了esi寄存器。
另一個例子:編寫shellcode的另外一個技巧—Delta offset。一個shellcode寫好之後,其中的指令和資料的相對位置是固定的。那麼該shellcode在shellcode開發機和被攻擊的機器上的不同在於,shellcode的載入位置不同(eip不同)。如果把shellcode的所用到的地址都寫入程式碼為開發機中實際的地址,那麼理論上上只需要知道Delta offset,就可以計算出被攻擊機器的地址。如:
這時問題就被轉化為如何獲得被攻擊機器的eip的值,可以這樣做:
call delta delta: pop ebp
或者:
fpu_addr: fnop call GetPhAddr sub ebp,fpu_addr GetPhAddr: sub esp,16 fnstenv [esp-12] pop ebp add esp,12 ret
3.2 三個基本動作: 1、類比memory,類比CPU memory:類比兩級頁表(寫時複製)。 CPU:類比寄存器、段、當前指令及其描述。 2、靜態分析
是否是合法的x86彙編格式:
梳理指令流程:順序執行,跳轉,條件跳轉, 得到令執行流程圖。
判斷指令的資料地址有沒有超出”shellcode”的控制範圍。
3、動態執行
判斷在指令執行時,該指令所用到的寄存器、記憶體位址的值,是不是由shellcode控制的。這裡需要用到靜態分析中得到的指令執行流程圖。
3.3、判斷是不是shellcode的標準:
這個字串,是否能夠作為一段組合語言動態執行?
四、虛擬碼
emu_shellcode_test(XXX,uint8_t *data, uint16_t size { if(data不包含“0xe8”和“0xd9”) { this is safe ; return; } 從data開始找第一個合法的彙編語句,並進行靜態分析; if(靜態分析出錯)//語法錯誤或者資料不可控 { this is safe; return; } 進行動態分析; if(data中的彙編可連續動態執行N步) { this is suspecting shellcode; return; } }
五、局限性
平台:只局限於X86
效能:比較低,libemu自己提供的nids demo 吞吐為2Mbps
誤判漏報:shellcode中不一定會有"call"
檢測手段:libeum實際上並沒有真正的檢測攻擊
編碼/加密:libemu對編碼或加密的資料無能為力