PPC和MIPS指令集下二進位代碼中函數參數個數的識別方法尹小康, 劉鎏, 劉龍, 劉勝利
數學工程與先進計算國家重點實驗室,河南 鄭州 450001
摘要:函數參數個數的識別有助於函數原型的恢復,是進行數據流分析以及其他安全分析的基礎。為了提高對函數參數個數識別的準確率,提出一種依據函數調用關係的投票機制來確定函數參數個數的算法——Findargs。Findargs從PPC和MIPS指令集的函數調用特點出發,利用函數調用關係和參數傳遞分析,識別函數參數的個數,為函數原型的恢復提供幫助。為了評估Findargs的識別效果,選取大型的二進位文件進行了測試,並與radare2進行了對比。實驗結果表明,Findargs具有更高的準確率。對於PPC指令集,其準確率達到90.3%;對於MIPS指令集,其準確率為86%。
關鍵詞:靜態分析 ; 函數調用分析 ; 參數個數識別 ; 投票機制
中圖分類號:TP309
文獻標識碼:A
doi:10.11959/j.issn.2096−109x.2020047
1 引言
二進位分析在安全研究中具有重大意義,在安全分析中的應用主要有:二進位代碼審計、控制流完整性分析、汙點分析、符號執行、漏洞修復、代碼重用、漏洞挖掘等。在高級語言中,函數名、函數的參數個數、參數類型、函數的返回值等信息能夠有效幫助理解函數的功能。原始碼經過編譯器編譯丟失了如高級語言C/C++中的數據類型、數據結構、語義以及控制結構等信息,這給研究者分析二進位代碼造成了諸多障礙。因此,如何從二進位代碼中恢復出丟失的信息成為二進位分析的關鍵。對二進位程序進行逆向分析的第一步是對函數的識別,確定函數的起始位置、結束位置、函數的調用方式,以及函數的參數個數。二進位代碼逆向分析的準確率影響後續安全分析的正確性。函數參數個數的準確識別是進行函數原型識別的基礎,是進行數據流分析以及其他安全分析的前提。由於精簡過的二進位程序中的符號表等信息被移除,無法直接獲得函數入口等相關信息,增加了對二進位可執行文件進行分析的難度。Caballero等提出了X86指令集下基於動態分析的二進位函數接口識別方法。在無原始碼和符號表的情況下,該方法對二進位代碼進行動態分析,獲取函數的原型,以達到重用二進位函數的目的。由於動態分析無法獲取全面的信息,因此識別效果較差。radare2是最新的二進位分析工具,它擁有強大的分析功能,支持對不同架構語言的反彙編,在「aaa」命令中實現了對二進位函數分析的功能,在對PPC和MIPS指令集的二進位函數進行分析時,發現函數參數個數的識別效果比較差。為提高函數參數個數的識別準確率,本文提出並實現了一種基於函數調用關係的函數參數個數識別算法——Findargs,用於識別PPC和MIPS指令集下二進位可執行代碼中函數的參數個數。該方法結合PPC和MIPS指令集下函數參數的傳遞規則,通過分析函數調用時寄存器以及棧的使用情況,獲取二進位函數的參數個數。為了提高識別的準確率,Findargs 分析獲得所有的函數調用關係,然後對每個函數的調用者進行了分析,並通過投票機制,選取最有可能的參數個數。Findargs適用於對大型固件的分析,並且函數被調用的次數越多,準確率越高。本文的主要工作如下。1) 分析了函數參數識別的問題,並提出了二進位可執行代碼中二進位函數參數個數識別的概念。2) 提出並實現了基於函數調用關係的函數參數個數識別算法——Findargs。Findargs 使用靜態分析的方法,無須動態執行二進位文件,適用性較好。3) 選取大型的嵌入式系統固件,對該算法進行了評估,並與現有的二進位分析工具 radare2進行了對比。實驗結果表明,Findargs 具有更高的準確率。2 問題描述
2.1 問題定義二進位函數是在二進位可執行文件中,通過函數識別技術識別出具有函數入口和出口的代碼片段。與高級語言中的函數類似,二進位函數同樣具有函數名、函數參數、函數返回值等。參數傳遞指令序列是在函數調用指令前用於傳遞函數參數等信息的一段代碼片段。函數參數個數識別的目的是識別二進位函數中函數傳遞參數的個數,用於分析在二進位函數調用時參數的傳遞情況,進而分析程序的數據流的傳遞情況。對二進位文件中的函數參數個數進行識別的基礎是函數邊界的識別。函數邊界識別是給定包含n個函數的二進位文件輸出完整的函數起始地址集合。函數參數個數的識別問題是對於給定的二進位函數指令序列和函數的起始地址,輸出函數的參數個數。對於精簡二進位程序而言,輸出所有二進位函數的參數個數對。
2.2 二進位函數調用特點函數參數的傳遞一般有3種方式:棧傳遞、寄存器傳遞與全局變量進行隱式參數傳遞。通過棧傳遞參數,需要對參數的入棧順序進行約定,並對棧的平衡方式進行約定,最終確定由調用者還是被調用者來恢復棧平衡。對於使用寄存器傳遞參數來說,同樣需要確定哪些寄存器用於傳遞參數,以及參數傳遞的順序,並且需要確定當參數個數大於可用於傳遞參數的寄存器數時,如何進行參數傳遞。對於全局變量進行隱式參數傳遞來說,通過設置全局變量來共享變量,在一個函數內對該變量的修改會影響其他函數中該變量的值。對於使用全局變量進行隱式參數傳遞,需要進行數據流分析,才能從二進位可執行代碼中識別出全局變量。函數參數調用中常用的調用約定共有4種:_cdecl(C 規範)、pascal、stdcall 與 fastcall。表1詳細展示了各個調用約定的參數傳遞方式和傳遞順序以及平衡棧者。由表1可知,_cdecl、pascal、stdcall均使用棧進行參數的傳遞,fastcall利用處理器中寄存器的優勢使用寄存器和棧來傳遞參數。棧作為一種先進後出的數據結構被廣泛地應用。在調用函數時,通過將參數壓入棧中將參數傳遞給子程序。函數調用結束後,對棧進行平衡操作,將棧恢復到函數調用前的狀態。當函數具有多個參數時,需要對參數的傳遞順序進行約定,以及確定由函數調用者或者子程序來恢復棧的平衡。當函數具有多個參數時,_cdecl和stdcall約定參數的傳遞順序採用由右至左的順序,pascal約定參數傳遞順序採用由左至右的順序。對於棧的平衡方式,_cdecl 是調用者對棧進行平衡,而pascal、stdcall 和 fastcall 使用子程序對棧進行平衡。圖1為利用棧進行函數參數的傳遞,該參數傳遞方式是從右至左,首先將第二個參數壓入棧中,然後將第一個參數壓入棧中,在使用參數時通過ebp或者sp進行尋址。
![]()
使用寄存器進行參數傳遞具有快速高效的特點,尤其當函數的參數個數較少時,直接將參數放入寄存器中進行讀取,減少了一定的內存操作。處理器中擁有多個寄存器,可以選擇部分寄存器用於函數參數的傳遞。由表1可知,fastcall採用寄存器和棧進行函數參數的傳遞。當函數參數較少時,直接使用寄存器傳遞參數,當函數參數超過可用參數寄存器時,則將多餘的參數通過棧來傳遞。使用棧傳遞參數時,約定了參數的傳遞順序和棧平衡操作者。對於fastcall,參數的傳遞順序因編譯器的不同而不同,但都是通過子程序來平衡棧。
2.3 PPC和MIPS指令集下的函數參數傳遞表2列舉了PPC和MIPS指令集中約定可用於傳遞參數的寄存器。在PPC指令集中,寄存器r3作為函數的第一個參數,剩餘的參數分別依次放入r4 ~ r10,由此可知,PPC指令集中可用寄存器最多傳遞8個參數。在MIPS指令集下,分別使用編號為4 ~ 7的寄存器來傳遞參數,名稱分別為a0a3,因此,MIPS指令集下可通過寄存器來傳遞參數的個數最大為 4,多餘的參數需要通過棧進行傳遞。
![]()
2.4 運行實例
下面以sub_801FDFA4和sub_600746B8函數參數的傳遞方式為例,具體分析PPC和MIPS指令集下函數參數的傳遞過程。在PPC指令下用於傳遞參數的寄存器為 r3~r10,在調用函數sub_801FDFA4時使用了r3~r8寄存器,因此函數的參數個數為6。對於函數sub_600746B8,則為MIPS 指令下的函數,用於傳遞參數的寄存器為a0a3,在調用函數sub_600746B8時,在這段指令中使用了a1,a2,a3寄存器以及進行了兩壓棧和。參數寄存器的使用具有以下事實:參數寄存器是按照順序使用的,當後一個寄存器用於傳遞參數時,前一個寄存器必定用於傳遞參數。可知a0 也用於傳遞參數,共有 6 個參數。PPC 指令、MIPS 指令下函數調用參數的傳遞分別如圖2、圖3所示。3 二進位函數參數個數識別本節對二進位函數參數的識別算法進行詳細介紹。二進位可執行文件的函數參數個數識別算法——Findargs的流程如圖4所示。
3.1 函數邊界的識別對函數邊界的識別是二進位分析的基礎,需採用的函數邊界識別方法是 FRwithMBA,通過分析二進位可執行代碼,提取出函數的邊界,包括起始地址和結束地址,用於函數調用關係的分析。
3.2 二進位函數調用關係的建立與轉換函數調用關係的分析在二進位逆向分析中具有重要作用,如用於惡意代碼分析與分類、計算代碼相似性等,本文將函數的調用關係用於函數參數個數的識別。函數調用關係的分析是函數控制流圖生成以及研究數據流的基礎,函數調用關係圖(FCG,function call graph)對理解大型程序有很大幫助,FCG反映了函數的結構、可擴展性等信息。按照分析目標的不同,函數調用關係的分析可以分為源碼層面和二進位層面;按照分析方式的不同,函數調用關係分析可以分為靜態分析和動態分析。靜態分析依賴於對目標語言的理解水平,對目標語言中的函數調用指令分析的全面性,能夠遍歷分析所有分支,但是無法獲取間接函數調用的關係。動態分析是藉助函數運行時的信息進行分析,在程序運行時,能夠獲得相對於靜態分析更多的信息,但是對於程序未執行到的分支則無法進行分析。本文主要研究的是使用靜態分析方式分析二進位可執行代碼中的函數調用關係,獲取比較全面的函數直接調用關係,用於後續的函數參數的識別。與函數的邊界識別一樣,對二進位代碼中函數關係的分析可以採用線性掃描的方式或者遞歸下降回溯掃描的方式。對後續的參數識別只需要取函數調用的第一層關係即可。因此,函數調用關係的分析採用靜態分析的方式,結合函數的邊界,採用線性掃描的技術對整個代碼段進行分析。函數的邊界為函數的起始和結束地址,在每次解析函數調用關係時,將整個函數的可執行代碼取出進行解析,通過解析生成格式為{函數地址:子程序1,子程序2,子程序3,…,子程序m}的形式。在對所有的函數分析完成後,將格式轉換為{子程序:調用者1,調用者2,調用者3,…,調用者n}的形式用於後續的函數參數的識別。
3.3 基於調用關係的函數參數個數識別算法函數調用前的一段指令是對參數進行傳遞的指令,為了分析函數參數傳遞的情況,只需對函數調用前的一段長度的指令進行分析,這段代碼為參數傳遞指令序列。函數調用前,父函數會將調用子程序時需要的參數根據函數調用約定放入寄存器中或者壓入棧中。對二進位函數指令序列進行掃描分析,識別出其中的函數調用指令。選取函數調用前的一段指令序列作為函數參數傳遞指令序列,對參數傳遞指令序列進行分析,主要包括兩個方面:對參數寄存器的使用情況和棧操作的情況進行分析。對參數寄存器的使用情況分析主要是分析參數傳遞指令中使用了哪些參數寄存器,對於PPC指令主要分析r3 ~ r10寄存器的使用情況,對於MIPS指令則主要分析a0 a3寄存器的使用情況。對於棧操作的指令分析,主要分析在參數傳遞指令中是否進行了壓棧操作來傳遞參數。對於函數參數的傳遞,有以下情況:對於未使用棧進行參數傳遞的函數,函數參數個數不會超過參數寄存器的個數,因為當參數寄存器足夠時,必定會使用參數寄存器來傳遞參數;並且當後一個參數寄存器用於傳遞參數時,前一個參數寄存器必定也用來傳遞參數,如在PPC指令下進行參數傳遞時,如果r5寄存器被用於傳遞參數,那麼前面的r3和r4寄存器也一定被用於傳遞參數。由於編譯器的優化,函數參數的傳遞位置可能發生改變,函數參數的傳遞會遠離函數調用指令,因此僅對單個的函數調用進行參數識別會出現識別錯誤的情況。為解決參數識別錯誤的問題,本文提出採用多函數調用分析的方法,即當該函數存在多個調用者時,對每個調用者都進行函數參數傳遞分析,獲得該函數的參數個數,然後使用基於投票的方法,選擇函數參數個數出現頻率最多的為函數參數的個數。通過對函數的調用關係的分析,能夠得到{子程序:調用者1,調用者2,調用者3,…,調用者n}的函數調用關係。為了更準確地獲得函數參數的個數,本文首先分別計算函數的調用者中傳遞的參數個數;然後基於投票的機制,對函數的參數個數進行投票,獲得票數最多的為函數的參數個數;最後運用函數參數個數識別算法進行函數參數個數的識別。輸入 二進位代碼序列B和函數調用關係集輸出 函數參數個數對1) 對參數變量進行初始化,設置函數參數個數數組S[],並對數組S[]中元素初始化為0;2) 從函數調用關係集 M 中取出一個元素,進行函數參數個數的識別,當取出所有元素後,結束執行,進行步驟5);3) 從函數關係中,依次取出函數調用者地址,並在二進位代碼序列B中取出該函數的二進位指令Fi,若已經取出所有調用者,則轉步驟4);對函數指令序列Fi進行線性掃描解析,查找函數調用指令,取出函數調用指令前m條指令進行參數寄存器和棧使用情況的分析,計算出函數的參數個數n,則S[n]←S[n]+1,繼續步驟3);4) 查找數組S[]中最大數,則最大數的下標j即函數的參數個數,將{calleri:j}添加到函數個數對集合P中,繼續步驟2);
3.4 運行實例調用函數 Func_37326dc8 的函數關係如圖5所示。由圖5可知共有9個函數調用了該函數,為了準確識別函數Func_37326dc8的參數個數,對調用函數Func_37326dc8的這9個函數進行參數傳遞分析,最終選取出現次數最多的數為函數的參數個數。其中,根據函數Func_3092dabc傳遞的參數分析函數 Func_37326dc8 的參數個數為2,而對剩餘的8個函數進行參數傳遞分析獲得的函數Func_37326dc8的參數個數為3,因此函數Func_37326dc8的參數個數為3。經驗證結果正確。圖5 調用函數Func_37326dc8的函數關係4 實驗評估
4.1 實驗設置本節對Findargs的函數參數識別效果進行評估,並與現有的工具radare2進行對比。實驗所用計算機的配置為Intel R CoreTM 6-core 3.7 GHz i7-8700K CPU and 32 GB RAM。radare2的版本為radare2 2.7.0-git 18197 @ linux-x86-64 git.2.6.032-g3c8d7d53f。
4.2 實驗結果為了驗證函數參數個數的識別效果,需要選取擁有大量函數並且調用關係多樣的二進位代碼。本文選取了路由器固件 C2600-IPBA SEM-12.3(6f).BIN(PPC 指令集)和 C2900UNIVERSALK9 - M-15.7(3)M2.BIN(MIPS指令集)為測試樣本,逆向分析得到二進位中的C語言庫函數,對函數參數個數的識別效果進行驗證, C語言部分庫函數的參數個數識別對比如表3所示。從表中可以看出該方法能夠準確識別出函數的參數個數。
![]()
「—」表示未在PPC指令集的二進位文件中發現此函數由表3 可知,Findargs 對於常用庫函數的識別的效果較好,原因是庫函數調用的次數比較多,並且函數的參數個數較少,使用參數寄存器能夠滿足所有參數的傳遞。為了能夠更準確地評估 Findargs 的識別效果,本文從路由器固件中 C2600-IPBASEM-12.3(6f).BIN和C3725-I-M-12.3(1a).BIN逆向分析獲得函數的參數個數,分別使用 Findargs 和radare2進行了參數個數的識別,識別結果如表4所示。實驗結果表明,與radare2相比,Findargs具有更高的準確率。對於PPC指令集,Findargs準確率達到 90.3%;對於 MIPS 指令集,識別的準確率較低,達到86.0%。在實驗中,Findargs的輸出結果為函數的起始地址和參數個數對。而radare2 首先通過命令「aaa」對二進位可執行文件進行分析,然後通過「afll」命令輸出到文本中,並使用 Python 腳本對輸出的結果進行提取以獲得函數的參數個數。為了更好地展示Findargs的識別效果和函數調用次數對參數個數識別準確率的影響,本文依據函數的調用次數對這些函數進行了分類統計。對PPC和MIPS指令集分別統計了上述的300個函數,分類統計結果為:對於PPC指令集,函數調用次數大於或等於2次的共有139個,函數調用次數大於或等於3次的共有77個,函數調用次數大於或等於4次的共有54個;對於MIPS指令集,函數調用次數大於或等於2次的共有144個,函數調用次數大於或等於3次的共有105個,函數調用次數大於或等於4次的共有76個。函數調用次數對函數參數個數識別的影響如表5所示,其中,多調用分析是對所有的調用者進行分析識別準確的函數個數,單調用分析是只分析其中的一個函數調用進行分析識別準確的函數個數。表6展示了不同調用次數下的函數參數個數的識別準確率。由表中數據可知,函數調用次數越多,函數參數個數的識別準確率越高,並且多調用分析的效果好於單調用分析。為了研究函數參數個數對參數識別準確率的影響,本文對不同參數個數的函數進行了統計(如表7所示),分別計算了識別的準確率(如表8所示)。由表可知,函數的參數個數一般小於 6 個。整體上來說,在此範圍(參數小於6)內函數識別的準確率較高,由於PPC有8個參數寄存器,基本能夠滿足函數進行參數的傳遞。對於MIPS指令而言,在參數個數大於4時,需要藉助棧進行參數的傳遞,使用棧進行參數的傳遞比使用參數寄存器傳遞複雜,因此識別的準確率略低。後續將考慮結合數據流分析追蹤參數的使用情況來提高MIPS指令集下函數參數個數識別的準確率。此外,經過分析函數調用的位置同樣影響函數參數個數的識別準確率,位於函數頭部的函數調用由於借用了上層函數的調用參數,沒有明顯的傳參行為,因此對存在此類函數調用的函數的識別準確率較低。
![]()
![]()
![]()
![]()
![]()
5 結束語函數的參數個數作為函數原型中的一個重要特徵,能夠輔助後續的二進位程序分析。本文提出了二進位函數參數個數分析算法——Findargs,來識別PPC和MIPS指令集下二進位代碼中函數的參數個數。實驗結果表明,Findargs 具有較高的準確率,對於PPC指令集的二進位可執行文件,識別準確率達到 90.3%;對於 MIPS 指令集的二進位可執行文件,識別準確率稍低,為 86.0%。並且,本文與現有的工具radare2進行了對比,結果表明Findargs具有更高的準確率。由於Findargs依賴於對參數寄存器的分析,對於_cdecl、pascal、stdcall僅使用棧進行參數傳遞的方式適用性較差,但對多函數調用關係依據投票來選擇最準確的參數個數的機制可以應用到其他3種參數傳遞規範。這3種參數個數分析方法可以應用到對 fastcall 參數傳遞方式的分析。當使用 fastcall進行參數傳遞時,函數調用傳遞的參數個數超過參數寄存器個數時,參數傳遞的方式與上述3種方式相同。後續將考慮通過數據流分析追蹤參數的使用情況,來提高參數個數識別的準確率。
作者簡介
尹小康(1994-),男,河南周口人,數學工程與先進計算國家重點實驗室博士生,主要研究方向為網絡空間安全和逆向工程 。劉鎏(1998-),女,安徽合肥人,主要研究方向為網絡空間安全 。劉龍(1983-),男,河南尉氏人,數學工程與先進計算國家重點實驗室副教授,主要研究方向為網絡空間安全和機器學習 。劉勝利(1973-),男,河南周口人,博士,數學工程與先進計算國家重點實驗室教授,主要研究方向為網絡空間安全。
《網絡與信息安全學報》是由工業和信息化部主管,人民郵電出版社有限公司主辦的信息安全領域的學術刊物,現為中國網絡空間安全協會會刊,中國科技核心期刊、CCF推薦中文科技期刊。辦刊宗旨:匯聚安全創新思想,傳播學術研究成果,提升科學研發實力,服務國家信息安全。
中國網絡空間安全協會會刊
中國科技核心期刊
CCF推薦中文科技期刊
關注我們,查看更多內容