幾種ARM反彙編器

最近在爲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的反彙編器並不會特別困難,這個指令集本來就很簡單。關鍵是選擇好要實現的特性。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章