曲海鵬, 于 芮, 孫 磊, 呂文杰
(中國海洋大學信息科學與工程學院, 山東 青島 266100)
基帶處理器是移動通信設備的重要組成部分,負責處理與蜂窩網(wǎng)絡的通信,擁有獨立的RAM和固件?;鶐Ч碳褂肅編寫,不使用libc、glibc等通用的函數(shù)庫,使用靜態(tài)編譯且剝離了調(diào)試信息,運行于實時操作系統(tǒng)(RTOS)和ARM處理器上,包含有與蜂窩協(xié)議相關的眾多功能[1]。雖然基帶固件的這些特點給逆向分析和漏洞發(fā)掘帶來很大困難,但基帶固件漏洞近年來還是不斷被曝出[2-4]。由于基帶固件的閉源性和大量使用內(nèi)存拷貝操作,我們認為更有針對性的安全分析將可能發(fā)現(xiàn)其更多安全漏洞。目前,研發(fā)基帶處理器的廠商主要包括,高通,三星,華為等。其中,本文研究的是三星Shannon基帶芯片,其處理器架構是Armv7-R,提取得到的基帶固件大小有36.5 MB,經(jīng)IDA識別得到的函數(shù)達61 535個。
可執(zhí)行目標文件中的調(diào)試信息中包含有函數(shù)名稱[5],因此針對調(diào)試信息剝離的基帶固件的安全分析分為函數(shù)安全性分析和漏洞發(fā)掘兩個階段。函數(shù)安全性分析的目標是重新識別基帶固件中執(zhí)行可變長度內(nèi)存拷貝功能的危險函數(shù),漏洞發(fā)掘的目標是發(fā)現(xiàn)由于危險函數(shù)的不正確使用,導致的緩沖區(qū)溢出漏洞。第一階段的分析方法多使用基于二進制代碼相似性[6]比對的函數(shù)識別方法,以目前應用最廣泛的 Google BinDiff[7-8]為例,通過將目標固件與使用標準函數(shù)庫編譯得到的固件進行比對,可匹配出與標準函數(shù)庫中危險函數(shù)類似的函數(shù)。BinDiff通過對比多種語義特征,匹配輸入文件之間相似的函數(shù),但因基帶固件函數(shù)重寫、調(diào)試信息剝離、靜態(tài)鏈接等方式導致只能發(fā)現(xiàn)少量危險函數(shù)。
2012年RP Weinmann[3]首次系統(tǒng)性的介紹了在基帶固件中發(fā)現(xiàn)的內(nèi)存損壞漏洞,并搭建偽基站對漏洞實現(xiàn)了利用。在RP Weinmann的工作中,首先使用二進制文件對比工具BinDiff,對固件中使用的內(nèi)存拷貝危險函數(shù)進行了重新識別,之后,通過分析危險函數(shù)處的代碼實現(xiàn)和相關協(xié)議規(guī)范,發(fā)現(xiàn)了多個內(nèi)存破壞缺陷。在之后的國際黑客會議上,針對基帶發(fā)現(xiàn)的漏洞多是由于固件中的危險函數(shù)導致的緩沖區(qū)溢出漏洞,例如函數(shù)memcpy()[9]和memcpy_s()[2]。
現(xiàn)在已有多種對危險函數(shù)進行重寫識別的二進制文件對比工具。BinDiff是目前最流行,應用最廣泛的對比工具。BinDiff依賴于IDA,并將IDA數(shù)據(jù)庫文件作為輸入文件,它忽略匯編層指令的結構,工作在函數(shù)的控制流程圖和調(diào)用關系圖層面上,基于圖形結構中所包含的語義特征進行相似性檢測,具有很好的抗混淆[10-11]特性。BinDiff根據(jù)兩種圖形結構中基本塊的數(shù)量,基本塊間邊的數(shù)量和子函數(shù)調(diào)用關系,為每個函數(shù)計算得到一個“指紋”,并利用該“指紋”在兩個二進制文件中匹配相似的函數(shù)。此外,對于一些僅使用以上兩種圖形結構,無法識別相似性的函數(shù),BinDiff通過比較函數(shù)內(nèi)容的哈希值、函數(shù)內(nèi)循環(huán)的次數(shù)和函數(shù)內(nèi)引用的字符串等進行更深一步的探索。另外和BinDiff一樣,工作在抽象圖形模型層面上的二進制對比工具還有Diaphora[12-13],Turbodiff[14],BinKit[15]。近幾年,隨著機器學習方法的流行,跨學科知識的交叉開始在基于語義特征的相似性檢測中得到應用,包括Asm2vec模型[16],SAFE網(wǎng)絡[17]等。
另一種識別危險函數(shù)的二進制文件對比工具IDA FLIRT[18],則基于函數(shù)的二進制字節(jié)序列進行比對。FLIRT創(chuàng)建了一個包含所有想要識別的庫函數(shù)的數(shù)據(jù)庫,每個庫函數(shù)在FLIRT數(shù)據(jù)庫中被表示為一個簽名,這個簽名是由函數(shù)的前32個字節(jié)組成的,其中包括所有的變體字節(jié)。通過將待識別的函數(shù)的字節(jié)簽名與數(shù)據(jù)庫中的簽名進行對比,F(xiàn)LIRT判斷其是否為已知的庫函數(shù)。但是,與使用抽象圖形模型的BinDiff對比,F(xiàn)LIRT靈活性較差。
其他的開源的二進制文件對比工具還包括主要應用于微軟的補丁分析的eEye Binary Diffing Suite[19];適用于較小的文件比較的IDACompare[20]等。
本文提出了一種基于動態(tài)執(zhí)行的基帶固件函數(shù)安全性分析方法DEx。DEx方法通過把固件正確映射到內(nèi)存中,對固件函數(shù)實現(xiàn)調(diào)用執(zhí)行。同時,針對危險函數(shù)的特征,DEx捕獲函數(shù)動態(tài)執(zhí)行過程中產(chǎn)生的三種語義信息,包括函數(shù)對內(nèi)存的讀寫,存儲在寄存器R0中的返回值以及函數(shù)執(zhí)行過程中產(chǎn)生的輸出內(nèi)容,并設置優(yōu)先級排序,以用于后續(xù)函數(shù)的安全性分析。
動態(tài)執(zhí)行方法DEx與傳統(tǒng)的二進制代碼相似性方法存在幾個重要的不同之處。首先,DEx方法只對基帶固件進行分析。與二進制代碼相似性方法還需使用到對比文件相比,只需要用到目標固件即可。其次,DEx更加關注危險函數(shù)所包含的語義特征。與二進制代碼相似性方法所使用的多種的、廣泛的特征信息相比,更具針對性。同時,本文基于DEx方法,實現(xiàn)了dyndiff工具,評估結果顯示,dyndiff提高了基帶固件中危險函數(shù)的識別準確率。最后,闡述了本文所做的函數(shù)安全性分析工作在后續(xù)漏洞發(fā)掘工作中的應用。
為了降低文件的大小和更好的抵抗逆向分析,基帶固件中包括符號表在內(nèi)的調(diào)試信息都是被剝離的。針對調(diào)試信息剝離的基帶固件的逆向分析首先需要使用二進制補丁對比工具重新識別基帶固件中執(zhí)行內(nèi)存拷貝的危險函數(shù)。因此,通過使用目前應用最廣泛的BinDiff將固件與使用標準函數(shù)庫編譯得到的固件進行比對,重新識別了目標固件中使用的strcpy(),strncpy(),strcat(),strncat()等危險函數(shù)。但是,在人工分析基帶偽代碼的過程中,我們發(fā)現(xiàn)了多個BinDiff工具未能正確識別的危險函數(shù),如圖1(a)所示。與圖1(b)中所示的標準庫中危險函數(shù)相比,其未進行源指針和目的指針所指向的地址是否為空(圖1(b)第二行代碼)或是否重疊(圖1(b)第七行代碼)等情況的判斷,因此,我們推測該函數(shù)是在程序開發(fā)過程中由編程人員重新實現(xiàn)的?;鶐Ч碳纳鲜鎏卣?,特別是函數(shù)重寫導致的危險函數(shù)與標準庫中危險函數(shù)相比實現(xiàn)太過簡單,導致了基于多特征信息進行函數(shù)匹配的BinDiff只能發(fā)現(xiàn)少量危險函數(shù)。由于基帶固件中函數(shù)個數(shù)達6萬多個,人工分析以發(fā)現(xiàn)全部危險函數(shù)顯然是不現(xiàn)實的。針對上述問題,本文提出了基于動態(tài)執(zhí)行的DEx方法。
圖1 固件中與標準庫中危險函數(shù)代碼對比
DEx方法整體流程框架如圖2所示。首先,經(jīng)預處理模塊得到基帶固件的函數(shù)信息和段內(nèi)容。之后,特征信息收集模塊加載基帶固件段內(nèi)容到內(nèi)存中,根據(jù)函數(shù)信息動態(tài)執(zhí)行內(nèi)存中符合條件的函數(shù),并得到函數(shù)的語義特征信息。最后,根據(jù)函數(shù)的語義特征信息,經(jīng)函數(shù)安全性分析模塊識別得到危險函數(shù)。
圖2 DEx方法整體流程
1.2.1 預處理 以三星Shannon基帶固件為例,代碼中包含多達6萬余個函數(shù),為了提高后續(xù)動態(tài)執(zhí)行的整體效率,首先經(jīng)預處理模塊過濾掉一部分無關函數(shù)。為了確定應該監(jiān)控并記錄基帶固件中哪些函數(shù)的動態(tài)執(zhí)行時信息,通過對標準函數(shù)庫中危險函數(shù)的分析,DEx方法將執(zhí)行內(nèi)存拷貝的危險函數(shù)mem_copy分為以下3種類型:
re_val mem_copy(void*dest, [dest_length], void*src, [src_length]);
(1)該函數(shù)接收兩個指針型參數(shù)src和dest,并將源指針src指向內(nèi)存中的數(shù)據(jù)復制或追加到目的指針dest指向的內(nèi)存中。
(2)該函數(shù)接收兩個指針型參數(shù)src、dest和一個數(shù)值型參數(shù)src_length,并將源指針src指向內(nèi)存中的src_length個字節(jié)的數(shù)據(jù)復制或追加到目的指針dest指向的內(nèi)存中。
(3)該函數(shù)接收兩個指針型參數(shù)src、dest和兩個數(shù)值型參數(shù)src_length、dest_length,其中dest_length表示目的地址存儲空間的大小。
基于以上對危險函數(shù)的分類,預處理模塊根據(jù)python模塊idaapi,idc和idautils中提供的函數(shù)得到基帶固件的函數(shù)信息和段內(nèi)容。其中函數(shù)信息包括函數(shù)的參數(shù)個數(shù),函數(shù)距離基帶固件文件頭的偏移量,以及對函數(shù)指令集的說明,用常數(shù)0和1來區(qū)分。0表示ARM指令集,1表示Thumb指令集?;鶐Ч碳亩蝺?nèi)容包括每段所包含的字節(jié)數(shù)量和具體的字節(jié)序列內(nèi)容。
1.2.2 特征信息收集 根據(jù)預處理模塊得到的基帶固件函數(shù)信息和段內(nèi)容,特征信息收集模塊主要完成以下兩個操作:
(1)加載基帶固件段內(nèi)存到內(nèi)存中。
(2)根據(jù)基帶固件的函數(shù)信息對內(nèi)存中的函數(shù)實現(xiàn)動態(tài)執(zhí)行,監(jiān)視并記錄函數(shù)運行期間產(chǎn)生的語義特征信息。
一旦段內(nèi)容被正確映射到內(nèi)存,DEx將控制轉移到內(nèi)存中的函數(shù)以對其實現(xiàn)動態(tài)執(zhí)行。在此之前,根據(jù)函數(shù)信息,對待執(zhí)行的基帶固件函數(shù)做如下調(diào)用約定:僅執(zhí)行基帶固件中參數(shù)個數(shù)為兩個、三個或四個的函數(shù)。
(1)如果該函數(shù)的參數(shù)個數(shù)為兩個,約定全部為指針類型。
(2)如果該函數(shù)的參數(shù)個數(shù)為三個,約定兩個為指針類型,一個為數(shù)字類型。
(3)如果該函數(shù)的參數(shù)個數(shù)為四個,約定兩個為指針類型,兩個為數(shù)字類型。
其中,段內(nèi)容在內(nèi)存中的基地址與函數(shù)信息中函數(shù)的偏移量之和即為函數(shù)在內(nèi)存中的地址,通常,通過把該值傳值到調(diào)用程序處便可實現(xiàn)對函數(shù)的執(zhí)行。但是,ARMv7-R支持ARM和Thumb兩種指令集。ARM指令集的指令長度為32位,Thumb指令集的指令長度為16位或者32位。處于Thumb狀態(tài)(即正在執(zhí)行Thumb指令)的處理器可以通過執(zhí)行BX、BLX等指令進入到ARM狀態(tài),更改為執(zhí)行ARM指令,反之亦然。當處理器在Thumb狀態(tài)和ARM狀態(tài)之間切換時,傳值到調(diào)用程序處的值較正常情況略有差異,除了對待執(zhí)行的固件函數(shù)內(nèi)存地址的說明,還需說明函數(shù)使用的是何種指令集。例如分支指令BLX(register),如果處理器是由ARM狀態(tài)切換至Thumb狀態(tài),傳值到調(diào)用程序處的值等于段內(nèi)容在內(nèi)存中的基地址加上函數(shù)的偏移量再加上1,其中“1”表示當前待執(zhí)行的基帶固件函數(shù)使用的是Thumb指令集。
在實際運行過程中,為保證對基帶固件的調(diào)用執(zhí)行總在合理的時間內(nèi)終止,對于一個函數(shù)的一次執(zhí)行,我們定義了以下標準用于判斷函數(shù)是否已經(jīng)運行結束:
(1)執(zhí)行到達函數(shù)的結尾,函數(shù)正常返回。
(2)函數(shù)執(zhí)行出錯。
(3)函數(shù)的運行時間超過約定的時間。
為了確定某個函數(shù)是否是執(zhí)行可變長度內(nèi)存拷貝功能的危險函數(shù),特征信息收集模塊記錄基帶固件函數(shù)的各種動態(tài)運行時信息。在分析了標準庫中相關危險函數(shù)的實現(xiàn)后,本文選取的特征信息即可捕獲各種系統(tǒng)級別信息(例如內(nèi)存訪問),也可獲取函數(shù)本身可能的輸出。同時,對選取的特征信息設置了如下優(yōu)先級排序以用于后續(xù)的函數(shù)安全性分析:
(1)第一類優(yōu)先級是函數(shù)對內(nèi)存的讀寫。
(2)第二類優(yōu)先級是存儲在寄存器R0中函數(shù)的返回值。
(3)第三類優(yōu)先級是函數(shù)運行期間產(chǎn)生的輸出內(nèi)容。
執(zhí)行內(nèi)存拷貝功能的危險函數(shù),在運行過程中會對參數(shù)指針指向的內(nèi)存進行讀寫操作。例如,標準函數(shù)庫中危險函數(shù)
char*strcpy(char*dest,const char*src)。
將指針src指向內(nèi)存中的字符串復制到指針dest指向的內(nèi)存中。由于strcpy()函數(shù)沒有長度參數(shù),無法確定目的緩沖區(qū)的大小,不正確的使用可能會導致緩沖區(qū)溢出并破壞相鄰其他內(nèi)存。同時,strcpy()函數(shù)將指向目標地址的指針作為返回值傳遞給上層調(diào)用者。因此,特征集收集模塊捕獲基帶固件函數(shù)執(zhí)行前后參數(shù)指針指向內(nèi)存中的內(nèi)容,以及上層調(diào)用者得到的返回值。危險函數(shù)的返回值既可以是指向目的地址指針的副本,也可以是常數(shù)。例如函數(shù)memcpy_s(),執(zhí)行成功返回零,錯誤返回非零值。
1.2.3 函數(shù)安全性分析 根據(jù)特征信息收集模塊得到的函數(shù)特征信息以及設置的優(yōu)先級排序,如果基帶固件函數(shù)訪問了參數(shù)指針指向的內(nèi)存,并且函數(shù)執(zhí)行完成后目標地址字符串等于或者包含源地址字符串,則認為該函數(shù)是執(zhí)行內(nèi)存拷貝功能的危險函數(shù)。同時,實驗過程中,我們發(fā)現(xiàn)基帶固件中存在某類函數(shù)A,A函數(shù)只是對危險函數(shù)進行了簡單調(diào)用。安全性分析模塊依據(jù)第二類優(yōu)先級,存儲在寄存器R0中函數(shù)的返回值,對A類函數(shù)實現(xiàn)過濾。最后,第三類優(yōu)先級,函數(shù)執(zhí)行過程中產(chǎn)生的所有輸出內(nèi)容被發(fā)送到指定文件并提供給研究人員,以發(fā)現(xiàn)其他有趣的部分。
基于DEx方法,我們實現(xiàn)了dyndiff函數(shù)安全性分析工具(https://github.com/xibeiandchangan/dyndiff),并以三星Shannon基帶固件為對象進行了對比實驗。實驗環(huán)境為ubuntu linux 18.04.2 LTS系統(tǒng),安裝交叉編譯工具鏈arm-linux-gnueabihf[21]和QEMU虛擬機管理器[22],其中arm-linux-gnueabihf支持x86處理器架構上進行ARM處理器架構可執(zhí)行代碼的交叉編譯生成,QEMU用戶模式支持在x86處理器架構上進行ARM可執(zhí)行文件的模擬執(zhí)行。實驗結果如表1所示。
dyndiff重新識別得到固件中22個危險函數(shù),而BinDiff識別結果為4個。其中,圖3為本文實現(xiàn)工具dyndiff和BinDiff識別結果對比圖。dyndiff比BinDiff表現(xiàn)更好:dyndiff識別得到的危險函數(shù)的個數(shù)是BinDiff對比工具的5.5倍,其中包括對BinDiff識別結果的全覆蓋。
表1 dyndiff識別結果
圖3 dyndiff和BinDiff識別結果對比圖
在對dyndiff工具的識別結果分析過程中,本文發(fā)現(xiàn)一個有趣的現(xiàn)象,即在基帶固件中存在多個代碼實現(xiàn)完全相同的危險函數(shù),如圖4所示。我們推測這可能是由于基帶固件源程序是由多個程序開發(fā)人員分工合作編寫完成,因此出現(xiàn)了對同一功能函數(shù)的多次實現(xiàn)。
在3GPP規(guī)范中,運行在手機端的GSM協(xié)議棧的第3層消息由IEs(Information Elements)組成,而某些IEs被定義為可變長度的。當危險函數(shù)將可變長度的IEs復制至本地棧時,不充分的長度檢查將導致緩沖區(qū)溢出漏洞。因此,本論文進行的函數(shù)安全性分析工作,是后續(xù)漏洞發(fā)掘的基礎?;赿yndiff識別結果,通過分析危險函數(shù)處的代碼實現(xiàn)和與之相對應的協(xié)議規(guī)范,我們發(fā)現(xiàn)了存在的內(nèi)存破壞缺陷,更深入的利用研究仍在進一步進行。
圖4 兩個實現(xiàn)完全相同的危險函數(shù)
本文針對基帶固件函數(shù)的安全性分析問題,提出了動態(tài)執(zhí)行方法DEx。DEx通過對基帶固件函數(shù)實現(xiàn)調(diào)用執(zhí)行,并根據(jù)其運行過程中產(chǎn)生的語義信息和設置的優(yōu)先級排序,解決了基帶固件中危險函數(shù)的識別問題。實驗結果表明,dyndiff工具表現(xiàn)出比BinDiff更好的識別效果。由于基帶固件中函數(shù)數(shù)量達6萬多個,后續(xù)的工作將研究DEx方法的預處理模塊,對待執(zhí)行函數(shù)做進一步的篩選,以進一步提高dyndiff的工作效率。本文實現(xiàn)工具dyndiff的下載地址https://github.com/xibeiandchangan/dyndiff。