摘 要:控制流圖(CFG)是二進(jìn)制程序分析的基礎(chǔ)。傳統(tǒng)靜態(tài)分析方法構(gòu)建控制流圖速度快,代碼覆蓋率高,但不能解決間接跳轉(zhuǎn)問題;動(dòng)態(tài)分析方法能夠分析間接跳轉(zhuǎn),但代碼覆蓋率低、性能開銷大。為更加高效構(gòu)建完備的控制流圖,提出靜態(tài)動(dòng)態(tài)結(jié)合的混合分析方案。首先使用靜態(tài)分析獲取程序的初始控制流圖,采用模糊測(cè)試的方法獲取目標(biāo)程序不同執(zhí)行流的輸入數(shù)據(jù),誘導(dǎo)重寫后的目標(biāo)程序執(zhí)行獲取間接跳轉(zhuǎn)地址;融合靜態(tài)分析和動(dòng)態(tài)分析結(jié)果,從而高效構(gòu)建完備的控制流圖。通過(guò)實(shí)驗(yàn)驗(yàn)證,該混合分析方案相比于現(xiàn)有的混合分析方案,能夠構(gòu)建更加完整的控制流圖,相比于基于動(dòng)態(tài)二進(jìn)制插樁的混合分析方案效率更高。
關(guān)鍵詞: 控制流圖; 二進(jìn)制程序; 混合分析; 二進(jìn)制重寫
中圖分類號(hào): TP311 文獻(xiàn)標(biāo)志碼: A 文章編號(hào): 1001-3695(2025)02-032-0555-05
doi:10.19734/j.issn.1001-3695.2024.06.0281
Hybrid analysis based on binary rewriting to build control flow graph solution
Li Ziyou1, Huang Xiaofang1’, Yin Mingyong2
(1.School of Computer Science amp; Technology, Southwest University of Science amp; Technology, Mianyang Sichuan 621000, China; 2.Institute of Computer Application, Mianyang Sichuan 621000, China)
Abstract:CFG forms the foundation of binary program analysis.Traditional static analysis methods construct CFGs quickly with high code coverage but cannot resolve indirect jumps.Dynamic analysis methods,while capable of handling indirect jumps,suffer from low code coverage and high performance overhead.To efficiently construct a complete CFG,this paper proposed a hybrid analysis approach combining static and dynamic methods.This approach first used static analysis to generate the program’s initial CFG,then applied fuzz testing to obtain input data for different execution paths of the target program,inducing the modified program to execute and retrieve indirect jump addresses.By integrating the results of both static and dynamic analyses,the complete CFG was efficiently constructed.Experimental results confirm that this hybrid analysis approach constructs a more complete CFG compared to existing hybrid analysis methods,and is more efficient than hybrid analysis approaches based on dynamic binary instrumentation.
Key words:control flow graph(CFG); binary program; hybrid analysis; binary rewrite
在對(duì)軟件產(chǎn)品進(jìn)行安全性分析時(shí),許多軟件并未開源,目前大部分采用控制流圖(CFG)[1]對(duì)無(wú)源碼的軟件進(jìn)行二進(jìn)制代碼安全性分析。CFG用于描述程序在執(zhí)行過(guò)程中的控制流轉(zhuǎn)移關(guān)系,包括函數(shù)調(diào)用、條件分支和循環(huán)等,在代碼相似性檢測(cè)[2,3]、漏洞檢測(cè)[4~7]和惡意代碼變種[8,9]等多個(gè)領(lǐng)域都起著重要作用,也是二進(jìn)制程序的基礎(chǔ)結(jié)構(gòu)。同時(shí),許多二進(jìn)制程序分析技術(shù),如污點(diǎn)分析(taint analysis)[10,11]、符號(hào)執(zhí)行(symbolic execution)[12]等都要依賴程序的控制流圖。因此,構(gòu)建完整的控制流圖對(duì)軟件進(jìn)行二進(jìn)制代碼安全性分析具有重要意義。
1 相關(guān)工作
為構(gòu)建目標(biāo)二進(jìn)制程序的控制流圖,目前主要分為動(dòng)態(tài)、靜態(tài)和混合分析。動(dòng)態(tài)分析方法[13]使用輸入數(shù)據(jù)促使二進(jìn)制程序執(zhí)行,通過(guò)監(jiān)控程序執(zhí)行過(guò)程,構(gòu)建每個(gè)輸入產(chǎn)生執(zhí)行流。程序動(dòng)態(tài)執(zhí)行時(shí)能夠獲取執(zhí)行流某一時(shí)刻的上下文狀態(tài),從而構(gòu)建的控制流圖也是精確的,該方法缺點(diǎn)是代碼覆蓋率低,若要實(shí)現(xiàn)代碼高覆蓋率,需要大量有效的輸入。在使用靜態(tài)分析[14]方法時(shí),不需要大量有效輸入,只需要通過(guò)解析對(duì)應(yīng)平臺(tái)的文件結(jié)構(gòu),將解析到的指令和數(shù)據(jù)構(gòu)建控制流圖即可實(shí)現(xiàn),該方法的優(yōu)點(diǎn)是速度快,但是無(wú)法解決間接跳轉(zhuǎn)[15]問題。
Rimsa等人[16]使用了純動(dòng)態(tài)分析方法,能夠更加準(zhǔn)確捕捉程序的執(zhí)行行為,但純動(dòng)態(tài)控制流圖重建的質(zhì)量依賴于輸入的覆蓋率。如果輸入不能觸發(fā)某些代碼路徑,控制流圖構(gòu)建便不完善。葉志斌等人[17]提出靜態(tài)符號(hào)執(zhí)行的混合分析控制流圖構(gòu)建方案,使用符號(hào)執(zhí)行和程序切片技術(shù)對(duì)目標(biāo)程序進(jìn)行動(dòng)態(tài)分析,該方案需要采用求解器[18]求解路徑執(zhí)行流,導(dǎo)致對(duì)于復(fù)雜的程序路徑會(huì)造成約束求解開銷大、效率低等問題。對(duì)于靜態(tài)符號(hào)執(zhí)行產(chǎn)生的問題,Xie等人[19]采用動(dòng)態(tài)符號(hào)執(zhí)行的方法構(gòu)建二進(jìn)制程序的控制流圖,提高路徑覆蓋率,但仍存在路徑爆炸、約束求解復(fù)雜的問題。朱凱龍等人[20]在混合方法恢復(fù)控制流的方法中,采用動(dòng)態(tài)二進(jìn)制插樁的方式分析二進(jìn)制程序,該方法相比符號(hào)執(zhí)行能夠較快地分析程序的間接跳轉(zhuǎn)地址,但動(dòng)態(tài)二進(jìn)制插樁在運(yùn)行時(shí)對(duì)二進(jìn)制代碼進(jìn)行修改和監(jiān)視,這需要額外計(jì)算和內(nèi)存訪問開銷,會(huì)導(dǎo)致程序運(yùn)行速度變慢,因此,該方法不適合包含有較復(fù)雜控制流的程序。
針對(duì)以上問題,本文提出了基于二進(jìn)制重寫[21]的控制流圖構(gòu)建方法,采用模糊測(cè)試方法[22]生成大量有效的測(cè)試用例,輸入給重寫后的二進(jìn)制文件執(zhí)行,從而獲取間接跳轉(zhuǎn)地址,然后,將間接跳轉(zhuǎn)目標(biāo)地址與靜態(tài)分析得到的控制流圖相融合得到完整的控制流圖。相較于靜態(tài)符號(hào)執(zhí)行和動(dòng)態(tài)二進(jìn)制插樁技術(shù),該方法避免使用求解器進(jìn)行約束求解和動(dòng)態(tài)執(zhí)行時(shí)監(jiān)控每條執(zhí)行的語(yǔ)句帶來(lái)的巨大開銷,高效地構(gòu)建了二進(jìn)制程序完整的控制流圖。
2 混合分析控制流圖構(gòu)建
本文提出基于二進(jìn)制重寫的混合分析控制流圖構(gòu)建方案,并設(shè)計(jì)實(shí)現(xiàn)了控制流圖構(gòu)建工具HBRCFG,該工具的具體架構(gòu)如圖1所示。HBRCFG通過(guò)靜態(tài)分析初步提取目標(biāo)二進(jìn)制文件的控制流圖。首先,采用模糊測(cè)試的方法獲取程序的輸入測(cè)試用例。其次,在動(dòng)態(tài)分析階段,使用測(cè)試用例誘導(dǎo)重寫后的二進(jìn)制程序執(zhí)行,獲取間接跳轉(zhuǎn)的目的地址。最后,使用融合算法將動(dòng)態(tài)分析結(jié)果融合到靜態(tài)分析的控制流圖中,從而高效地構(gòu)建更加完整的控制流圖。
2.1 控制流圖構(gòu)建原理
2.1.1 控制流圖的定義
控制流圖可以抽象出程序的執(zhí)行路徑,用有向圖表示,記為G=(B,E),其中B是基本塊節(jié)點(diǎn)的集合,E是有向邊的集合。每個(gè)基本塊是程序指令的一個(gè)線性序列,具有單一的入口點(diǎn)和單一的出口點(diǎn)。基本塊可以有多個(gè)前驅(qū)和多個(gè)后繼。
在控制流圖中,每個(gè)節(jié)點(diǎn)bi代表一個(gè)基本塊,每條有向邊(bi,bj)表示程序控制從基本塊bi轉(zhuǎn)移到基本塊bj。存在一個(gè)后繼函數(shù)F將節(jié)點(diǎn)映射到直接后繼的集合F(bi)={bi|(bi,bj)∈E}。同樣,可以定義一個(gè)前驅(qū)函數(shù)F-1獲取一個(gè)節(jié)點(diǎn)的直接前驅(qū)集合??刂屏鲌D是連通的,從圖中的任何節(jié)點(diǎn)都可以通過(guò)連續(xù)應(yīng)用F或F-1到任何其他節(jié)點(diǎn),如圖2所示。
通過(guò)控制流圖,可以識(shí)別程序中的循環(huán)、條件分支、程序的入口和出口點(diǎn)等關(guān)鍵結(jié)構(gòu)。
2.1.2 間接跳轉(zhuǎn)原理
當(dāng)程序中發(fā)生的調(diào)用不是顯式指定的,而是在程序執(zhí)行過(guò)程中動(dòng)態(tài)值決定的,此時(shí)便會(huì)產(chǎn)生間接跳轉(zhuǎn)現(xiàn)象,在C/C++語(yǔ)言中,若使用函數(shù)指針、多態(tài)或動(dòng)態(tài)鏈接庫(kù)等方式調(diào)用指定功能便會(huì)發(fā)生間接跳轉(zhuǎn)。在匯編語(yǔ)言語(yǔ)言層面便是以寄存器為調(diào)用對(duì)象,寄存器的值在程序運(yùn)行時(shí)動(dòng)態(tài)生成,靜態(tài)分析構(gòu)建控制流圖無(wú)法獲取寄存器中的值,導(dǎo)致構(gòu)建控制流圖不完備。
2.1.3 動(dòng)態(tài)鏈接庫(kù)調(diào)用
動(dòng)態(tài)鏈接庫(kù)屬于位置無(wú)關(guān)代碼,其可以被加載到內(nèi)存的各個(gè)位置執(zhí)行,所以使用動(dòng)態(tài)鏈接庫(kù)函數(shù)時(shí),編譯后函數(shù)地址不會(huì)顯式指定,而是通過(guò)寄存器間接調(diào)用,如示例代碼1所示,在API動(dòng)態(tài)鏈接庫(kù)中實(shí)現(xiàn)Plus函數(shù),在main函數(shù)中加載動(dòng)態(tài)鏈接庫(kù)并調(diào)用Plus函數(shù),匯編代碼顯示call rax,靜態(tài)分析獲取不到rax的值,無(wú)法構(gòu)建函數(shù)間的跳轉(zhuǎn)關(guān)系。
示例代碼1 動(dòng)態(tài)鏈接庫(kù)調(diào)用
int main(){
typedef int(*lpPlus)(int,int);
lpPlus myPlus;
HMODULE hMod=LoadLibrary(\"api.dll\"); //加載動(dòng)態(tài)鏈接庫(kù)
plus=(lpPlus)GetProcAddress(hMod,\"?Plus@@YAHHH@Z\");
int a=plus(10,2); //call rax
return 0;}
//動(dòng)態(tài)鏈接庫(kù)api.dll:
#include \"apidll.h\"
int Plus(int x,int y){
return x+y;}
2.2 靜態(tài)分析構(gòu)建控制流圖
2.2.1 靜態(tài)反匯編
對(duì)于沒有源碼的二進(jìn)制程序,需要將二進(jìn)制結(jié)構(gòu)文件的指令部分進(jìn)行反匯編,將對(duì)應(yīng)的機(jī)器指令轉(zhuǎn)換成對(duì)應(yīng)匯編指令,按照代碼結(jié)構(gòu)形成基本塊,依據(jù)跳轉(zhuǎn)關(guān)系構(gòu)建出靜態(tài)的控制流圖。其中線性反匯編是一種常用的反匯編方法,從程序入口開始對(duì)二進(jìn)制代碼進(jìn)行逐字節(jié)反匯編,該方法不能區(qū)分代碼和數(shù)據(jù),若出現(xiàn)滿足指令格式的數(shù)據(jù)時(shí),也會(huì)被反匯編成指令,導(dǎo)致結(jié)果不準(zhǔn)確。
本文采用遞歸反匯編方法,遞歸反匯編可以在遇到跳轉(zhuǎn)指令時(shí),轉(zhuǎn)到跳轉(zhuǎn)的目的地址繼續(xù)進(jìn)行反匯編,根據(jù)控制流進(jìn)行反匯編的方式能夠清晰地區(qū)分代碼和數(shù)據(jù),反匯編工具IDA Pro[23]使用的就是采用遞歸反匯編的方法。
2.2.2 確定基本塊和邊
在控制流圖中,基本塊屬于原子節(jié)點(diǎn),其中包含一組二進(jìn)制代碼,該代碼順序執(zhí)行,從控制流開始進(jìn)入,只有一個(gè)出口,其中沒有其他分支跳轉(zhuǎn)和調(diào)用,如果出現(xiàn)其他分支,其后續(xù)代碼應(yīng)該劃分到下一個(gè)基本塊當(dāng)中。因此基本塊的定義如下:
入口指令:函數(shù)的第一條指令、跳轉(zhuǎn)指令的下一條指令、匯編代碼緊鄰的下一條指令。出口指令:跳轉(zhuǎn)指令、返回指令、目標(biāo)基本塊的上一條指令,其中跳轉(zhuǎn)指令包括間接跳轉(zhuǎn)和非間接跳轉(zhuǎn),CALL指令是無(wú)條件有返回的跳轉(zhuǎn)指令。
如果當(dāng)前基本塊的最后一條指令是間接跳轉(zhuǎn)指令,無(wú)法獲得間接跳轉(zhuǎn)的目的地址,當(dāng)前基本塊與后續(xù)基本塊的連接按照順序反匯編的結(jié)果進(jìn)行連接,如圖3(a)所示。在靜態(tài)分析時(shí)如果兩個(gè)基本塊存在直接跳轉(zhuǎn)關(guān)系,這兩個(gè)基本塊之間存在一條邊,如圖3(b)所示。
2.3 動(dòng)態(tài)分析獲取間接跳轉(zhuǎn)地址
在靜態(tài)分析結(jié)果中,并不能夠發(fā)現(xiàn)間接跳轉(zhuǎn)的地址,針對(duì)這個(gè)問題,本文使用二進(jìn)制重寫技術(shù)對(duì)間接跳轉(zhuǎn)地址插樁,獲取間接跳轉(zhuǎn)地址。為了獲取更多的控制流,需要在對(duì)二進(jìn)制重寫之前先進(jìn)行模糊測(cè)試,使用模糊測(cè)試[23]生成的測(cè)試用例誘導(dǎo)重寫后的二進(jìn)制程序執(zhí)行,并記錄執(zhí)行過(guò)程中的間接跳轉(zhuǎn)。
2.3.1 提高代碼覆蓋率
針對(duì)不同輸入數(shù)據(jù),程序可能會(huì)產(chǎn)生不同的執(zhí)行路徑,為提高程序代碼覆蓋率,使最終生成的控制流圖更加完整,本文采用模糊測(cè)試方法,獲取更多的有效輸入讓程序執(zhí)行不同路徑。文獻(xiàn)[17]中使用符號(hào)執(zhí)行的技術(shù)方法,對(duì)大規(guī)模的程序存在著復(fù)雜的約束,使用求解器求解,耗時(shí)嚴(yán)重,甚至無(wú)法求解。本文方案用模糊測(cè)試的方法能夠很好地避免該問題。
本文在模糊測(cè)試中采用基于覆蓋的灰盒模糊測(cè)試(CGF),輸入隨機(jī)生成的種子,并利用AFL++[24]遺傳算法的變異策略對(duì)輸入的種子進(jìn)行評(píng)估、變異,若該輸入能發(fā)現(xiàn)新的執(zhí)行路徑,則對(duì)該輸入繼續(xù)變異。為避免變異產(chǎn)生的大量測(cè)試用例讓二進(jìn)制程序重復(fù)執(zhí)行相同路徑,方案只收集能夠讓二進(jìn)制程序執(zhí)行不同路徑的測(cè)試用例,并標(biāo)記為該二進(jìn)制程序的測(cè)試用例。
2.3.2 獲取間接跳轉(zhuǎn)地址
將模糊測(cè)試生成的測(cè)試用例依次輸入給指定的二進(jìn)制程序,程序在執(zhí)行過(guò)程中記錄間接跳轉(zhuǎn)地址。HBRCFG使用二進(jìn)制重寫[12]的方式,提前對(duì)需要提取CFG的二進(jìn)制程序進(jìn)行重寫,重寫增加的代碼用來(lái)監(jiān)控程序執(zhí)行過(guò)程中遇到的間接跳轉(zhuǎn)。如果遇到間接跳轉(zhuǎn)便記錄下間接跳轉(zhuǎn)的目的地址。朱凱龍等人[20]使用動(dòng)態(tài)插樁的方式對(duì)程序中會(huì)發(fā)生間接跳轉(zhuǎn)的指令進(jìn)行監(jiān)控,該方法會(huì)在程序執(zhí)行時(shí)對(duì)每條執(zhí)行指令進(jìn)行插樁,隨后再判斷指令是否符合要求,該方法損失了執(zhí)行效率。二進(jìn)制重寫技術(shù)直接在原二進(jìn)制文件中寫入新增的代碼,當(dāng)使用測(cè)試用例誘導(dǎo)執(zhí)行時(shí),直接順序執(zhí)行二進(jìn)制指令,相比動(dòng)態(tài)二級(jí)制插樁的方法效率更高。
2.4 控制流圖構(gòu)建優(yōu)化算法
本文將靜態(tài)分析得到的控制流圖與動(dòng)態(tài)分析得到的間接跳轉(zhuǎn)地址融合,從而完善控制流圖。在進(jìn)行靜態(tài)分析時(shí),只能把靜態(tài)的二進(jìn)制文件解析后,根據(jù)機(jī)器碼翻譯成對(duì)應(yīng)的匯編指令,但無(wú)法執(zhí)行指令。若分析的二進(jìn)制程序中存在函數(shù)遞歸調(diào)用,靜態(tài)分析過(guò)程中并不能理解何時(shí)結(jié)束遞歸調(diào)用,所以要在靜態(tài)分析控制流圖時(shí)加上限制條件,從而避免靜態(tài)分析時(shí)產(chǎn)生無(wú)限循環(huán)。
2.4.1 避免靜態(tài)分析遞歸循環(huán)算法
在二進(jìn)制程序中若存在遞歸調(diào)用,靜態(tài)遞歸反匯編時(shí)無(wú)法判斷程序的出口,若通過(guò)call指令的操作數(shù)來(lái)構(gòu)建后續(xù)的控制流圖,將會(huì)導(dǎo)致構(gòu)建程序陷入無(wú)限循環(huán)當(dāng)中,所以需要破除遞歸調(diào)用導(dǎo)致的循環(huán),避免遞歸循環(huán)的方法如算法1所示。該算法遍歷每個(gè)函數(shù)的基本塊,如果不是間接跳轉(zhuǎn)分支便獲取跳轉(zhuǎn)目標(biāo)地址,如果目標(biāo)地址指向本函數(shù)地址,便不再分析該分支的后續(xù)控制流。
算法1 避免遞歸循環(huán)
輸入:函數(shù)控制流圖。
輸出:非間接跳轉(zhuǎn)目標(biāo)基本塊。
a) fbbs=function.bbs()
b) for bb in fbbs //遍歷函數(shù)基本塊
c) if bb.endins not INDIRECT //基本塊最后不是間接跳轉(zhuǎn)指令
d) target=getTarget(bb) //獲取跳轉(zhuǎn)目標(biāo)
e)
if target!=function.addr //目標(biāo)不是自身
f)
targets.append(target) //加入后續(xù)構(gòu)建隊(duì)列
g) return targets
2.4.2 融合控制流圖算法
本文提出融合算法,將動(dòng)態(tài)分析的間接跳轉(zhuǎn)地址融合到靜態(tài)分析得到的控制流圖當(dāng)中,從而完善目標(biāo)程序的控制流圖,具體如算法2所示,動(dòng)態(tài)分析時(shí)將獲取間接跳轉(zhuǎn)的指令地址和間接跳轉(zhuǎn)的目的地址,循環(huán)篩選出間接跳轉(zhuǎn)指令所在的基本塊,將該基本塊的目標(biāo)基本塊融合到控制流圖當(dāng)中。
算法2 融合控制流圖
輸入:靜態(tài)分析控制流圖;間接跳轉(zhuǎn)指令地址和間接跳轉(zhuǎn)目標(biāo)。
輸出:融合間接跳轉(zhuǎn)的控制流圖。
a) for bb in sCFG.blocks:
b)
if ins_address in bb.addrscope:
c) if bb.endins is INDIRECT_ins: //判斷結(jié)尾指令是跳轉(zhuǎn)指令
d) targets=getTargetAddress(bb.endins) //獲取所有目標(biāo)
e) for t in targets:
f)
connect bb to t
g)connect t to bb.successors //t繼承bb的所有后繼
h)disconnect bb to bb.successors //斷開bb之前的后繼
i) return sCFG
如圖4所示,因?yàn)樵陟o態(tài)分析時(shí),已經(jīng)將間接調(diào)轉(zhuǎn)指令作為基本塊的出口指令,所以在融合時(shí),便只需要檢查基本塊的出口指令是否是間接跳轉(zhuǎn)指令,若滿足則獲取該間接跳轉(zhuǎn)的目標(biāo)地址的基本塊。隨后將該基本塊的后繼連接關(guān)系繼承給間接跳轉(zhuǎn)的目標(biāo)基本塊,并在該基本塊與目標(biāo)基本塊之間添加一條邊,實(shí)現(xiàn)與目標(biāo)基本塊的鏈接。這里的間接跳轉(zhuǎn)的目標(biāo)可能有多個(gè),所以需要依次處理該基本塊與目標(biāo)基本塊之間的關(guān)系,完善靜態(tài)分析的結(jié)果,從而制備出更加精確的控制流圖。
3 實(shí)驗(yàn)
3.1 實(shí)驗(yàn)環(huán)境
Kali2022 64 bit操作系統(tǒng),CPU使用Intel Core i3-4170HQ @3.70 GHz,內(nèi)存為DDR3 8 GB。先使用手工構(gòu)造的包含間接跳轉(zhuǎn)地址的程序驗(yàn)證HBRCFG的有效性;實(shí)驗(yàn)數(shù)據(jù)使用網(wǎng)絡(luò)安全挑戰(zhàn)賽[25](CGC)中部分二進(jìn)制程序。
3.2 實(shí)驗(yàn)結(jié)果分析
3.2.1 有效性分析
手工構(gòu)造包含的間接跳轉(zhuǎn)的程序源碼如示例代碼2所示,該程序通過(guò)輸入的值來(lái)判斷需要調(diào)用的函數(shù),其中函數(shù)指針變量的值可能是func1函數(shù)地址值或者是func2函數(shù)地址值,通過(guò)編譯之后,使用函數(shù)指針變量indirect對(duì)func1和func2的函數(shù)調(diào)用時(shí),在匯編層面調(diào)用指令為CALL RCX,調(diào)用的目的地址是程序運(yùn)行時(shí)寄存器RCX中的值,寄存器的名稱并不能指導(dǎo)靜態(tài)分析構(gòu)建后續(xù)的控制流圖,在程序安全性分析時(shí),間接跳轉(zhuǎn)函數(shù)中的問題就無(wú)法被分析。
示例代碼2 程序pointer_call源代碼
int func1();int func2();void func(int a,int b);
int main(){
int a,b;
scanf(\"%d%d\",amp;a,amp;b);
func(a,b);
return 0;}
int func1(){return 1;}
int func2(){return 0;}
void func(int a,int b){
int(*indirect)(); //定義函數(shù)指針
if (a gt; b) indirect=func1; //根據(jù)條件給指針賦值
else indirect=func2;
indirect(); //CALL RCX}
在對(duì)pointer_call源代碼編譯鏈接之后,通過(guò)靜態(tài)反匯編的方式構(gòu)建出程序的控制流圖。圖5是其中func函數(shù)的控制流圖,可以發(fā)現(xiàn)基本塊和邊都滿足定義的規(guī)則。因?yàn)殚g接跳轉(zhuǎn)關(guān)系發(fā)生在func函數(shù)當(dāng)中,所以func函數(shù)中出現(xiàn)了call rdx形式的間接函數(shù)調(diào)用。
如圖6所示是程序pointer_call融合后的控制流圖,為了方便說(shuō)明問題,這里展示了發(fā)生間接跳轉(zhuǎn)的func函數(shù)部分,虛線的邊是發(fā)現(xiàn)間接跳轉(zhuǎn)。在圖中0x40116a是func通過(guò)函數(shù)指針調(diào)用函數(shù)的基本塊,指令是call rdx,rdx取值不同將會(huì)調(diào)用不同的函數(shù),本文通過(guò)動(dòng)態(tài)分析得到rdx可能的取值。當(dāng)a>b時(shí),函數(shù)指針indirect賦值為func2函數(shù)地址,此時(shí)rdx的值為0x401126。當(dāng)a<b時(shí),函數(shù)指針indirect賦值為func2函數(shù)地址,此時(shí)rdx的值為0x401131。使用二進(jìn)制重寫的混合分析方法能夠分析出間接調(diào)轉(zhuǎn)關(guān)系,并且對(duì)于同一基本塊的多個(gè)間接跳轉(zhuǎn)關(guān)系同樣能夠識(shí)別,HBRCFG能夠構(gòu)建包含間接跳轉(zhuǎn)的完整的控制流圖。
本文從二進(jìn)制程序的入口開始分析,由入口代碼開始構(gòu)建程序的控制流圖。統(tǒng)計(jì)分析靜態(tài)分析工具IDA和HBRCFG對(duì)示例程序的執(zhí)行情況,結(jié)果如表1所示,pointer_callh、pointer_calli分別表示HBRCFG和IDA的分析結(jié)果。表中F表示由程序入口開始分析得到的函數(shù)數(shù)量,V表示構(gòu)建控制流圖中基本塊數(shù)量,E表示連接關(guān)系的數(shù)量,I表示HBRCFG發(fā)現(xiàn)的間接跳轉(zhuǎn)的數(shù)量。從統(tǒng)計(jì)結(jié)果中可以觀察出,HBRCFG能夠發(fā)現(xiàn)目標(biāo)程序中的間接跳轉(zhuǎn),相比于靜態(tài)分析能夠發(fā)現(xiàn)更多的函數(shù)體。所以HBRCFG能夠有效地識(shí)別間接跳轉(zhuǎn)關(guān)系,構(gòu)建更加完整的控制流圖。
3.2.2 性能分析
在大規(guī)模程序分析時(shí),需要考慮程序分析效率,實(shí)驗(yàn)將進(jìn)一步驗(yàn)證本文算法的性能。將采用實(shí)驗(yàn)環(huán)境中的數(shù)據(jù)(CGC),使用CFGConstructor[20]進(jìn)行混合分析構(gòu)建控制流圖的結(jié)果如表2所示,本文算法的分析結(jié)果如表3所示。其中S是每個(gè)測(cè)試程序的大小,I是發(fā)現(xiàn)間接跳轉(zhuǎn)的數(shù)量,相比于CFGConstructor,HBRCFG能夠構(gòu)建Rn間接跳轉(zhuǎn)函數(shù)中的后續(xù)函數(shù)調(diào)用控制流,進(jìn)一步構(gòu)建完備的控制流圖。并且統(tǒng)計(jì)了Ru后續(xù)調(diào)用中不重復(fù)的函數(shù)數(shù)量。Fh-c、Vh-c、Eh-c、Ih-c表示HBRCFG比CFGConstructor多發(fā)現(xiàn)的函數(shù)、基本塊、邊和間接跳轉(zhuǎn)關(guān)系的百分比。由表中的結(jié)果可以看出,CFGConstructor能夠發(fā)現(xiàn)大部分的函數(shù)和間接跳轉(zhuǎn)關(guān)系,對(duì)于間接跳轉(zhuǎn)函數(shù)中產(chǎn)生的跳轉(zhuǎn)關(guān)系仍不能構(gòu)建。HBRCFG能夠在動(dòng)態(tài)執(zhí)行后發(fā)現(xiàn)間接跳轉(zhuǎn)關(guān)系,并將對(duì)應(yīng)的跳轉(zhuǎn)關(guān)系融合到靜態(tài)分析的控制流圖當(dāng)中,且能夠從發(fā)現(xiàn)的間接跳轉(zhuǎn)的可達(dá)函數(shù)中繼續(xù)構(gòu)建其發(fā)生的調(diào)用關(guān)系Rn。實(shí)驗(yàn)結(jié)果中,netstorage和CableGrind程序HBRCFG能夠分析出大量間接跳轉(zhuǎn)的后續(xù)函數(shù)調(diào)用,完善控制流圖邊的構(gòu)建,進(jìn)一步制備更加完備控制流圖。就兩個(gè)工具分析出的函數(shù)、節(jié)點(diǎn)、邊和間接跳轉(zhuǎn)函數(shù)的數(shù)量來(lái)說(shuō),本文算法比CFGConstructor混合分析的效果更好。本文算法平均能夠比CFGConstructor多發(fā)現(xiàn)35.9%的函數(shù),60.7%的基本塊,60%的邊和38%的間接跳轉(zhuǎn)。
對(duì)HBRCFG的分析效率進(jìn)行評(píng)估,實(shí)驗(yàn)選擇使用AFL++對(duì)目標(biāo)程序進(jìn)行模糊測(cè)試生成測(cè)試用例。為生成更多有效的測(cè)試用例集,模糊測(cè)試停止時(shí)間根據(jù)afl-fuzz的狀態(tài)決定,若在半小時(shí)后仍不能發(fā)現(xiàn)新的執(zhí)行路徑就停止模糊測(cè)試。使用測(cè)試用例誘導(dǎo)重寫后的程序執(zhí)行,記錄程序開始執(zhí)行到完成控制流圖融合所需的時(shí)間,如表4所示,記錄HBRCFG每次分析的時(shí)間t單位秒,以及每次使用測(cè)試用例數(shù)量T??梢钥闯觯w積越大、執(zhí)行路徑更復(fù)雜的程序,需要的測(cè)試用例的數(shù)量也會(huì)越多。為了更高效地進(jìn)行動(dòng)態(tài)分析,實(shí)驗(yàn)只保存能夠讓程序執(zhí)行不同路徑的測(cè)試用例。
表4的th結(jié)果中可以看出,HBRCFG更夠更加高效地構(gòu)建程序的完整控制流圖,實(shí)驗(yàn)程序Grit體積186 KB大小,HBRCFG能夠在11.38 s完成完整的控制流圖的構(gòu)建,該程序使用的測(cè)試用例有2 029個(gè),構(gòu)建的控制流圖中包含81個(gè)函數(shù),函數(shù)中包含1 270個(gè)基本塊和1 950條連接。CFGConstructor使用動(dòng)態(tài)插樁的方式動(dòng)態(tài)分析表4中tp所示,同樣條件下將耗時(shí)1 022.36 s,時(shí)間效率將提升89倍。如果采用靜態(tài)符號(hào)執(zhí)行的方法恢復(fù)目標(biāo)程序的控制流圖,將產(chǎn)生約束復(fù)雜,求解路徑爆炸,甚至無(wú)解的問題;使用動(dòng)態(tài)二進(jìn)制插樁的方法時(shí),誘導(dǎo)程序動(dòng)態(tài)執(zhí)行時(shí),監(jiān)控程序執(zhí)行的指令,開銷太大。所以,HBRCFG能夠在開銷更小的情況下構(gòu)建出目標(biāo)程序完成的控制流圖。
4 結(jié)束語(yǔ)
本文提出使用基于二進(jìn)制重寫的混合分析構(gòu)建二進(jìn)制程序的控制流圖方案,設(shè)計(jì)并實(shí)現(xiàn)了控制流圖構(gòu)建工具HBRCFG。相較于以往的控制流圖構(gòu)建方案,使用二進(jìn)制重寫技術(shù)提高了動(dòng)態(tài)執(zhí)行效率,改進(jìn)了靜態(tài)分析時(shí)構(gòu)建控制流圖基本塊的規(guī)則,使其能夠在融合分析結(jié)果時(shí)更加高效。最終實(shí)驗(yàn)表明,相比于CFGConstructor,HBRCFG能夠在目標(biāo)程序中平均多發(fā)現(xiàn)35.9%的函數(shù),60.7%的基本塊,60%的邊和38%的間接跳轉(zhuǎn)。并且在保證控制流圖完整性的情況下,相較于動(dòng)態(tài)二進(jìn)制插樁的動(dòng)態(tài)分析方案,本方案時(shí)間提升了38倍,更能應(yīng)對(duì)大規(guī)模的程序分析。下一步研究方向,將針對(duì)影響代碼覆蓋率的字節(jié)進(jìn)行變異,減少無(wú)效輸入,通過(guò)較少的輸入數(shù)據(jù)發(fā)現(xiàn)更多的執(zhí)行路徑,提高模糊測(cè)試效率,從而更加高效地構(gòu)建更加完整的控制流圖。
參考文獻(xiàn):
[1]Xu Liang,Sun Fangqi,Su Zhendong.Constructing precise control flow graphs from binaries[D].Davis,CA:University of California,Davis,2009:14-23.
[2]孫祥杰,魏強(qiáng),王奕森,等.代碼相似性檢測(cè)技術(shù)綜述[J].計(jì)算機(jī)應(yīng)用,2024,44(4):1248-1258.(Sun Xiangjie,Wei Qiang,Wang Yisen,et al.Survey of code similarity detection technology[J].Journal of Computer Applications,2024,44(4):1248-1258.)
[3]Yu Zeping,Cao Rui,Tang Qiyi,et al.Order matters:semantic-aware neural networks for binary code similarity detection[C]//Proc of AAAI Conference on Artificial Intelligence.Palo Alto,CA:AAAI Press,2020:1145-1152.
[4]Wang Yan,Jia Peng,Peng Xi,et al.BinVulDet:detecting vulnerability in binary program via decompiled pseudo code and BiLSTM-attention[J].Computers amp; Security,2023,125:103023.
[5]Hin D,Kan A,Chen Huaming,et al.LineVD:statement-level vulnerability detection using graph neural networks[C]//Proc of the 19th International Conference on Mining Software Repositories.New York:ACM Press,2022:596-607.
[6]Li Litao,Ding S H H,Tian Yuan,et al.VulANalyzeR:explainable binary vulnerability detection with multi-task learning and attentional graph convolution[J].ACM Trans on Privacy and Security,2023,26(3):1-25.
[7]Luo Zhenhao,Wang Pengfei,Wang Baosheng,et al.VulHawk:cross-architecture vulnerability detection with entropy-based binary code search[C]//Proc of NDSS.2023.
[8]Seneviratne S,Shariffdeen R,Rasnayaka S,et al.Self-supervised vision Transformers for malware detection[J].IEEE Access,2022,10:103121-103135.
[9]Lucas K,Pai S,Lin Weiran,et al.Adversarial training for Raw-Binary malware classifiers[C]//Proc of the 32nd USENIX Security Sympo-sium.Berkeley,CA:USENIX Association,2023:1163-1180.
[10]Chen Sanchuan,Lin Zhiqiang,Zhang Yinqian.SelectiveTaint:efficient data flow tracking with static binary rewriting[C]//Proc of the 30th USENIX Security Symposium.Berkeley,CA:USENIX Association,2021:1665-1682.
[11]Hough K,Bell J.A practical approach for dynamic taint tracking with control-flow relationships[J].ACM Trans on Software Enginee-ring and Methodology,2021,31(2):1-43.
[12]Van Bertrand O C H,Legay A.Malware analysis with symbolic execution and graph kernel[C]//Proc of Nordic Conference on Secure IT Systems.Cham:Springer International Publishing,2022:292-310.
[13]Wu Qingyang,Huo Quanrui,Ning Yuqiao,et al.A survey of binary code security analysis[C]//Proc of the 6th International Conference on Data Science and Information Technology.Piscataway,NJ:IEEE Press,2023:42-49.
[14]Zhou Anshunkang,Ye Chengfeng,Huang Heqing,et al.Plankton:re-conciling binary code and debug information[C]//Proc of the 29th ACM International Conference on Architectural Support for Programming Languages and Operating Systems.New York:ACM Press,2024:912-928.
[15]Wang Hao,Qu Wenjie,Katz G,et al.jTrans:jump-aware Transformer for binary code similarity detection[C]//Proc of the 31st ACM SIGSOFT International Symposium on Software Testing and Analysis.New York:ACM Press,2022:1-13.
[16]Rimsa A,Amaral J N,Quint?o F M.Efficient and precise dynamic construction of control flow graphs[C]//Proc of XXIII Brazilian Symposium on Programming Languages.New York:ACM Press,2019:19-26.
[17]葉志斌,姜鑫,史大偉.一種面向二進(jìn)制的控制流圖混合恢復(fù)方法[J].計(jì)算機(jī)應(yīng)用研究,2018,35(7):2168-2171.(Ye Zhibin,Jiangxin,Shi Dawei.Combined method of constructing binary-oriented control flow graph[J].Application Research of Computers,2018,35(7):2168-2171.)
[18]Microsoft Research.Z3:an efficient SMT solver[EB/OL].[2024-04-26].https://github.com/Z3Prover/z3.
[19]Xie Bailin,Li Qi,Luo Jiabin.Program vulnerability mining system based on symbolic execution[C]//Proc of the 7th International Conference on Intelligent Information Technology.New York:ACM Press,2022:83-89.
[20]朱凱龍,陸余良,黃暉,等.基于混合分析的二進(jìn)制程序控制流圖構(gòu)建方法[J].浙江大學(xué)學(xué)報(bào):工學(xué)版,2019,53(5):829-836.(Zhu Kailong,Lu Yuliang,Huang Hui,et al.Construction approach for control flow graph from binaries using hybrid analysis[J].Journal of Zhejiang University:Engineering Science,2019,53(5):829-836.)
[21]Duck G J,Gao Xiang,Roychoudhury A.Binary rewriting without control flow recovery[C]//Proc of the 41st ACM SIGPLAN Conference on Programming Language Design and Implementation.New York:ACM Press,2020:151-163.
[22]Dutra R,Gopinath R,Zeller A.FormatFuzzer:effective fuzzing of binary file formats[J].ACM Trans on Software Engineering and Methodology,2023,33(2):1-29.
[23]Hex-Rays.IDAPro disassembler[EB/OL].[2024-04-20].https://www.hex-rays.com/.
[24]Fioraldi A,Maier D,Eiβfeldt H,et al.AFL++:combining incremental steps of fuzzing research[C]//Proc of the 14th USENIX Workshop on Offensive Technologies.Berkeley,CA:USENIX Association,2020:10.
[25]DARPA.DARPA cyber grand challenge[EB/OL].[2024-05-01].https://github.com/CyberGrandChallenge.