最近在爲androguard實現ARM反彙編和ARM漏洞利用代碼檢測的功能。Anthony告訴我三種方案:smiasm、radare、IDAPython。前段時間嘗試了這些方法,各有優劣。歸納如下:
方案 | 開源 | 支持Thumb | 遞歸反彙編 | 提供指令詳情 |
smiasm | 是 | 否 | 是 | 是 |
radare | 是 | 是 | 否 | 否 |
IDAPython | 否 | 是 | 是 | 是 |
下面是詳細情況:
smiasm
smiasm是一個純Python的反彙編框架。它由三個子項目構成,其中elfesteem實現ELF和PE格式解析,miasm實現反彙編。
smiasm的代碼使用了Python的很多特性,比如elfesteem/elf_init.py中的這一段代碼:
class StructWrapper( object ): class __metaclass__( type ): def __new__( cls , name, bases, dct): wrapped = dct[ "wrapped" ] if wrapped is not None : # XXX: make dct lookup look into base classes for fname,v in wrapped._fields: dct[fname] = property (dct.pop( "get_" + fname, lambda self ,fname = fname: getattr ( self .cstr,fname)), dct.pop( "set_" + fname, lambda self ,v,fname = fname: setattr ( self .cstr,fname,v)), dct.pop( "del_" + fname, None )) return type .__new__( cls , name, bases, dct) wrapped = None |
讓我這樣的python初學者學到很多新的知識。
此外,smiasm使用遞歸下降反彙編,反彙編結果質量非常好。
但它不能很好地滿足我的需求。ARM架構下有三種指令集:ARM、Thumb、Thumb-2。在Android的NDK中,默認使用Thumb;在其他代碼中,ARM與Thumb的混合使用也是經常出現的。但smiasm目前仍不支持Thumb指令集。
另外,smiasm的代碼還是有些臃腫,比如反彙編接口定義如下:
def dis_bloc(mnemo, pool_bin, cur_bloc, offset, job_done, symbol_pool, dont_dis = [], follow_call = False , patch_instr_symb = True , dontdis_retcall = False , lines_wd = None , dis_bloc_callback = None , dont_dis_nulstart_bloc = False , * * kargs): |
但大部分參數最後都沒有真正使用,或者用了一個硬編碼默認值。這種情況應該是作者希望寫一個通用的反彙編框架導致的。但整個項目的代碼都沒有足夠的文檔或註釋,可用性大打折扣。
radare
radare應該是最好的開源逆向框架了。它使用C語言書寫,支持多種指令集和文件格式,例如支持ARM和Thumb。另外,它提供了對多種動態語言的綁定。radare對逆向的抽象非常到位,可以說是框架設計的一個典型。
但是在使用radare時,遇到不少問題。
一、它的python綁定使用SWIG實現,在unsigned char *型參數的傳遞上至今仍存在bug沒有被補上(而且在近期不大可能解決這個問題了),就連自己用ctypes定義一個該類型都無法搞定。雖然能夠把binary data轉成hex string,以字符串的形式傳給本地庫,但效率上無疑打了折扣。
二、其對ARM的反彙編是線性掃描反彙編,需要自行判斷一個函數是否返回,否則不斷地反彙編下去。
三、從Python中得到的反彙編結果僅僅是可以給人讀的字符串而已,不包含任何其他信息,例如指令類型、是否分支跳轉、寄存器列表、註釋等等。也就是說,如果要給人讀,radare勉強足夠,但如果要進一步處理,例如對代碼序列做檢測、畫出CFG等,就需要再去解析字符串了。這樣還不如從頭開始解析binary code。
我們來看一個輸出的片段,可以更直觀地瞭解到這兩個問題:
mov ip, sp push {fp, ip, lr, pc} sub fp, ip, #4 ; 0x4 sub sp, sp, #16 ; 0x10 ldr r2, [pc, #164] ; 0x000000bc str r2, [fp, #-28] ...... mov r0, r3 mov r1, #0 ; 0x0 bl 0xfffffffffffff9f4 mov r3, r0 ...... sub sp, fp, #12 ; 0xc ldm sp, {fp, sp, pc} andeq r2, r0, r0, lsr sp undefined instruction 0xfffff678 undefined instruction 0xfffff690 |
四、對ELF文件格式的解析同樣能力不足,太多信息被封裝起來而無法獲得。
IDAPython
IDAPython是對IDA Pro的一個功能擴展接口,封裝了IDC的幾乎所有API。
在ARM反彙編和反編譯上,IDA Pro的功能無疑是最強大的。無論是其遞歸下降反彙編、多指令集支持、混合指令識別,還是交叉引用、CFG、自動註釋、反編譯等等。IDAPython的接口也非常豐富,完全可以獲得需要的每個細節信息。
IDA Pro的主要問題在於,首先,它是一個商業軟件(目前6.2的demo版包括了arm反彙編,但無法保存數據庫);其次,它不適合於自動化處理。
結語
所以我說這三個方案是各有優劣,都無法完美地滿足我的需求。
目前來看,自己寫一個ARM/Thumb的反彙編器並不會特別困難,這個指令集本來就很簡單。關鍵是選擇好要實現的特性。