• 
    

    
    

      99热精品在线国产_美女午夜性视频免费_国产精品国产高清国产av_av欧美777_自拍偷自拍亚洲精品老妇_亚洲熟女精品中文字幕_www日本黄色视频网_国产精品野战在线观看

      ?

      SiCsFuzzer:基于稀疏插樁的閉源軟件模糊測(cè)試方法

      2022-08-16 09:34:06劉麗艷鄒燕燕周建華樸愛(ài)花
      信息安全學(xué)報(bào) 2022年4期
      關(guān)鍵詞:基本塊插樁測(cè)試用例

      劉麗艷 ,李 豐 ,鄒燕燕,5 ,周建華,5 ,樸愛(ài)花 ,劉 峰 ,霍 瑋,5

      1 中國(guó)科學(xué)院信息工程研究所信息安全國(guó)家重點(diǎn)實(shí)驗(yàn)室,北京 中國(guó) 100093

      2 中國(guó)科學(xué)院信息工程研究所,北京 中國(guó) 100093

      3 中國(guó)科學(xué)院網(wǎng)絡(luò)測(cè)評(píng)技術(shù)重點(diǎn)實(shí)驗(yàn)室,北京 中國(guó) 100195

      4 網(wǎng)絡(luò)安全防護(hù)技術(shù)北京市重點(diǎn)實(shí)驗(yàn)室,北京 中國(guó) 100195

      5 中國(guó)科學(xué)院大學(xué)網(wǎng)絡(luò)空間安全學(xué)院,北京 中國(guó) 100049

      1 引言

      模糊測(cè)試是目前發(fā)現(xiàn)軟件漏洞的最有效方法之一。它通過(guò)向目標(biāo)程序提供大量的經(jīng)過(guò)特殊構(gòu)造的測(cè)試用例,并在程序運(yùn)行過(guò)程中監(jiān)控程序的執(zhí)行行為,以程序是否發(fā)生異常行為為標(biāo)志,來(lái)發(fā)現(xiàn)目標(biāo)程序可能存在的安全漏洞。為了快速發(fā)現(xiàn)軟件潛在的漏洞,以AFL[1]為代表的模糊測(cè)試工具[2-4]通過(guò)跟蹤覆蓋率來(lái)指導(dǎo)測(cè)試用例的變異,力求變異生成的測(cè)試用例能夠覆蓋到目標(biāo)程序中更多的未測(cè)代碼,從而更有效的發(fā)現(xiàn)目標(biāo)程序中潛在的漏洞。上述模糊測(cè)試方法被稱為基于覆蓋率反饋的模糊測(cè)試方法。

      給定目標(biāo)程序P 以及一系列種子輸入I,目前主流的基于覆蓋率反饋的模糊測(cè)試工具,其工作流程可以分為以下三個(gè)步驟:(1)變異:通過(guò)位翻轉(zhuǎn)、刪除、替換等一系列的策略對(duì)種子輸入進(jìn)行變異,生成大量新的輸入;(2)跟蹤與反饋:將新生成的輸入交由目標(biāo)程序執(zhí)行,通過(guò)程序插樁等技術(shù)跟蹤目標(biāo)程序在該輸入下的代碼覆蓋率信息(如:節(jié)點(diǎn)覆蓋率、邊覆蓋率等),并根據(jù)所反饋的覆蓋率變化情況,對(duì)于覆蓋了新路徑的輸入,在后續(xù)的變異過(guò)程中賦給其更高的優(yōu)先級(jí);(3)監(jiān)控:監(jiān)控程序執(zhí)行過(guò)程中的異常行為(如:程序崩潰等)以及觸發(fā)異常的輸入,作為漏洞分析及定位的依據(jù)。由此可見(jiàn),跟蹤測(cè)試用例的代碼覆蓋率是決定模糊測(cè)試效能的關(guān)鍵環(huán)節(jié)之一。

      然而,跟蹤測(cè)試用例的代碼覆蓋率也會(huì)為模糊測(cè)試引入額外的性能開(kāi)銷,甚至成為模糊測(cè)試性能開(kāi)銷的主要來(lái)源。對(duì)于開(kāi)源程序,可通過(guò)編譯時(shí)插樁插入用于在運(yùn)行時(shí)獲取覆蓋信息的代碼。但對(duì)于閉源程序,尤其是Windows 平臺(tái)的二進(jìn)制程序,需要通過(guò)動(dòng)態(tài)插樁[5]、二進(jìn)制重寫(xiě)[6]或硬件輔助[7-8]的方法來(lái)追蹤覆蓋率信息。其中,基于硬件輔助的方法幾乎不引入額外開(kāi)銷,但依賴于平臺(tái)硬件支持,不易擴(kuò)展。最近的工作[9]表明,對(duì)于Linux 平臺(tái)上的閉源目標(biāo)程序,AFL 跟蹤代碼覆蓋率的開(kāi)銷高達(dá)13 倍。本文的實(shí)驗(yàn)分析(詳見(jiàn)第2 章和第5 章)也表明,對(duì)于Windows 平臺(tái)上的二進(jìn)制程序,跟蹤覆蓋率的開(kāi)銷是程序正常運(yùn)行的3~18.9 倍,平均占執(zhí)行單個(gè)測(cè)試用例時(shí)間的82%。

      相關(guān)工作也就模糊測(cè)試過(guò)程中跟蹤覆蓋率開(kāi)銷的緩解提出了改進(jìn)方案。代表性方案UnTracer[9]借助于輕量級(jí)檢測(cè)和采用基于靜態(tài)二進(jìn)制重寫(xiě)的覆蓋率跟蹤技術(shù),在所選數(shù)據(jù)集上僅相對(duì)程序正常執(zhí)行時(shí)間引入了0.3%的額外開(kāi)銷。其采用的輕量級(jí)檢測(cè)避免了對(duì)沒(méi)有價(jià)值的種子進(jìn)行覆蓋率跟蹤,但是對(duì)于有價(jià)值的種子,UnTracer 仍然面對(duì)跟蹤覆蓋率的開(kāi)銷,而其使用的基于靜態(tài)二進(jìn)制重寫(xiě)的覆蓋率跟蹤技術(shù)在 Windows 平臺(tái)上缺乏魯棒性,無(wú)法擴(kuò)展到Windows 平臺(tái)閉源軟件的模糊測(cè)試中。新進(jìn)提出的二進(jìn)制重寫(xiě)技術(shù)RetroWrite[10],其速度是QEMU 的4.5 倍,但僅適用于64 位Linux 平臺(tái)上的地址無(wú)關(guān)代碼。采用二進(jìn)制動(dòng)態(tài)跟蹤代碼覆蓋率雖然開(kāi)銷較高,但確是目前最具普適性的方法。

      本文針對(duì)閉源軟件(尤其是Windows 平臺(tái)上閉源軟件)模糊測(cè)試過(guò)程中因跟蹤代碼覆蓋率引入的額外時(shí)間開(kāi)銷問(wèn)題,提出了一種基于稀疏插樁跟蹤的模糊測(cè)試方法,在不影響覆蓋率計(jì)算精度的前提下,采用基于稀疏插樁的跟蹤策略,僅對(duì)目標(biāo)程序中覆蓋率不可推導(dǎo)的基本塊或分支進(jìn)行插樁跟蹤,并根據(jù)跟蹤結(jié)果推導(dǎo)其余基本塊或分支的被覆蓋情況,同時(shí)結(jié)合“預(yù)熱”優(yōu)化,避免因動(dòng)態(tài)插樁平臺(tái)反復(fù)啟動(dòng)以及對(duì)目標(biāo)程序代碼的重復(fù)翻譯所引入的時(shí)間開(kāi)銷。通過(guò)剔除閉源軟件覆蓋率跟蹤過(guò)程中的冗余開(kāi)銷,提高閉源程序模糊測(cè)試的效率,進(jìn)而提高針對(duì)閉源程序的漏洞發(fā)現(xiàn)效率。

      其中,基于稀疏插樁的覆蓋率跟蹤策略以傳統(tǒng)程序分析技術(shù)的支配關(guān)系作為插樁位置選擇以及覆蓋率推導(dǎo)的基礎(chǔ)。目前主流的基于覆蓋率反饋的模糊測(cè)試工具默認(rèn)對(duì)目標(biāo)程序中的所有基本塊或分支進(jìn)行插樁。但并非所有插樁位置都是必要的。以圖1所示的程序片段及其對(duì)應(yīng)的控制流圖(CFG)為例。根據(jù)后支配關(guān)系,如果測(cè)試用例覆蓋了基本塊6,則必然也覆蓋了基本塊1。換而言之,基本塊1 是否被覆蓋可以通過(guò)對(duì)基本塊6 的插樁跟蹤結(jié)果推導(dǎo)出來(lái)。因此,在對(duì)基本塊6 進(jìn)行插樁的同時(shí),再對(duì)基本塊1插樁是冗余的。文獻(xiàn)[11]所述的程序優(yōu)化技術(shù)也表明,可以找到目標(biāo)程序所有基本塊/分支的一個(gè)子集,該子集中的基本塊/分支可以推導(dǎo)出目標(biāo)程序控制流圖上的所有基本塊/分支。文獻(xiàn)[11]的實(shí)驗(yàn)也表明,對(duì)于選擇的8 個(gè)C 程序,只需要覆蓋目標(biāo)程序的特定的32%的分支,即可確保100%的分支覆蓋。本文第5章的實(shí)驗(yàn)也顯示,平均只需要對(duì)目標(biāo)程序的40.61%的分支進(jìn)行插樁,就可以推導(dǎo)出目標(biāo)程序中其他分支是否被覆蓋??梢?jiàn),通過(guò)支配關(guān)系指導(dǎo)的稀疏插樁,可以有效的減少不必要的插樁與追蹤。本文在文獻(xiàn)[11]工作的基礎(chǔ)上,擴(kuò)展了對(duì)二進(jìn)制代碼分析以及動(dòng)態(tài)運(yùn)行時(shí)插樁的支持,以適應(yīng)閉源程序的模糊測(cè)試需求。

      如前所述,對(duì)閉源程序的覆蓋率跟蹤可以采取動(dòng)態(tài)二進(jìn)制插樁或基于硬件輔助的技術(shù)。其中,動(dòng)態(tài)二進(jìn)制插樁相對(duì)基于硬件輔助的技術(shù)可以適應(yīng)更多的平臺(tái),因此具有更強(qiáng)的魯棒性。代表性的模糊測(cè)試工具AFL 和Vuzzer[12]分別使用QEMU 和Pin[13]對(duì)閉源程序進(jìn)行插樁。為使所提出的方法及對(duì)應(yīng)工具能夠適應(yīng)更多的平臺(tái),尤其是支持對(duì)Windows 平臺(tái)上閉源程序的高效模糊測(cè)試,本文也采用動(dòng)態(tài)二進(jìn)制插樁技術(shù)跟蹤代碼覆蓋率。但文獻(xiàn)[9]的統(tǒng)計(jì)顯示,QEMU 引入的額外開(kāi)銷約為目標(biāo)程序正常執(zhí)行時(shí)間的10 倍。本文的實(shí)驗(yàn)結(jié)果也表明,Pin 空載所引入的額外開(kāi)銷是程序正常運(yùn)行時(shí)間的2倍以上,其中52%的開(kāi)銷來(lái)源于動(dòng)態(tài)代碼翻譯。由于動(dòng)態(tài)插樁平臺(tái)每執(zhí)行一個(gè)測(cè)試用例,都需要對(duì)目標(biāo)程序重新進(jìn)行動(dòng)態(tài)代碼翻譯,由此帶來(lái)冗余的開(kāi)銷?!邦A(yù)熱”優(yōu)化的引入可以使先前生成的目標(biāo)程序代碼被所有測(cè)試用例共享,從而避免上述冗余開(kāi)銷。

      基于上述方法實(shí)現(xiàn)的基于稀疏插樁的閉源軟件模糊測(cè)試原型SiCsFuzzer。對(duì)于Windows 平臺(tái)上的9個(gè)黑盒二進(jìn)制目標(biāo)程序,在不影響覆蓋率計(jì)算精度的前提下,SiCsFuzzer只需對(duì)目標(biāo)程序中40.61%的分支進(jìn)行插樁,最終SiCsFuzzer 的執(zhí)行效率比傳統(tǒng)的基于覆蓋率反饋的模糊測(cè)試工具快3 倍。

      本文的主要貢獻(xiàn)如下:

      1) 提出了一種面向閉源程序的高效模糊測(cè)試方法。該方法借助基于稀疏插樁的覆蓋率跟蹤以及針對(duì)流行的動(dòng)態(tài)二進(jìn)制插樁工具(例如Pin)的“預(yù)熱”優(yōu)化,降低基于覆蓋率反饋的模糊測(cè)試過(guò)程中跟蹤覆蓋率的開(kāi)銷,提高模糊測(cè)試效率。

      2) 基于該解決方案實(shí)現(xiàn)的原型工具SiCsFuzzer,在Windows 平臺(tái)9 個(gè)規(guī)模在286KB~19.3MB,類型涉及圖片處理、視頻處理、文件壓縮、加密和文檔處理等類型應(yīng)用所組成的測(cè)試集上,跟蹤覆蓋率引入的額外開(kāi)銷為程序正常執(zhí)行時(shí)間的1.1 倍,比傳統(tǒng)的基于覆蓋率反饋的模糊測(cè)試工具快3 倍,并發(fā)現(xiàn)PDFtk 和XnView 程序最新版本中的未知漏洞各1。

      本文的組織結(jié)構(gòu)如下:第2 章介紹基于覆蓋率反饋的模糊測(cè)試方法的工作流程,剖析性能開(kāi)銷分布,并提出本文的改進(jìn)思路;第3 章闡述基于稀疏插樁的閉源軟件模糊測(cè)試方法的系統(tǒng)設(shè)計(jì)及其中涉及的兩個(gè)關(guān)鍵技術(shù)的細(xì)節(jié);第4 章介紹基于稀疏插樁的閉源軟件模糊測(cè)試原型SiCsFuzzer 的實(shí)現(xiàn)細(xì)節(jié);第5 章分析實(shí)驗(yàn)數(shù)據(jù);第6 章介紹相關(guān)工作;第7 章總結(jié)全文。

      2 基于覆蓋率反饋的模糊測(cè)試性能開(kāi)銷

      本章將依次介紹基于覆蓋率反饋的模糊測(cè)試方法的工作流程,剖析性能開(kāi)銷分布,并提出改進(jìn)思路。

      2.1 基于覆蓋率反饋的模糊測(cè)試方法

      圖2 展示了傳統(tǒng)的基于覆蓋率反饋的模糊測(cè)試(以下簡(jiǎn)稱模糊測(cè)試)的工作流程,主要包括三個(gè)重要的部分:(1)測(cè)試用例的生成;(2)執(zhí)行和監(jiān)控目標(biāo)程序/跟蹤覆蓋率;(3)覆蓋率反饋和崩潰結(jié)果分析。在模糊測(cè)試運(yùn)行前,對(duì)于一個(gè)目標(biāo)程序,給定一個(gè)目標(biāo)程序和一系列初始種子,當(dāng)模糊測(cè)試運(yùn)行時(shí),首先,模糊測(cè)試工具將初始種子加入到種子隊(duì)列中,按照特定的順序從種子隊(duì)列中選取一個(gè)種子并按照一系列的變異規(guī)則對(duì)種子進(jìn)行變異,生成大量新的測(cè)試用例,并依次提供給目標(biāo)程序。接著,目標(biāo)程序在執(zhí)行每一個(gè)測(cè)試用例的過(guò)程中,模糊測(cè)試工具通過(guò)靜態(tài)或動(dòng)態(tài)插樁的方式對(duì)目標(biāo)程序進(jìn)行插樁,來(lái)跟蹤代碼覆蓋率。如果一個(gè)測(cè)試用例能夠探索到目標(biāo)程序新的代碼區(qū)域,比如新的基本塊、新的分支,則該測(cè)試用例被認(rèn)為是有價(jià)值的,并被保存到初始種子隊(duì)列中,以備將來(lái)之用。如果該測(cè)試用例是無(wú)價(jià)值的,則被丟棄??傊?基于覆蓋率反饋的模糊測(cè)試工具將目標(biāo)程序執(zhí)行測(cè)試用例時(shí)得到的覆蓋率作為反饋信息,來(lái)指導(dǎo)種子的選擇和變異。以這種方法得到的測(cè)試用例更有可能探索到未被發(fā)現(xiàn)的目標(biāo)程序代碼區(qū)域,并觸發(fā)其中的漏洞。因此,準(zhǔn)確的代碼覆蓋率信息是模糊測(cè)試工具發(fā)現(xiàn)有價(jià)值的種子并快速發(fā)現(xiàn)軟件漏洞的重要依據(jù)[14]。

      當(dāng)前主流的模糊測(cè)試工具多使用分支覆蓋來(lái)計(jì)算測(cè)試用例對(duì)目標(biāo)程序的代碼覆蓋率。以AFL 為例。AFL 使用一個(gè)位圖結(jié)構(gòu)記錄分支覆蓋率,并為每個(gè)分支計(jì)算一個(gè)哈希值,作為其在位圖中的鍵值。該哈希值由分支的起始基本塊地址與結(jié)束基本塊地址通過(guò)移位及異或的方式計(jì)算得到。在不考慮哈希碰撞的前提下,每個(gè)分支對(duì)應(yīng)的哈希值是唯一的。由于本文重點(diǎn)關(guān)注閉源程序,尤其是以往工作普遍忽視的Windows 平臺(tái)上閉源程序模糊測(cè)試的效率優(yōu)化,本章的后續(xù)小節(jié)將針對(duì)Windows 程序基于分支覆蓋反饋的模糊測(cè)試時(shí)間開(kāi)銷進(jìn)行剖析,并根據(jù)剖析結(jié)果闡述本文的效率改進(jìn)方案。

      2.2 性能剖析

      本節(jié)選取 Windows 平臺(tái)上規(guī)模在 286KB~19.3MB,類型涉及圖片處理、視頻處理和文件壓縮的9 個(gè)目標(biāo)程序,剖析模糊測(cè)試的性能構(gòu)成。實(shí)驗(yàn)選擇動(dòng)態(tài)插樁工具Pin 作為追蹤和反饋分析覆蓋的基礎(chǔ)平臺(tái)。

      圖3 所示為模糊測(cè)試的一次迭代[15]過(guò)程中,跟蹤覆蓋率的執(zhí)行時(shí)間的占比。通過(guò)對(duì)8 個(gè)目標(biāo)程序的統(tǒng)計(jì)可以看出,跟蹤覆蓋率(對(duì)應(yīng)圖2 的第2 部分)的平均執(zhí)行時(shí)間占模糊測(cè)試的一次迭代總執(zhí)行時(shí)間的82%,是模糊測(cè)試開(kāi)銷的主要來(lái)源。圖4 進(jìn)一步剖析了跟蹤覆蓋率的時(shí)間開(kāi)銷構(gòu)成。從中可以看出,跟蹤覆蓋率所引入的額外開(kāi)銷為程序正常執(zhí)行時(shí)間的5.25 倍。上述額外的開(kāi)銷主要來(lái)自兩個(gè)方面:(1)二進(jìn)制插樁平臺(tái)Pin 的開(kāi)銷,包括啟動(dòng)和初始化Pin、加載和啟動(dòng)目標(biāo)程序、在JIT 模式下對(duì)目標(biāo)程序代碼進(jìn)行動(dòng)態(tài)翻譯;(2)插樁開(kāi)銷,包括用于確定在目標(biāo)程序的哪些位置插入跟蹤代碼的開(kāi)銷和執(zhí)行跟蹤代碼的開(kāi)銷。如圖4 所示,上述兩部分的開(kāi)銷分別占跟蹤測(cè)試用例覆蓋率開(kāi)銷的60%和24%。

      圖5 進(jìn)一步剖析了二進(jìn)制插樁平臺(tái)Pin 的開(kāi)銷構(gòu)成。從中可以看出,Pin 的空載執(zhí)行時(shí)間(即使用Pin 控制目標(biāo)程序運(yùn)行,但不對(duì)目標(biāo)程序進(jìn)行插樁的執(zhí)行時(shí)間)主要由三部分構(gòu)成:(1)平臺(tái)初始化和目標(biāo)程序加載的開(kāi)銷;(2)動(dòng)態(tài)翻譯開(kāi)銷;(3)執(zhí)行翻譯后的代碼的開(kāi)銷。本文將平臺(tái)初始化和加載目標(biāo)程序,以及對(duì)目標(biāo)程序代碼的動(dòng)態(tài)翻譯這兩部分統(tǒng)稱為“預(yù)熱”階段。從圖5 可以看到,“預(yù)熱”階段的開(kāi)銷是Pin執(zhí)行時(shí)間的主要組成部分,其中初始化和加載過(guò)程占Pin 執(zhí)行時(shí)間的33%,動(dòng)態(tài)代碼生成占52%。

      上述實(shí)驗(yàn)表明,跟蹤覆蓋率的時(shí)間開(kāi)銷是模糊測(cè)試開(kāi)銷的主要來(lái)源(82%),而跟蹤覆蓋率相對(duì)于程序正常執(zhí)行所引入的額外開(kāi)銷主要源于Pin 的“預(yù)熱”階段的開(kāi)銷以及插樁開(kāi)銷。如何避免和緩解上述開(kāi)銷是本文工作的重點(diǎn)。

      2.3 改進(jìn)方案

      基于以上實(shí)驗(yàn)分析,我們發(fā)現(xiàn)基于動(dòng)態(tài)插樁的跟蹤覆蓋率是基于覆蓋率反饋的模糊測(cè)試的主要開(kāi)銷來(lái)源。為了降低跟蹤覆蓋率的開(kāi)銷,應(yīng)該考慮兩個(gè)關(guān)鍵因素:(1)插樁的開(kāi)銷;(2)Pin 的“預(yù)熱”階段的開(kāi)銷。接下來(lái),本文將分別介紹本文降低跟蹤覆蓋率開(kāi)銷的關(guān)鍵思路。

      降低插樁的開(kāi)銷。目前主流的基于覆蓋率反饋的模糊測(cè)試工具默認(rèn)對(duì)目標(biāo)程序中的所有基本塊或分支進(jìn)行插樁。但并非所有插樁位置都是必要的。以圖1 所示的程序片段及其對(duì)應(yīng)的控制流圖(CFG)為例,對(duì)于該程序,為了跟蹤覆蓋率,只需要對(duì)BB2(基本塊2)、BB4 和BB5 進(jìn)行插樁,就可以區(qū)分每一條執(zhí)行路徑,并且能夠推導(dǎo)出準(zhǔn)確的覆蓋率信息。文獻(xiàn)[11]所述的程序優(yōu)化技術(shù)也表明,可以找到目標(biāo)程序所有基本塊/分支的一個(gè)子集,該子集中的基本塊/分支可以推導(dǎo)出目標(biāo)程序控制流圖上的所有基本塊/分支。文獻(xiàn)[11]的實(shí)驗(yàn)也表明,對(duì)于選擇的8 個(gè)C 程序,只需要覆蓋目標(biāo)程序中特定的32%的分支,即可確保100%的分支覆蓋。受到該工作的啟發(fā),本文將插樁對(duì)象限定在目標(biāo)程序中的一部分基本塊或分支,這些基本塊或分支運(yùn)行與否無(wú)法通過(guò)程序中其它基本塊或分支的運(yùn)行信息進(jìn)行推斷。這樣,可以在不犧牲代碼覆蓋率準(zhǔn)確性的情況下減少插樁的開(kāi)銷?;谠撍枷?我們擴(kuò)展文獻(xiàn)[11]中的工作,以支持閉源軟件代碼分析和動(dòng)態(tài)插樁。在本文接下來(lái)的部分稱其為基于稀疏插樁的覆蓋率跟蹤技術(shù)。

      降低Pin 的“預(yù)熱”階段的開(kāi)銷。由于動(dòng)態(tài)插樁平臺(tái)每執(zhí)行一個(gè)測(cè)試用例,都需要重新加載目標(biāo)程序并對(duì)目標(biāo)程序重新進(jìn)行動(dòng)態(tài)代碼翻譯,由此帶來(lái)冗余的開(kāi)銷。本文引入“預(yù)熱”優(yōu)化,通過(guò)避免對(duì)同一程序的重復(fù)加載提高對(duì)CodeCache 的復(fù)用率,從而避免重復(fù)加載和重復(fù)翻譯的開(kāi)銷。

      3 系統(tǒng)設(shè)計(jì)與技術(shù)細(xì)節(jié)

      3.1 系統(tǒng)設(shè)計(jì)

      基于2.3 介紹的改進(jìn)方案,本文設(shè)計(jì)實(shí)現(xiàn)了SiCsFuzzer(A Sparse-instrumentation-based Fuzzing Platform for Closed Source Software)。SiCsFuzzer 系統(tǒng)設(shè)計(jì)如圖6 所示。與圖2 所示的傳統(tǒng)的基于覆蓋率反饋的模糊測(cè)試相比,SiCsFuzzer 對(duì)圖2 中的第2階段,即執(zhí)行和監(jiān)控目標(biāo)程序/跟蹤覆蓋率的階段進(jìn)行了以下兩方面改進(jìn)。

      1) 提出基于稀疏插樁的覆蓋率跟蹤技術(shù),根據(jù)支配關(guān)系選擇必要的插樁位置,僅對(duì)覆蓋率無(wú)法推導(dǎo)的分支或基本塊進(jìn)行稀疏插樁,從而在不影響覆蓋率準(zhǔn)確性的情況下降低插樁的開(kāi)銷?;舅悸肥窃趯?duì)閉源目標(biāo)程序進(jìn)行模糊測(cè)試之前,通過(guò)二進(jìn)制代碼逆向分析和控制流分析,構(gòu)建全局控制流圖以及全局超級(jí)塊支配圖,計(jì)算基本塊之間的前/后支配關(guān)系,從而在全局控制流圖上標(biāo)記出能夠區(qū)分不同路徑并且能夠推導(dǎo)出其它基本塊/邊的覆蓋情況的最小基本塊/邊的集合,用于指導(dǎo)動(dòng)態(tài)二進(jìn)制插樁過(guò)程中位置的選擇以及模糊測(cè)試一次迭代過(guò)程中覆蓋率的推導(dǎo)和重建,由此達(dá)到降低插樁代價(jià),提高模糊測(cè)試效率的目的。

      2) 提出“預(yù)熱”優(yōu)化,避免二進(jìn)制插樁平臺(tái)重復(fù)啟動(dòng)以及對(duì)目標(biāo)程序熱代碼的重復(fù)翻譯的開(kāi)銷,從而進(jìn)一步提高模糊測(cè)試的效率。與圖2 所示的傳統(tǒng)模糊測(cè)試流程相比,SiCsFuzzer 將插樁平臺(tái)的“預(yù)熱階段”從模糊測(cè)試的循環(huán)迭代中分離出來(lái),僅在模糊測(cè)試開(kāi)始時(shí)進(jìn)行插樁平臺(tái)的初始化及被測(cè)目標(biāo)程序的加載。在剔除重復(fù)啟動(dòng)、加載開(kāi)銷的同時(shí),使測(cè)試用例之間可以共享已被動(dòng)態(tài)翻譯的代碼,以緩解冗余動(dòng)態(tài)翻譯的開(kāi)銷?;舅悸肥窃谀繕?biāo)程序加載后,執(zhí)行到輸入讀取位置之前的某一程序點(diǎn)p 時(shí),保存內(nèi)存快照,當(dāng)目標(biāo)程序讀取輸入并執(zhí)行到指定的結(jié)束位置時(shí),使用保存的快照將程序執(zhí)行狀態(tài)恢復(fù)到程序點(diǎn)p,并讀取新的輸入。

      3.2 技術(shù)細(xì)節(jié)

      3.2.1 基于稀疏插樁的覆蓋率跟蹤技術(shù)

      本節(jié)將介紹基于稀疏插樁的覆蓋率跟蹤技術(shù)的技術(shù)細(xì)節(jié)。

      如前所述,稀疏插樁的基礎(chǔ)是標(biāo)記程序控制流圖上滿足具備路徑可區(qū)分性以及覆蓋率的推導(dǎo)重建能力的基本塊。路徑可區(qū)分性是指通過(guò)被標(biāo)記的基本塊可以區(qū)分每一條不同的執(zhí)行路徑。也就是說(shuō),對(duì)于任意兩條不同的路徑,由路徑上被標(biāo)記的基本塊構(gòu)成序列是不同的。如圖1 所示,如果被標(biāo)記的基本塊為BB2、BB4 和BB5,則經(jīng)過(guò)BB1→BB3→BB4→BB6 的執(zhí)行路徑將被表示成[BB4],經(jīng)過(guò) BB1→BB3→BB5→BB6 的執(zhí)行路徑被表示為[BB5],經(jīng)過(guò)BB1→BB2→BB6 的執(zhí)行路徑被表示為[BB2]。換而言之,只需要對(duì)這三個(gè)基本塊進(jìn)行插樁,就可以區(qū)分出不同的執(zhí)行路徑。代碼覆蓋率的推導(dǎo)重建能力是指根據(jù)所跟蹤到的被標(biāo)記基本塊,能夠推導(dǎo)出當(dāng)前測(cè)試用例所執(zhí)行的路徑上其它未被標(biāo)記的基本塊,即重建整條路徑對(duì)應(yīng)的代碼覆蓋率。仍以圖1 為例,如果當(dāng)前測(cè)試用例覆蓋了被標(biāo)記的基本塊BB4,則可以推導(dǎo)出當(dāng)前測(cè)試用例覆蓋了圖1 代碼片段中的路徑BB1→BB3→BB4→BB6。

      本文參照并擴(kuò)展了文獻(xiàn)[11]和文獻(xiàn)[16]所述方法,將稀疏插樁位置的選擇問(wèn)題轉(zhuǎn)化為全局超級(jí)塊支配圖上的頂點(diǎn)(即基本塊)標(biāo)注問(wèn)題。以圖7 所示的程序代碼為例。采用文獻(xiàn)[11]所述方法可以構(gòu)建出各個(gè)函數(shù)的超級(jí)塊支配圖。構(gòu)建流程如圖7~10 所示。即:首先構(gòu)建各個(gè)函數(shù)的控制流圖(圖7),并基于控制流圖計(jì)算前支配樹(shù)和后支配樹(shù)(圖8),然后合并前、后支配樹(shù)中相同的節(jié)點(diǎn),生成如圖9 所示的基本塊支配圖,再規(guī)約圖中的強(qiáng)聯(lián)通分量并去除冗余邊后,得到圖10 中所示的每個(gè)函數(shù)的超級(jí)塊支配圖。

      超級(jí)塊支配圖具備如下性質(zhì):(1)如果一個(gè)測(cè)試用例覆蓋了超級(jí)塊支配圖中的某個(gè)超級(jí)塊,則該超級(jí)塊中包含的所有基本塊也都被覆蓋;(2)如果一個(gè)測(cè)試用例的執(zhí)行路徑覆蓋了超級(jí)塊U 的一個(gè)子超級(jí)塊V,則該測(cè)試用例也覆蓋了U。將上述性質(zhì)應(yīng)用在稀疏插樁的位置選擇上,即只需要標(biāo)記超級(jí)塊支配圖上子節(jié)點(diǎn)數(shù)量少于兩個(gè)的超級(jí)塊中包含的任意一個(gè)基本塊,如圖10,對(duì)于main 函數(shù),只需要對(duì)基本塊2、4、5 插樁,對(duì)于display 函數(shù),只需要對(duì)基本塊8、10 插樁。通過(guò)動(dòng)態(tài)插樁記錄上述基本塊集合是否被覆蓋,則可推導(dǎo)出同一函數(shù)中其它基本塊的覆蓋情況。

      但由于單個(gè)函數(shù)的超級(jí)塊支配圖并未考慮函數(shù)調(diào)用對(duì)支配關(guān)系的影響,基于目標(biāo)程序中每個(gè)函數(shù)的超級(jí)塊支配圖所標(biāo)記出的最小稀疏插樁位置集合有可能冗余,甚至是不正確的。以圖7 所示的程序?yàn)槔?如果一個(gè)測(cè)試用例覆蓋了display 函數(shù)的基本塊8,則可以推斷出該測(cè)試用例同時(shí)覆蓋了main 函數(shù)中的基本塊1,2,6,也就是說(shuō),如果對(duì)基本塊8 插樁,則不需要對(duì)基本塊2 插樁。另外,當(dāng)程序中出現(xiàn)abort、exit 等函數(shù)時(shí),會(huì)影響支配關(guān)系的計(jì)算,例如,仍以圖7 為例,若基本塊8 是一個(gè)exit 函數(shù),當(dāng)一個(gè)測(cè)試用例覆蓋了基本塊8,由函數(shù)調(diào)用關(guān)系可知,該測(cè)試用例一定覆蓋了基本塊2,根據(jù)圖10 的main 函數(shù)的超級(jí)支配圖推導(dǎo)出,如果測(cè)試用例覆蓋了基本塊2,則該測(cè)試用例一定覆蓋了基本塊1,6。顯然,該測(cè)試用例不會(huì)覆蓋基本塊6。因此為了對(duì)程序的全局控制流進(jìn)行分析,本文實(shí)現(xiàn)了文獻(xiàn)[17]提出的全局超級(jí)塊支配圖理論,根據(jù)函數(shù)的調(diào)用關(guān)系,并結(jié)合每個(gè)函數(shù)的超級(jí)塊支配圖,得到全局超級(jí)塊支配圖,如圖11 所示。最后,本文將上述超級(jí)塊支配圖的性質(zhì)應(yīng)用到插樁位置選擇,根據(jù)全局超級(jí)塊支配圖(圖11),只需要對(duì)基本塊4、5、8 和10 進(jìn)行插樁。并且基于全局超級(jí)支配圖中,本文實(shí)現(xiàn)了文獻(xiàn)[17]中提出的方法解決了函數(shù)調(diào)用過(guò)程中不能正常返回的情況。

      算法1.基于稀疏插樁的跟蹤算法.

      輸入:目標(biāo)程序和被標(biāo)記的基本塊

      輸出:無(wú)

      如算法1,當(dāng)SiCsFuzzer 在跟蹤覆蓋率時(shí),插樁工具取目標(biāo)程序?qū)⒁獔?zhí)行的一個(gè)順序指令序列(記做trace),并判斷trace 中每個(gè)基本塊是否被標(biāo)記。如果被標(biāo)記,則在該基本塊前插入跟蹤代碼。跟蹤代碼的功能是維護(hù)一個(gè)bitmap 數(shù)據(jù)結(jié)構(gòu)。為了重建代碼覆蓋率,在跟蹤代碼中,我們額外使用另外一個(gè)與bitmap 大小相同的bitmapAddr 數(shù)據(jù)結(jié)構(gòu)記錄被覆蓋的基本塊/分支的地址。比如如果覆蓋了基本塊1,則會(huì)根據(jù)該基本塊地址計(jì)算得到bitmap 數(shù)組的下標(biāo),相應(yīng)地,以該下標(biāo)的bitmap 的值代表對(duì)應(yīng)的基本/分支塊的被覆蓋次數(shù),同時(shí)以該下標(biāo)的bitmapAddr 的值為該基本塊/分支的地址。

      如前所述,基于稀疏插樁可以推導(dǎo)出其它未被插樁的基本塊及邊的覆蓋率。算法2 為覆蓋率重建算法。雖然覆蓋率重建對(duì)本文方法而言并不是必須的,但考慮到與主流模糊測(cè)試工具之間的兼容性,重建覆蓋率可以更好的輔助主流模糊測(cè)試工具進(jìn)行變異策略的選擇。比如,AFL 會(huì)根據(jù)當(dāng)前測(cè)試用例覆蓋的基本塊或邊的數(shù)量選擇變異次數(shù),LibFuzzer 會(huì)給予覆蓋了更多新的基本塊的種子更高的優(yōu)先級(jí)。在重建覆蓋率的基礎(chǔ)上能夠更加直觀的計(jì)算出這些信息,從而提高本文方法的適用面。

      算法2.代碼覆蓋率重建算法

      輸入:bitmapAddr 和marked。

      輸出:代碼覆蓋率

      如算法2 所示,根據(jù)bitmapAddr 和marked 即可重建覆蓋率。根據(jù)目標(biāo)程序的全局超級(jí)塊支配圖,我們得到被標(biāo)記的基本塊。對(duì)于每一個(gè)標(biāo)記的基本塊,我們遞歸地記錄它的所有父節(jié)點(diǎn),也就是與該標(biāo)記的基本塊同時(shí)被覆蓋的未被標(biāo)記的基本塊,記為marked,以圖11 為例,其數(shù)據(jù)結(jié)構(gòu)為:{4:1,3,6;5:1,3,6;8:1,2,6,7,9,11;10:1,2,6,7,9,11}。另外,bitmapAddr 為算法1 中提到的記錄動(dòng)態(tài)跟蹤時(shí)被覆蓋的被標(biāo)記的基本塊/分支的地址。在算法2 中,我們使用一個(gè)哈希表bbl_cover 存儲(chǔ)當(dāng)前測(cè)試用例覆蓋到的基本塊/分支的地址,首先遍歷bitmapAddr 中的每一個(gè)值,如果該值是當(dāng)前測(cè)試用例覆蓋的基本塊/分支地址,則覆蓋率增加1,并存儲(chǔ)到哈希表中(第5~7 行),然后遍歷該基本塊/分支能推導(dǎo)出的其他基本塊/分支,同樣如果該基本塊/分支的地址不在bbl_cover 哈希表中,則將其存儲(chǔ)到哈希表中,并將覆蓋率增加1(第8~13)。最終,我們通過(guò)稀疏插樁的覆蓋率跟蹤方法,實(shí)現(xiàn)了代碼覆蓋率重建。

      3.2.2 “預(yù)熱”優(yōu)化技術(shù)

      本節(jié)介紹“預(yù)熱”優(yōu)化技術(shù)的細(xì)節(jié)。以Pin 為代表的二進(jìn)制動(dòng)態(tài)插樁平臺(tái)在執(zhí)行到目標(biāo)程序的一個(gè)新的基本塊時(shí),會(huì)將該基本塊轉(zhuǎn)換成Pin 的可執(zhí)行指令序列存儲(chǔ)到CodeCache 當(dāng)中; 如果CodeCache 當(dāng)中已經(jīng)保存了該基本塊對(duì)應(yīng)的指令序列,則無(wú)需再次翻譯。一旦插樁平臺(tái)重啟或程序重新載入,則CodeCache 將被清空?!邦A(yù)熱”優(yōu)化的基本思路是通過(guò)避免對(duì)同一程序的重復(fù)加載提高對(duì)CodeCache 的復(fù)用率,從而避免重復(fù)加載和重復(fù)翻譯的開(kāi)銷。該優(yōu)化得以實(shí)施的基礎(chǔ)是能夠在目標(biāo)程序加載后,執(zhí)行到輸入讀取位置之前的某一程序點(diǎn)p 時(shí),保存內(nèi)存快照,當(dāng)目標(biāo)程序讀取輸入并執(zhí)行到指定的結(jié)束位置時(shí),使用保存的快照將程序執(zhí)行狀態(tài)恢復(fù)到程序點(diǎn)p,并讀取新的輸入。

      SiCsFuzzer 默認(rèn)選擇main 函數(shù)的開(kāi)始位置作為快照的生成和恢復(fù)位置??煺毡4娴膬?nèi)容包括寄存器狀態(tài)、內(nèi)存狀態(tài)。如果測(cè)試用例是通過(guò)main 函數(shù)的參數(shù)讀入的,則額外監(jiān)控測(cè)試用例的存放位置L,并在每次恢復(fù)快照的同時(shí)將從種子隊(duì)列中讀取的新輸入復(fù)制到L。SiCsFuzzer 默認(rèn)選擇的結(jié)束位置為main 函數(shù)的結(jié)束位置;也可以選擇在調(diào)用exit 函數(shù)的位置;對(duì)于有明顯輸出信息的程序,可以通過(guò)動(dòng)態(tài)調(diào)試并觀察輸出狀態(tài)選擇出結(jié)束位置。

      這樣,我們可以只關(guān)注目標(biāo)程序的代碼部分,而不是花費(fèi)大量的時(shí)間用于初始化插樁工具和加載目標(biāo)程序。同時(shí),“預(yù)熱”優(yōu)化可以充分發(fā)揮插樁工具的“Trace Linking”優(yōu)化機(jī)制,避免重復(fù)將相同的trace 生成新的指令代碼的開(kāi)銷,使得之前生成的指令代碼存儲(chǔ)在CodeCache 中被執(zhí)行所有測(cè)試用例時(shí)共享。并且隨著模糊測(cè)試的進(jìn)行,被覆蓋到的新的trace 越來(lái)越少,其中大多數(shù)已經(jīng)存儲(chǔ)在CodeCache中,極大地降低了不必要的開(kāi)銷。

      4 系統(tǒng)設(shè)計(jì)實(shí)現(xiàn)

      本文基于上述設(shè)計(jì),在現(xiàn)有模糊測(cè)試平臺(tái)Puzzer[18]上實(shí)現(xiàn)了基于稀疏插樁的閉源軟件模糊測(cè)試原型SiCsFuzzer。本章將介紹原型中兩個(gè)關(guān)鍵技術(shù)的實(shí)現(xiàn)細(xì)節(jié)。

      4.1 基于稀疏插樁的覆蓋率跟蹤實(shí)現(xiàn)

      基于稀疏插樁的覆蓋率跟蹤實(shí)現(xiàn)分為基本塊標(biāo)記、插樁追蹤和覆蓋率重建三部分。

      其中,基本塊標(biāo)記實(shí)現(xiàn)為IDA Pro 插件的形式,利用IDA Pro 提供的接口提取目標(biāo)程序的函數(shù)調(diào)用關(guān)系和每個(gè)函數(shù)的程序控制流圖;然后使用Boost 圖形庫(kù)函數(shù)建立程序的前支配樹(shù)和后支配樹(shù)。如果模糊測(cè)試使用基本塊覆蓋,則計(jì)算基本塊的前支配樹(shù)和后支配樹(shù),如果模糊測(cè)試使用分支覆蓋,則計(jì)算分支的前支配樹(shù)和后支配樹(shù);合并前、后支配樹(shù)中相同的節(jié)點(diǎn),構(gòu)成圖的形式,規(guī)約圖中的強(qiáng)聯(lián)通分量并去除冗余邊后,得到每個(gè)函數(shù)對(duì)應(yīng)的超級(jí)塊支配圖;最后根據(jù)函數(shù)調(diào)用關(guān)系合并每個(gè)函數(shù)的超級(jí)塊支配圖,得到全局超級(jí)塊支配圖。根據(jù)超級(jí)塊支配圖的性質(zhì)得到需要插樁的基本塊/分支和對(duì)應(yīng)的未插樁的基本塊/分支,記錄在文件中。該文件將在模糊測(cè)試開(kāi)始時(shí)由模糊測(cè)試進(jìn)程加載到共享內(nèi)存。

      如前所述,基本塊標(biāo)記的結(jié)果將用于指導(dǎo)模糊測(cè)試過(guò)程中的動(dòng)態(tài)二進(jìn)制插樁位置的選擇,但插樁平臺(tái)Pin 與IDA Pro 生成的控制流圖對(duì)基本塊的劃分存在不一致的情況。圖12 所示為IDA Pro 生成的用于計(jì)算全局超級(jí)支配圖的控制流圖片段。根據(jù)支配關(guān)系,SiCsFuzzer 會(huì)將標(biāo)記圖12 中的基本塊2 和基本塊3 為需要?jiǎng)討B(tài)插樁的基本塊。但在覆蓋率跟蹤過(guò)程中,如果執(zhí)行的路徑為基本塊1的假分支,Pin會(huì)將基本塊3 劃入基本塊2,進(jìn)而造成基本塊3 的覆蓋被重復(fù)計(jì)算。因此本文從IDA Pro 提取目標(biāo)程序的程序控制流圖時(shí),對(duì)以mov 指令結(jié)束的基本塊進(jìn)行標(biāo)記,在分析覆蓋率時(shí),遇到帶有標(biāo)記的基本塊時(shí),則將其對(duì)應(yīng)覆蓋率減一,以調(diào)整覆蓋率計(jì)算。

      4.2 “預(yù)熱”優(yōu)化實(shí)現(xiàn)

      對(duì)于本文工作而言,理想的方式是使用靜態(tài)重寫(xiě),其開(kāi)銷較低,但是Windows 平臺(tái)上的二進(jìn)制重寫(xiě)工具如Dyninst、McSema[19]等工具魯棒性較差。采用二進(jìn)制動(dòng)態(tài)跟蹤代碼覆蓋率雖然開(kāi)銷較高,但確是目前最具普適性的方法。因此本文實(shí)現(xiàn)了“預(yù)熱”優(yōu)化來(lái)降低二進(jìn)制動(dòng)態(tài)跟蹤代碼覆蓋率的開(kāi)銷。

      為實(shí)現(xiàn)“預(yù)熱”優(yōu)化,我們?cè)O(shè)計(jì)并實(shí)現(xiàn)了fuzzer進(jìn)程和instrumentor 進(jìn)程之間的通信。如圖13,一共有以下四個(gè)主要對(duì)象:

      1) fuzzer:fuzzer 是基于覆蓋率反饋的模糊測(cè)試的主進(jìn)程,主要負(fù)責(zé)初始化種子隊(duì)列、生成測(cè)試用例、分析代碼覆蓋率以及啟動(dòng)instrumentor 進(jìn)程。

      2) instrumentor:instrumentor 是由fuzzer 開(kāi)啟的子進(jìn)程,該進(jìn)程是插樁進(jìn)程,主要負(fù)責(zé)控制目標(biāo)程序的執(zhí)行,并分析在目標(biāo)程序的哪些位置插入跟蹤代碼。

      3)目標(biāo)程序:指的是目標(biāo)二進(jìn)制程序,由instrumentor 控制執(zhí)行。

      4) 共享內(nèi)存:SiCsFuzzer 使用共享內(nèi)存存儲(chǔ)代碼覆蓋信息。在模糊測(cè)試運(yùn)行過(guò)程中,instrumentor首先初始化該共享內(nèi)存,目標(biāo)程序在插樁工具的控制下執(zhí)行并將覆蓋率信息記錄到共享內(nèi)存中,當(dāng)目標(biāo)程序運(yùn)行到結(jié)束位置后,fuzzer 進(jìn)程開(kāi)始讀取共享內(nèi)存的數(shù)據(jù)并分析代碼覆蓋信息。

      fuzzer 進(jìn)程與instrumentor 進(jìn)程的交互如下:

      1) fuzzer 選擇一個(gè)測(cè)試用例并開(kāi)始新一輪的模糊測(cè)試。首先f(wàn)uzzer 向instrumentor 進(jìn)程發(fā)送一個(gè)begin信號(hào)。表示instrumentor 可以開(kāi)始運(yùn)行。

      2) instrumentor 收到begin信號(hào)后,首先對(duì)共享內(nèi)存做相關(guān)初始化工作,然后控制目標(biāo)二進(jìn)制程序開(kāi)始運(yùn)行。同時(shí)保存目標(biāo)程序當(dāng)前的上下文信息。

      3) 目標(biāo)二進(jìn)制程序首先讀取測(cè)試用例,并運(yùn)行,并在instrumentor 的控制下,將覆蓋率信息記錄到共享內(nèi)存中。

      4) instrumentor 監(jiān)控目標(biāo)二進(jìn)制程序運(yùn)行到指定結(jié)束指令位置后,instrumentor 發(fā)送end信號(hào)給fuzzer進(jìn)程,表示目標(biāo)程序運(yùn)行結(jié)束,同時(shí)instrumentor 恢復(fù)2)中保存的上下文,并返回到程序開(kāi)始指令位置。

      5) fuzzer 接收到end信號(hào)后,開(kāi)始讀取共享內(nèi)存的數(shù)據(jù)并分析程序運(yùn)行時(shí)的覆蓋率等信息。

      6) 返回到1)并重復(fù)。

      本文實(shí)現(xiàn)的“預(yù)熱”優(yōu)化基于插樁工具Pin。為了實(shí)現(xiàn)在指定的開(kāi)始指令位置獲取目標(biāo)程序的上下文信息,并在結(jié)束指令位置恢復(fù)保存的上下文信息,傳統(tǒng)的方法可使用Pin 進(jìn)行指令插樁,記錄寫(xiě)內(nèi)存的

      指令操作和內(nèi)存的狀態(tài),當(dāng)程序運(yùn)行到結(jié)束指令的位置時(shí),恢復(fù)內(nèi)存狀態(tài)。但是該方法開(kāi)銷很大,而本文采用的方法是在程序運(yùn)行到開(kāi)始位置時(shí),使用PyDbg 獲取目標(biāo)程序的上下文信息,包括寄存器狀態(tài),內(nèi)存狀態(tài),在程序運(yùn)行到結(jié)束指令的位置時(shí),恢復(fù)保存的寄存器、內(nèi)存狀態(tài)。

      AFL 實(shí)現(xiàn)了fork-server 機(jī)制[20]來(lái)避免“預(yù)熱”階段的開(kāi)銷,但是fork-server 的實(shí)現(xiàn)思想主要依賴Linux 的系統(tǒng)函數(shù)fork,在每一輪模糊測(cè)試時(shí),使用fork函數(shù)復(fù)制一個(gè)新的目標(biāo)程序進(jìn)程并執(zhí)行,避免了載入目標(biāo)程序的重復(fù)性工作。fork函數(shù)使用寫(xiě)時(shí)復(fù)制(copy on write)的機(jī)制,開(kāi)銷非常低,但是 Windows 平臺(tái)沒(méi)有類似的函數(shù),因此在Windows 平臺(tái)實(shí)現(xiàn)fork-server 機(jī)制具有很大的挑戰(zhàn)。

      5 實(shí)驗(yàn)與分析

      本文在現(xiàn)有模糊測(cè)試平臺(tái)Puzzer[18]上實(shí)現(xiàn)了基于稀疏插樁的閉源軟件模糊測(cè)試原型SiCsFuzzer。本章將SiCsFuzzer 與Puzzer 和WinAFL 進(jìn)行對(duì)比,本文的實(shí)驗(yàn)主要回答了以下5 個(gè)問(wèn)題:

      Q1:采用稀疏插樁的覆蓋率跟蹤技術(shù)使需要插樁的基本塊或分支的數(shù)量降低了多少?

      Q2:基于稀疏插樁的覆蓋率跟蹤技術(shù)對(duì)模糊測(cè)試的效率改進(jìn)情況如何?

      Q3:“預(yù)熱”優(yōu)化對(duì)模糊測(cè)試效率的改進(jìn)情況如何?

      Q4:在執(zhí)行時(shí)間相同的前提下,SiCsFuzzer 是否能夠比Puzzer 達(dá)到更高的覆蓋率?

      Q5:SiCsFuzzer與WinAFL的效能對(duì)比結(jié)果如何?

      5.1 實(shí)驗(yàn)配置

      本章以表1 所示的9 個(gè)Windows 平臺(tái)閉源二進(jìn)制軟件作為實(shí)驗(yàn)分析的目標(biāo)程序。程序涉及圖片處理、視頻處理、文件壓縮、加解密和文檔處理5 類,軟件規(guī)模從 266KB~19.3MB 不等。實(shí)驗(yàn)均運(yùn)行在Windows 7-32、2 核Intel i7-87700 處理器的虛擬機(jī)上。

      表1 二進(jìn)制目標(biāo)程序信息Table 1 Binary target program information

      為了避免隨機(jī)因素的影響,確保對(duì)比實(shí)驗(yàn)的公平性,我們先使用Puzzer 工具分別對(duì)每一個(gè)目標(biāo)程序測(cè)試了24h,將變異生成的測(cè)試用例保存下來(lái),作為對(duì)比實(shí)驗(yàn)的測(cè)試用例集。再對(duì)工具 Puzzer 和SiCsFuzzer 在不執(zhí)行變異的前提下,分別執(zhí)行上述測(cè)試用例集,并記錄每個(gè)測(cè)試用例跟蹤覆蓋率的時(shí)間開(kāi)銷。在統(tǒng)計(jì)和對(duì)比過(guò)程中,使用“切尾均值降噪”的方法[21],刪除了執(zhí)行時(shí)間中最高和最低的30%,以減少其他因素對(duì)程序執(zhí)行時(shí)間的影響,更好的展示中位數(shù)的趨勢(shì)。最后,以目標(biāo)程序正常執(zhí)行所需的時(shí)間為“基準(zhǔn)”,將所有執(zhí)行時(shí)間換算為相對(duì)于基準(zhǔn)時(shí)間的“相對(duì)執(zhí)行時(shí)間”。

      5.2 實(shí)驗(yàn)結(jié)果分析

      Q1:圖14 所示為SiCsFuzzer 對(duì)表1 所示的9 個(gè)程序采用稀疏插樁后,每個(gè)目標(biāo)程序中需要插樁的分支數(shù)量占傳統(tǒng)方法(對(duì)所有基本塊/分支插樁)插樁數(shù)量的比例。與傳統(tǒng)模糊測(cè)試默認(rèn)對(duì)所有基本塊插樁的方法相比,目標(biāo)程序需要插樁的分支數(shù)量平均減少了59.39%,最高了減少了67%。

      Q2:接下來(lái),本文分析了采用基于稀疏插樁跟蹤技術(shù)后SiCsFuzzer 的性能。本文記錄了對(duì)于每一個(gè)目標(biāo)程序,采用基于稀疏插樁的覆蓋率跟蹤技術(shù)的SiCsFuzzer 和改進(jìn)前的模糊測(cè)試工具Puzzer 的相對(duì)執(zhí)行時(shí)間。如圖15 所示,采用基于稀疏插樁跟蹤技術(shù)后,SiCsFuzzer 的性能相比Puzzer 提升了16.8%,圖中的折線代表將目標(biāo)程序運(yùn)行在二進(jìn)制插樁平臺(tái)Pin 上,但不對(duì)目標(biāo)程序進(jìn)行插樁的時(shí)間開(kāi)銷,相對(duì)于程序正常執(zhí)行時(shí)間開(kāi)銷進(jìn)行標(biāo)準(zhǔn)化后的比值,簡(jiǎn)稱“Pin 空載”的相對(duì)執(zhí)行時(shí)間。該折線也是采用稀疏插樁跟蹤技術(shù)后,SiCsFuzzer 能達(dá)到的性能上限。實(shí)驗(yàn)結(jié)果表明,對(duì)于所有被測(cè)目標(biāo)程序,Pin 空載的平均相對(duì)執(zhí)行時(shí)間為6.1,Puzzer 的平均相對(duì)執(zhí)行時(shí)間為8.3,而SiCsFuzzer 的平均相對(duì)執(zhí)行時(shí)間為6.9。換而言之,SiCsFuzzer 相對(duì)于對(duì)所有基本塊進(jìn)行插樁的Puzzer,消除了將近64%的插樁開(kāi)銷(計(jì)算方法:(8.3–6.9)/(8.3–6.1))。

      對(duì)于flashplayer這類需要交互的目標(biāo)程序,程序解析完文件后,無(wú)法自動(dòng)結(jié)束,因此對(duì)于程序正常運(yùn)行時(shí)間、Pin 空載時(shí)間和模糊測(cè)試時(shí)間的獲取方法如下:本文將其開(kāi)始顯示視頻內(nèi)容的時(shí)間其作為結(jié)束時(shí)間,然后根據(jù)統(tǒng)計(jì)將它的正常執(zhí)行時(shí)間設(shè)為2 s,Pin 空載時(shí)間設(shè)為3 s。在執(zhí)行模糊測(cè)試之前,通過(guò)逆向確定其解析文件結(jié)束的位置,在該位置插入結(jié)束運(yùn)行的代碼,以此方法獲取交互類軟件的執(zhí)行模糊測(cè)試的時(shí)間。

      Q3:圖 16 所示為使用“預(yù)熱”優(yōu)化后的SiCsFuzzer 與Puzzer 的性能差異。實(shí)驗(yàn)結(jié)果表明,加入“預(yù)熱”優(yōu)化后,SiCsFuzzer 的平均相對(duì)執(zhí)行時(shí)間是2.1,也就是說(shuō)SiCsFuzzer 的平均執(zhí)行時(shí)間是程序正常運(yùn)行時(shí)間的2.1 倍。而改進(jìn)前工具Puzzer 的平均相對(duì)執(zhí)行時(shí)間是8.3。換而言之,SiCsFuzzer 的模糊測(cè)試效率平均比Puzzer 快3 倍(1.24~8.25 倍)。

      對(duì)于選定的9 個(gè)目標(biāo)軟件,gpg和flashplayer的模糊測(cè)試效率甚至分別優(yōu)于這兩個(gè)程序的正常執(zhí)行效率。這是由于引入“預(yù)熱”優(yōu)化后,和目標(biāo)程序正常運(yùn)行相比,SiCsFuzzer 避免了加載和啟動(dòng)目標(biāo)程序的開(kāi)銷,并且只執(zhí)行目標(biāo)程序中選定的部分,即從讀取輸入到程序退出之間的部分。尤其是對(duì)于flashplayer這類圖形界面軟件,加載和啟動(dòng)目標(biāo)程序的開(kāi)銷本身在程序正常執(zhí)行時(shí)間中占比較高,更能發(fā)揮“預(yù)熱”優(yōu)化的優(yōu)勢(shì)。

      Q4:圖17 所示為相同時(shí)間(24 h)內(nèi),SiCsFuzzer與Puzzer 的覆蓋率增長(zhǎng)情況。根據(jù)實(shí)驗(yàn)結(jié)果統(tǒng)計(jì),SiCsFuzzer 平均只用了6.3 h 就達(dá)到了Puzzer 執(zhí)行24 h 才能達(dá)到的覆蓋率。

      對(duì)于部分目標(biāo)軟件(magick,Rar,pdf2html,iview),SiCsFuzzer 在24 h 內(nèi)達(dá)到的覆蓋率明顯高于Puzzer。對(duì)于7zip和gpg兩個(gè)目標(biāo)軟件,在模糊測(cè)試執(zhí)行一段時(shí)間后,覆蓋率不再變化。由此可見(jiàn),在達(dá)到相同覆蓋率時(shí),SiCsFuzzer 所需時(shí)間明顯少于Puzzer,不過(guò)為了更好的提升模糊測(cè)試的效率,仍需要結(jié)合通過(guò)生成有價(jià)值的種子來(lái)提升覆蓋率的方法。

      Q5:WinAFL是AFL的擴(kuò)展版本,其使用二進(jìn)制插樁工具 DynamoRIO[22]跟蹤覆蓋率,以支持Windows 平臺(tái)上目標(biāo)軟件的模糊測(cè)試使用。此外,WinAFL 默認(rèn)開(kāi)啟了與SiCsFuzzer 類似的“預(yù)熱”優(yōu)化機(jī)制,但只保存并恢復(fù)了指定程序點(diǎn)的寄存器狀態(tài),故在實(shí)驗(yàn)過(guò)程,對(duì)本章選定的9 個(gè)目標(biāo)程序,只能成功測(cè)試其中的4 個(gè)目標(biāo)程序。圖18 對(duì)比了SiCsFuzzer 和WinAFL 相對(duì)執(zhí)行時(shí)間。實(shí)驗(yàn)結(jié)果表明,對(duì)于WinAFL 能成功測(cè)試的4 個(gè)目標(biāo)軟件,其模糊測(cè)試效率平均比SiCsFuzzer 快18%。但上述性能差異主要來(lái)自二進(jìn)制插樁平臺(tái)Pin 和DynamoRIO 之間的性能差異[23],且Pin 更加穩(wěn)定,能夠測(cè)試更多的目標(biāo)程序[13]。

      綜上,SiCsFuzzer 在Windows 平臺(tái)9 個(gè)規(guī)模在286KB~19.3MB,類型涉及圖片處理、視頻處理、文件壓縮、加密和文檔處理的應(yīng)用所組成的測(cè)試集上,平均只需對(duì)40.61%的分支進(jìn)行插樁,模糊測(cè)試引入的額外時(shí)間開(kāi)銷為程序正常運(yùn)行時(shí)間的1.1 倍,執(zhí)行效率比傳統(tǒng)的基于覆蓋率反饋的模糊測(cè)試方法快3倍。

      此外,借助SiCsFuzzer,新發(fā)現(xiàn)了PDFtk 最新版本(v2.02)和XnView 最新版本系列軟件Nconvert(v7.32)中的未知漏洞各1個(gè);前者是在文件解析過(guò)程中由于棧溢出導(dǎo)致的程序崩潰;后者是由于內(nèi)存破壞導(dǎo)致軟件崩潰,已獲廠商確認(rèn)。上述未知漏洞的發(fā)現(xiàn)也得益于模糊測(cè)試效率的提升。以XnView 為例,SiCsFuzzer 運(yùn)行6.5 h 后觸發(fā)該漏洞,漏洞觸發(fā)時(shí)的覆蓋率為9.97%;而Puzzer 在運(yùn)行到相同時(shí)間時(shí)的覆蓋率為8.2%,再運(yùn)行18 h 后,才觸發(fā)了漏洞,觸發(fā)漏洞時(shí)的覆蓋率為9.99%。對(duì)于PDFtk,SiCsFuzzer 運(yùn)行4 h 后觸發(fā)該漏洞,漏洞觸發(fā)時(shí)覆蓋率為26.15%;而Puzzer 在運(yùn)行到相同時(shí)間時(shí)的覆蓋率為26.03%,再運(yùn)行9 h 后,才觸發(fā)了漏洞,觸發(fā)漏洞時(shí)的覆蓋率為26.18%。

      6 相關(guān)工作

      當(dāng)前針對(duì)提升模糊測(cè)試性能提升的相關(guān)工作可以分為兩大類[15]:(1)通過(guò)生成有價(jià)值的種子降低模糊測(cè)試整體的開(kāi)銷。因?yàn)橛袃r(jià)值的種子更有可能觸發(fā)軟件漏洞,也就是通過(guò)生成有價(jià)值的種子來(lái)縮短發(fā)現(xiàn)軟件漏洞的時(shí)間,從而降低模糊測(cè)試整體的開(kāi)銷;(2)通過(guò)降低執(zhí)行單個(gè)測(cè)試用例的時(shí)間來(lái)降低模糊測(cè)試的開(kāi)銷。也就是說(shuō),在給定時(shí)間內(nèi),模糊測(cè)試能夠測(cè)試更多個(gè)測(cè)試用例,達(dá)到更高的代碼覆蓋率。目前現(xiàn)有的工作中,大多屬于第一種。而本文通過(guò)降低執(zhí)行單個(gè)測(cè)試用例時(shí)跟蹤測(cè)試用例代碼覆蓋率的開(kāi)銷,屬于第二種方法。兩個(gè)方向的相關(guān)工作如下:

      生成有價(jià)值的種子。生成有價(jià)值的種子主要與以下因素有關(guān):(1)種子選擇策略;(2)種子變異策略。一些研究[3-4]表明種子選擇策略對(duì)模糊測(cè)試非常重要,像libFuzzer[24]對(duì)提升代碼覆蓋率的種子給予更大的優(yōu)先權(quán),因?yàn)檫@樣的種子更有可能探索到目標(biāo)程序未被執(zhí)行到的代碼區(qū)域,VUzzer[12]對(duì)執(zhí)行路徑更深的種子給予更大的優(yōu)先權(quán),因?yàn)閂Uzzer 旨在發(fā)現(xiàn)更深的路徑??傊?良好的種子選擇策略能夠加速模糊測(cè)試工具探索到目標(biāo)程序不同的代碼區(qū)域和發(fā)現(xiàn)軟件漏洞。

      AFL 和libFuzzer 等模糊測(cè)試工具采用一組確定性和隨機(jī)的變異策略對(duì)種子進(jìn)行變異,生成大量的測(cè)試用例,這種方法雖然簡(jiǎn)單,但是在模糊測(cè)試進(jìn)行一段時(shí)間后,很難提升代碼覆蓋率。一些更加先進(jìn)的模糊測(cè)試工具試圖使用一種更聰明的方法對(duì)種子進(jìn)行變異。Driller[25]將模糊測(cè)試與符號(hào)執(zhí)行結(jié)合在一起,當(dāng)覆蓋率不再提升時(shí),通過(guò)符號(hào)執(zhí)行計(jì)算有效輸入。但是,由于符號(hào)執(zhí)行不適用于實(shí)際程序,因此應(yīng)用符號(hào)執(zhí)行來(lái)輔助測(cè)試大型軟件是不切實(shí)際的。VUzzer 使用控制流和數(shù)據(jù)流特征來(lái)識(shí)別要變異的字節(jié)。Skyfire[26]利用大量現(xiàn)有樣本中的知識(shí)來(lái)生成分布良好的種子輸入。

      盡管這些模糊工具可以有效地生成更多有價(jià)值的種子,但它們?nèi)匀幻媾R著執(zhí)行所有測(cè)試用例的開(kāi)銷。因此,降低執(zhí)行單個(gè)測(cè)試用例的開(kāi)銷,也會(huì)帶來(lái)極大的好處。

      降低執(zhí)行單個(gè)測(cè)試用例的開(kāi)銷。文獻(xiàn)[9]就降低執(zhí)行單個(gè)測(cè)試用例的開(kāi)銷提出了改進(jìn)方案UnTracer,其在跟蹤代碼覆蓋率之前,先通過(guò)一輪輕量級(jí)的檢測(cè),判斷變異生成的測(cè)試用例是否是有價(jià)值的測(cè)試用例,即是否能夠觸發(fā)新的基本塊或分支。對(duì)于沒(méi)有價(jià)值的測(cè)試用例,直接丟棄;而針對(duì)有價(jià)值的測(cè)試用例,UnTracer 仍然面對(duì)繼續(xù)跟蹤其覆蓋率的開(kāi)銷;近期的相關(guān)工作[10]提出了二進(jìn)制重寫(xiě)技術(shù)RetroWrite,其速度是QEMU 的4.5 倍,但該工作針對(duì)的目標(biāo)程序?yàn)?4 位的地址無(wú)關(guān)代碼的Linux 閉源程序。并且,文獻(xiàn)[9]的統(tǒng)計(jì)顯示,QEMU 引入的額外開(kāi)銷約為目標(biāo)程序正常執(zhí)行時(shí)間的10 倍,因此得出,RetroWrite 的執(zhí)行速度約為程序正常運(yùn)行的2.4 倍,而本文的SiCsFuzzer 的執(zhí)行速度為程序正常運(yùn)行的2.1 倍。

      文獻(xiàn)[15]提出為模糊測(cè)試工具設(shè)計(jì)三個(gè)操作原語(yǔ),降低了在多核計(jì)算機(jī)進(jìn)行模糊測(cè)試的性能開(kāi)銷。還有一些其他工作,提出使用硬件輔助的方法,如kAFL[7]、PTfuzz[8]和honggFuzz[2]使用Intel Processor Tracking(IPT)[27]進(jìn)行跟蹤測(cè)試用例的代碼覆蓋。但是這些工作對(duì)硬件有一定的要求,不能較好地應(yīng)用于大部分主流的應(yīng)用平臺(tái)。另外,文獻(xiàn)[28]提出了一種插樁方法,使用程序控制流圖的前支配樹(shù)信息來(lái)減少插樁位置的數(shù)量,但是由于只使用了前支配樹(shù)信息,缺乏后支配樹(shù)信息,所以這種插樁策略仍存在冗余。文獻(xiàn)[29]提出結(jié)合前支配樹(shù)和后支配樹(shù)信息來(lái)減少插樁位置的數(shù)量,但是該工作是針對(duì)具有源代碼的目標(biāo)程序。針對(duì)具有源代碼的目標(biāo)程序,這些工作根據(jù)程序的控制流圖信息,通過(guò)前支配樹(shù)信息或結(jié)合后支配樹(shù)信息得到每個(gè)函數(shù)需要插樁的基本塊,然后通過(guò)靜態(tài)插樁的方法即可對(duì)目標(biāo)程序進(jìn)行測(cè)試。而本文是針對(duì)閉源程序(尤其是Windows 平臺(tái)),閉源程序的插樁多使用動(dòng)態(tài)插樁。因此本文詳細(xì)地剖析了動(dòng)態(tài)跟蹤覆蓋率的開(kāi)銷,基于分析結(jié)果,本文提出稀疏插樁的覆蓋率跟蹤技術(shù)和“預(yù)熱”優(yōu)化。本文提出的基于稀疏插樁的覆蓋率跟蹤技術(shù)對(duì)全局控制流進(jìn)行分析,處理了程序中含有exit、abort 等函數(shù)的情況,根據(jù)動(dòng)態(tài)插樁的特點(diǎn),設(shè)計(jì)并實(shí)現(xiàn)了覆蓋率重建算法。結(jié)合“預(yù)熱”優(yōu)化,更有效的降低了模糊測(cè)試的開(kāi)銷。

      7 總結(jié)

      本文提出了一種面向閉源程序的高效模糊測(cè)試方法。該方法借助基于稀疏插樁的覆蓋率跟蹤以及針對(duì)流行的動(dòng)態(tài)二進(jìn)制插樁工具(例如Pin)的“預(yù)熱”優(yōu)化機(jī)制,降低基于覆蓋率反饋的模糊測(cè)試過(guò)程中跟蹤覆蓋率的開(kāi)銷,提高模糊測(cè)試效率?;谠摻鉀Q方案實(shí)現(xiàn)的原型工具SiCsFuzzer,在Windows 平臺(tái)9個(gè)規(guī)模在286KB~19.3MB、類型涉及圖片處理、視頻處理、文件壓縮、加密和文檔處理等類型應(yīng)用所組成的測(cè)試集上,引入的額外時(shí)間開(kāi)銷為程序正常運(yùn)行時(shí)間的1.1 倍,執(zhí)行效率比傳統(tǒng)的基于覆蓋率反饋的模糊測(cè)試工具快3倍。此外,使用SiCsFuzzer,還發(fā)現(xiàn)了PDFtk和XnView軟件最新版本中的未知漏洞各1 個(gè)。

      本文的下一步工作包括以下兩個(gè)方面。首先,本文提出的基于稀疏插樁的覆蓋率跟蹤技術(shù)需要借助靜態(tài)分析技術(shù)得到目標(biāo)程序中各基本塊間的支配關(guān)系。靜態(tài)分析的精度,尤其是對(duì)間接跳轉(zhuǎn)目標(biāo)的識(shí)別精度,將直接影響超級(jí)支配圖的精度,甚至造成有價(jià)值的種子被丟棄。在后續(xù)工作中,將嘗試通過(guò)模糊測(cè)試過(guò)程中記錄的動(dòng)態(tài)執(zhí)行軌跡,反過(guò)來(lái)指導(dǎo)并補(bǔ)充靜態(tài)分析未識(shí)別出的間接跳轉(zhuǎn)目標(biāo),完善控制流圖。此外,目前有很多工作[30-32]致力于提升靜態(tài)分析技術(shù)的準(zhǔn)確性,隨著該技術(shù)的完善,本文提出的算法也將得到更好的效果。其次,如4.1 節(jié)所述,本文方法在實(shí)現(xiàn)過(guò)程中遇到動(dòng)態(tài)插樁工具Pin 與靜態(tài)分析工具IDA Pro 生成的控制流圖對(duì)基本塊的劃分不一致的情況,雖然就目前分析的實(shí)例而言,識(shí)別以mov 指令結(jié)尾的基本塊能在一定程度緩解該問(wèn)題,但仍然不夠精準(zhǔn)。在后續(xù)的工作中,將通過(guò)對(duì)更多實(shí)例的分析總結(jié),歸納并識(shí)別出所有導(dǎo)致基本塊劃分不一致的情況,提高覆蓋率計(jì)算的精度。

      猜你喜歡
      基本塊插樁測(cè)試用例
      砂土中樁靴插樁對(duì)臨近筒型基礎(chǔ)的影響研究
      基于級(jí)聯(lián)森林的控制流錯(cuò)誤檢測(cè)優(yōu)化算法
      基于TXL的源代碼插樁技術(shù)研究
      距離與權(quán)重相結(jié)合的導(dǎo)向式灰盒模糊測(cè)試方法
      基于SmartUnit的安全通信系統(tǒng)單元測(cè)試用例自動(dòng)生成
      一種檢測(cè)控制流錯(cuò)誤的多層分段標(biāo)簽方法
      基于性能分析的自適應(yīng)插樁框架
      基于混合遺傳算法的回歸測(cè)試用例集最小化研究
      基于依賴結(jié)構(gòu)的測(cè)試用例優(yōu)先級(jí)技術(shù)
      基于順序塊的嵌入式白盒測(cè)試插樁技術(shù)研究
      龙岩市| 长沙市| 太白县| 临夏市| 平乡县| 新泰市| 金华市| 珠海市| 临漳县| 泾源县| 南靖县| 铜陵市| 古蔺县| 荃湾区| 两当县| 南溪县| 措勤县| 六盘水市| 邯郸市| 华池县| 高清| 海兴县| 封开县| 始兴县| 木兰县| 达孜县| 汉源县| 青海省| 鹤庆县| 进贤县| 哈尔滨市| 九江市| 保山市| 武冈市| 孝感市| 静宁县| 庆阳市| 璧山县| 紫金县| 华宁县| 调兵山市|