国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

基于Clang編譯前端的Android源代碼靜態(tài)分析技術(shù)①

2017-10-20 03:08曹原野丁麗萍
計算機系統(tǒng)應(yīng)用 2017年10期
關(guān)鍵詞:污點源代碼靜態(tài)

曹原野 ,丁麗萍

1(中國科學(xué)院 軟件研究所 基礎(chǔ)軟件實驗室,北京 100190)2(中國科學(xué)院大學(xué),北京 100049)

基于Clang編譯前端的Android源代碼靜態(tài)分析技術(shù)①

曹原野1,2,丁麗萍1

1(中國科學(xué)院 軟件研究所 基礎(chǔ)軟件實驗室,北京 100190)2(中國科學(xué)院大學(xué),北京 100049)

Android手機在全球占有很大的市場份額,基于Android衍生的第三方系統(tǒng)也為數(shù)不少.針對Android系統(tǒng)重大安全問題頻發(fā)的現(xiàn)狀,提出一種使用Clang編譯前端對Android源碼進行靜態(tài)分析的方法.該方法從已公布的CVE漏洞中提取規(guī)則和模型,通過改進的Clang編譯前端,對Android源碼進行靜態(tài)分析,從而檢測出有潛在安全風(fēng)險的代碼片段.在對Android源碼進行污點分析時,調(diào)用新加入的stp約束求解器,通過符號執(zhí)行,對敏感數(shù)據(jù)進行污點標(biāo)記,并對敏感函數(shù)、敏感操作、敏感規(guī)則進行污點分析,如果存在潛在的安全隱患,則進行報告.經(jīng)過實驗分析,該方法可以找出Android源代碼中存在的同類型有安全風(fēng)險的代碼片段,可以檢出libstagefright模塊5個高危CVE漏洞.

Clang 編譯器; 安卓; 靜態(tài)分析; 污點分析; 符號執(zhí)行

1 引言 111

Android系統(tǒng)因其開源性和開放性,在智能手機市場占有很大的市場份額.近些年來,Android系統(tǒng)不斷發(fā)展,在智能家電、物聯(lián)網(wǎng)等領(lǐng)域迅速攻占市場,與人們的日常生活越來越緊密相關(guān).然而,Android系統(tǒng)的安全問題日益突出,不斷爆出影響極大的安全漏洞,不僅影響了用戶的使用體驗,更嚴(yán)重威脅到了用戶的隱私,例如:具備麥克風(fēng)或攝像頭的Android智能電視被遠(yuǎn)程控制,將會造成非常可怕的隱私泄露.因此,Android硬件廠商在硬件發(fā)布之前,非常有必要對定制的Android系統(tǒng)進行安全審計,以盡可能地減少潛在的安全隱患.對定制的Android源代碼進行安全審計在保護用戶的隱私、減少企業(yè)的開發(fā)成本方面有重要意義.

在研究Android源代碼的CVE(Common vulnerabilities and exposures)漏洞補丁的過程中,發(fā)現(xiàn)部分漏洞存在特定的規(guī)律和模式.本文對這些規(guī)律和模式進行了總結(jié)分析,提出了一種基于改進的Clang編譯前端進行安全分析的靜態(tài)檢測方法,該方法通過Clang編譯前端對指定的Android模塊進行符號執(zhí)行[1,2],通過污點傳播對敏感數(shù)據(jù)進行標(biāo)記,通過對特定的函數(shù)[3,4]、條件分支、語法結(jié)構(gòu)進行污點分析,找到有潛在安全風(fēng)險的代碼片段,并給出相應(yīng)的檢查報告.企業(yè)在對Android系統(tǒng)進行定制修改之后,如果能夠在系統(tǒng)發(fā)布之前,對Android定制系統(tǒng)的源代碼進行安全審計,則可以有效降低定制系統(tǒng)的安全風(fēng)險所帶來的損失[5],同時因為審計的自動化,也可以大幅降低人力成本.

2 相關(guān)研究

代碼審計的最終目標(biāo)是挖掘軟件中潛在的有安全風(fēng)險的漏洞代碼.目前,針對Android系統(tǒng)的漏洞挖掘已經(jīng)有很多成熟的方法.例如:人工審查、模糊測試、動態(tài)分析、靜態(tài)分析等方法.

人工審查就是通過人工閱讀代碼的方式對源代碼進行逐行逐行地分析,判斷是否有安全問題.這要求審查人員有相當(dāng)深厚的審查經(jīng)驗,而且很費時間,適用于簡短但是易錯的代碼,如驅(qū)動代碼.

模糊測試(Fuzz)是指通過給目標(biāo)接口輸入大量的隨機數(shù)據(jù),來測試接口是否能夠正常處理這些畸形數(shù)據(jù)的測試方法.如果接口或系統(tǒng)出現(xiàn)了異常,則認(rèn)為接口極有可能存在缺陷.模糊測試的優(yōu)點是簡單有效,但是相當(dāng)耗費時間,因為是隨機生成的數(shù)據(jù),所以具有一定的概率性.而且測試速率要受制于目標(biāo)接口的響應(yīng)速率.對應(yīng)的工具有Peach等.Peach是一個遵守MIT開源許可證的模糊測試框架,用戶通過編寫Peach Pit配置文件,可以定義Fuzz過程的配置和原始數(shù)據(jù)結(jié)構(gòu)的定義.通過定義原始數(shù)據(jù)結(jié)構(gòu)生成結(jié)構(gòu)化的部分隨機數(shù)據(jù),來實現(xiàn)精確的模糊測試.

動態(tài)分析是指對二進制程序進行插樁,來達(dá)到運行時對程序的控制和監(jiān)控.動態(tài)分析的優(yōu)點是準(zhǔn)確率高,覆蓋面大,但是缺點是依賴于運行平臺,有路徑爆炸的風(fēng)險,并且在編譯過程中損失了一些代碼的細(xì)節(jié)信息.對應(yīng)的工具有 Pin、KLEE、Android_S2E[20]等.Pin是Intel公司提供的二進制插樁工具[6],它允許在可執(zhí)行程序的任何地方插入任意代碼[7].KLEE是一款源代碼動態(tài)符號執(zhí)行工具.KLEE需要修改源代碼,通過對源代碼內(nèi)特定的輸入數(shù)據(jù)進行標(biāo)記,插入自己的符號執(zhí)行代碼,然后編譯執(zhí)行并收集變量信息.Android_S2E是一款全系統(tǒng)符號執(zhí)行工具,它預(yù)裝QEMU模擬器和KLEE在虛擬機上運行Android,并執(zhí)行符號執(zhí)行,可以遍歷Android系統(tǒng)上小型C語言程序的所有路徑.

靜態(tài)分析是指在不運行代碼的情況下,通過多種方式對源代碼進行分析之后,得出源代碼是否存在問題的結(jié)論.分析方法涵蓋簡單的正則、詞法分析、語法分析、上下文路徑敏感分析等.對應(yīng)的工具有Coverity、Clang等.Coverity是一個先進的、可配置的用于檢測軟件缺陷和安全隱患的靜態(tài)代碼分析解決方案,它能自動化地檢測和解決C、C++、Java、C#源代碼中多種類型的缺陷,Coverity對Android系統(tǒng)有針對性優(yōu)化,但是Coverity是收費且閉源的.Clang是LLVM開源編譯套件的一個編譯前端,負(fù)責(zé)將C、C++、Object-C源代碼翻譯為中間代碼[8,9],而且Clang自身具備靜態(tài)分析的能力,可以在不運行代碼的情況下對代碼進行編譯分析.

現(xiàn)有Android系統(tǒng)安全問題的文獻研究多數(shù)集中在Android應(yīng)用層上的研究.對于Android系統(tǒng)自身底層代碼的安全研究的文獻研究其實不常見[10,11].移動安全會議上提到的工業(yè)界常用的方法多集中于模糊測試的方法.使用模糊測試的方法雖然具有一定的隨機性,但是簡單便捷,并且短期內(nèi)容易看到成效.但是,安全研究員如果想要建立一種長效的安全機制,這種機制是穩(wěn)定的,而且可以逐步完善、逐步歸納吸收已有的安全風(fēng)險的話,使用靜態(tài)分析是一種非常合適的方案.

靜態(tài)分析沒有模糊測試的隨機性,分析結(jié)果比較穩(wěn)定.并且,通過對現(xiàn)有的安全風(fēng)險進行歸納吸收,可以不斷完善靜態(tài)分析工具,那么靜態(tài)分析工具就能夠在檢測能力上得到持續(xù)加強.而一款能夠持續(xù)加強的靜態(tài)分析工具必須是開源的,所以本文主要調(diào)研了Clang編譯前端對Android源代碼進行靜態(tài)分析的難點.

本文經(jīng)過調(diào)研,使用Clang成功對Android源代碼進行了分析,并主要克服了 3個方面的困難.1)新版的Clang 3.8無法直接對Android源代碼進行分析,需要做兼容處理.2)Clang自帶的約束求解器的求解能力過弱,不適合應(yīng)用在Android源代碼這種復(fù)雜項目上.3)Clang自帶的檢測規(guī)則是通用檢測規(guī)則,沒有針對Android源代碼的檢測規(guī)則,導(dǎo)致檢測能力過弱.

本文克服了上述3個困難,最終實現(xiàn)了目標(biāo):實現(xiàn)一種工業(yè)界可用的,基于改進的Clang編譯前端的,用于Android系統(tǒng)源代碼的靜態(tài)分析方法.

3 基于Clang編譯前端的靜態(tài)分析原理

Clang作為LLVM編譯套件的編譯前端,自帶一個靜態(tài)代碼分析工具,可以編譯分析C、C++、Object-C源代碼,此靜態(tài)分析工具屬于Clang的一部分因而完全開源.

Clang在對源代碼進行編譯的時候,會通過靜態(tài)分析,對代碼風(fēng)格、語法錯誤和潛在的風(fēng)險進行warning警告.Clang靜態(tài)分析器通過自定義代碼可以實現(xiàn)更復(fù)雜的檢測機制來進行靜態(tài)分析.Clang的靜態(tài)分析器首先通過程序代碼,生成AST(語法樹),然后根據(jù)AST生成 CFG(控制流圖),通過符號執(zhí)行生成擴展圖(ExplodedGraph),具體控制流程如圖1[12]所示.

圖1 Clang 的靜態(tài)分析過程

通過自定義Checker(Clang中的檢查器,用來檢測自定義缺陷),可以實現(xiàn)對AST和ExplodedGraph的分析和控制.Checker不僅僅只能是被動的調(diào)用,Checker也能主動地修改ExplodedGraph.如果Checker認(rèn)為存在特定的缺陷,就可以調(diào)用BugReport來報告存在的缺陷,方便測試人員可視化地觀察檢測信息.

Clang的AST樹近似于常規(guī)的編程語法結(jié)構(gòu).通過“clang-Xclang-ast-dump example.cpp”可以對源代碼生成的AST進行觀察.AST語法樹主要由兩類結(jié)點(Stmt與Decl)和派生自他們的子結(jié)點構(gòu)成.Stmt是指statement語句,Decl是指 declarations聲明.

Clang的CFG控制流圖由若干個CFGBlock塊組成,每個CFGBlock均包含有EXIT塊和ENTRY塊.并且每個CFGBlock塊由一組CFGElement組成,其中的CFGElement代表AST樹中的一個結(jié)點.

Clang的ExplodedGraph圖是在通過符號執(zhí)行遍歷CFG圖的時候產(chǎn)生的.ExplodedGraph中的每個結(jié)點,都包含了 ProgramPoint點和 State 信息.Program-Point點,用來定義源代碼運行到該點時所有變量的值.State信息用來表示源代碼在符號執(zhí)行過程中的狀態(tài)信息,包括:表達(dá)式到值的映射關(guān)系、各種變量到值的映射關(guān)系、路徑條件約束等信息.

通過Clang的源碼,可以發(fā)現(xiàn),如果將Clang的靜態(tài)分析直接應(yīng)用到Android系統(tǒng)源碼之上,基本沒有效果.一個原因是Clang自帶的range約束求解器的求解能力過于薄弱,只能處理簡單約束.另一個原因是Clang作為一個通用編譯前端,更注重的是通用性,所以特定問題的檢測能力不強.需要對Clang的符號執(zhí)行能力和檢測能力進行增強.所以,以下小節(jié)將逐個描述對Clang進行加強的實現(xiàn)原理.

3.1 改進Clang靜態(tài)分析Android源碼的兼容性

Android源碼內(nèi),含有LLVM的預(yù)編譯工具鏈,但是直到最新的Android7.1的源代碼,LLVM預(yù)編譯工具鏈中Clang的版本仍舊是3.3版本.本文需要定制較新的Clang3.8版本進行靜態(tài)分析.所以需要了解Clang靜態(tài)分析指令和Android源代碼的編譯腳本工作原理.

Clang靜態(tài)分析由兩個指令構(gòu)成,分別是“scanbuild”和“scan-view”命令.“scan-build”命令后面緊接著正常的編譯命令,例如“scan-build g++ example.cpp”或者“scan-build make-j4”這種編譯命令.其中“scan-build”命令會對后面的編譯命令進行分析,替換其中的編譯器為Clang本身,則Clang可以順利地進行靜態(tài)分析.“scan-build”在分析完畢之后,會留下一個特殊的目錄,使用“scan-view”打開這個目錄,則可以顯示分析報表.

Android源代碼的編譯腳本主要集中在源代碼根目錄的build/envsetup.sh文件里.其中主要有4個編譯命令,分別是 mmm、mm、m、make 命令.mmm 命令主要用于編譯指定路徑下的模塊,mm命令用于編譯當(dāng)前路徑下的模塊,m命令編譯當(dāng)前目錄下的所有模塊,make命令則是編譯整個Android系統(tǒng).為了靜態(tài)分析的需要,主要進行單個模塊的分析,所以選用mmm命令.通過更換mmm命令后的路徑,可以實現(xiàn)不同模塊的靜態(tài)分析.“mmm path-B”其中的“-B”參數(shù)則是無論源碼修改與否都強制編譯path目錄下的所有源碼.

直接使用“scan-build mmm path-B”則會直接報錯.通過研究envsetup.sh的代碼,發(fā)現(xiàn)在getdriver函數(shù)聲明了靜態(tài)分析的使用規(guī)則和“scan-build”的二進制路徑,將getdriver函數(shù)的“scan-build”路徑改為改進的Clang源代碼生成的“scan-build”路徑.同時執(zhí)行“WITH_STATIC_ANALYZER=1 mmm path-B”則可成功啟動改進Clang的靜態(tài)分析.但是,分析途中一定會出錯,因為高版本的Clang已經(jīng)不支持一些舊命令參數(shù),所以需要對“scan-build”編譯腳本調(diào)用的其他編譯腳本進行兼容修改.經(jīng)過修改的的編譯腳本可以正確對某個模塊進行靜態(tài)分析.

3.2 增強Clang的符號執(zhí)行能力

SMT(Satisfiability modulo theories)可以用來解決邏輯公式的決策問題[13],可以用來處理布爾運算、量詞、算術(shù)運算、比較運算、位運算等約束性求解問題.SMT模型有一些具體的約束求解器實現(xiàn),例如:z3約束求解器、stp約束求解器等.這些求解器具備強大的求解能力,可以處理編程語言中常見的復(fù)雜條件判斷、位運算、數(shù)組操作等.

符號執(zhí)行是CFG生成ExplodedGraph時使用的.Clang靜態(tài)分析程序讀取CFG,當(dāng)遇到條件分支時,會根據(jù)不同的條件分支,依次執(zhí)行不同的條件分支.在執(zhí)行不同的條件分支之前,符號執(zhí)行會把進去當(dāng)前分支所需要的條件放入約束求解器查詢,如果當(dāng)前條件滿足約束求解器,則執(zhí)行分支并把分支條件放入約束求解器,否則不執(zhí)行當(dāng)前分支.

Clang具備符號執(zhí)行的能力,但是其自帶的range約束求解器能力不強,只支持簡單約束條件,遇到多元約束條件不能處理則忽略,這大大削弱了符號執(zhí)行的準(zhǔn)確性.在實際的復(fù)雜代碼中,這個自帶的約束求解器在精度方面經(jīng)常不能滿足預(yù)想的要求.

但是Clang本身支持約束求解器的擴展,可以通過仿照range約束求解器的編寫方式,修改Clang配置文件,增加新的約束求解器,達(dá)到增強約束求解器的目的.

本文通過修改Clang源碼,加入了stp約束求解器,使Clang可以處理復(fù)雜的多元約束求解.通過增強Clang符號執(zhí)行的約束求解能力,提高其檢測精度.

3.3 增強Clang的靜態(tài)檢測能力

作為一款通用編譯前端,Clang所面對的是通用場景的代碼.其靜態(tài)分析里的檢測規(guī)則面向的是常見的缺陷問題.所以,Clang對于特殊模式的問題無法進行正確檢測而得出結(jié)果.于是,在使用Clang對Android的源碼進行分析之前,需要預(yù)先增強Clang的靜態(tài)檢測能力.

對于Android系統(tǒng),如果Clang想要檢測出安全風(fēng)險,就需要預(yù)先知道可能的攻擊面.Android系統(tǒng)因為豐富的交互功能,其本身具有很多潛在的攻擊面.攻擊面可以分為 4 類.1)遠(yuǎn)程攻擊面:主要包含了網(wǎng)絡(luò)協(xié)議棧、對外暴露的網(wǎng)絡(luò)服務(wù)、短信、彩信、基礎(chǔ)軟件(瀏覽器接口、多媒體和文檔處理、電子郵件)等.2)物理相鄰的攻擊面:無線、藍(lán)牙、NFC 等.3)本地攻擊面:文件系統(tǒng)、系統(tǒng)調(diào)用等.4)物理連接攻擊面:USB連接等.

可被用戶控制的數(shù)據(jù)從這些攻擊面,流入到系統(tǒng)的控制流中,如果處理不當(dāng),則可能會引入安全風(fēng)險.所以,靜態(tài)分析的主要目標(biāo),就是需要頻繁從攻擊面獲取數(shù)據(jù)的模塊,例如:libstagefright模塊.為此,需要設(shè)定一段污點傳播程序,對Android源碼中有可能從攻擊面引入的危險數(shù)據(jù)加上污點標(biāo)記.并對污染的數(shù)據(jù)進行污點傳播,即圖2的“敏感函數(shù)污點標(biāo)記”.敏感函數(shù)例如:內(nèi)存操作函數(shù)、網(wǎng)絡(luò)操作函數(shù)、緩沖區(qū)管理函數(shù)、文件管理函數(shù)等.

圖2 增強的靜態(tài)檢測邏輯

在Android源代碼里,充滿了大量的宏定義和復(fù)雜的工具類,給開發(fā)人員帶來了巨大的便利,但是也給開發(fā)人員帶來了困擾:有時候會不記得當(dāng)前的變量到底是什么類型,有時候會忘記一些必須的操作.以下總結(jié)一些在Android源代碼漏洞中常見的錯誤模式.

(1)敏感函數(shù)的參數(shù)錯誤

memcpy(dest,src,len);

在復(fù)雜邏輯中,開發(fā)人員可能會忽略對len的正確約束,導(dǎo)致len可以賦值為一個超大的整數(shù)值.

(2)隱式轉(zhuǎn)換

memcpy(dest,src,len);

在開發(fā)中,開發(fā)人員混淆了len的類型,直接將有符號數(shù)直接傳入?yún)?shù),同時沒有限制len必須大于等于0.

long long a = int_b + int_c + (long long)d;

在開發(fā)中,遇到一個復(fù)雜計算式,而且數(shù)據(jù)類型不一致時,開發(fā)人員意識到需要進行強制類型轉(zhuǎn)換.但是強制類型轉(zhuǎn)換過晚,int_b和int_c已經(jīng)發(fā)生了溢出并進行了隱式轉(zhuǎn)換之后,才與d變量進行相加.

(3)分支條件

if(int_e+100

在開發(fā)中,開發(fā)人員忘記int_e的范圍沒有進行約束,有可能發(fā)生溢出.

if(int_j < uint_k)

在開發(fā)中,開發(fā)人員忘記int_j的類型,且沒有約束int_j必須大于等于0.

為了對上述3種錯誤模式進行追蹤檢查,要預(yù)先設(shè)定鉤子函數(shù)進行捕獲,當(dāng)鉤子函數(shù)捕捉到其中之一的模式正在發(fā)生,且包含有污點數(shù)據(jù)的時候,啟動進一步分析.例如:內(nèi)存分配函數(shù)、變量隱式轉(zhuǎn)換、條件判斷表達(dá)式這三種情況.這三種情況依次對應(yīng)圖2中的“敏感函數(shù)污點分析”,“污點數(shù)據(jù)類型轉(zhuǎn)換”,“分支條件判斷污點”.啟動進一步分析之后,對應(yīng)到圖2中的“溢出判斷”和“規(guī)則判斷”.

“溢出判斷”是指通過獲取污點變量的取值范圍[14,15],判斷是否存在于合法的區(qū)間.首先,通過Clang獲取污點變量的類型,根據(jù)變量類型生成對應(yīng)的最大值和最小值.通過stp約束求解器的查詢功能,查詢污點變量是否能夠取到最大值的同時再取到最小值,如果可以同時取到,則認(rèn)為存在風(fēng)險.

“規(guī)則判斷”是指通過設(shè)定若干組語法樹規(guī)則,對含有污點數(shù)據(jù)的語法樹進行匹配判斷.例如:當(dāng)發(fā)現(xiàn)污點數(shù)據(jù)在二元算式之后發(fā)生了類型提升,而且是隱式類型提升的時候,說明在編程語法上存在安全風(fēng)險,此時可提示有潛在的安全風(fēng)險.

4 Android 源碼靜態(tài)分析的實現(xiàn)

4.1 對Android源代碼的修改

建立Android源代碼的本地mirror,從mirror拉取branch為android-5.1.1_r14(為了進行對比實驗,需要拉取若干個branch)的分支,安裝好編譯工具,配置Android5.1.1的編譯環(huán)境和二進制輸出目錄,進入Android代碼目錄,執(zhí)行代碼1的指令.

代碼1.編譯所有Android源代碼$ source build/envsetup.sh$ lunch aosp_arm-eng$ make -j4

在靜態(tài)分析之前,必須先整體編譯一次Android,因為一個模塊在編譯的時候經(jīng)常會依賴其他模塊,如果在靜態(tài)分析前先全部編譯一次,就不會出現(xiàn)找不到依賴模塊的情況.

Android整體編譯完成之后,在Android的源代碼目錄下編輯build/envsetup.sh下按照代碼2進行編輯.修改--use-analyzer參數(shù)后面的路徑,更新為修改過的Clang程序的二進制文件.

Android源代碼的工具鏈自帶了一套Clang3.3編譯前端,但是其版本太低,需要如代碼 3 里所示,修改/prebuilts/misc/linux-x86/analyzer/bin/ccc-analyzer文件,做下列兼容工作,否則改進的Clang3.8無法正常運行.其主要操作是:通過參數(shù)指定Clang3.8使用新加入的stp約束求解器,并且替換一些傳遞的過時的命令行參數(shù).

?

push @Args,“-Xclang”,“-analyzer-viz-egraph-ubigraph”;}+ //強制Clang編譯器使用本實驗新加入的stp求解器+ push @Args,“-Xanalyzer”,“-analyzer-constraints=stp”; my$AnalysisArgs = GetCCArgs(“--analyze”,@Args); @CmdArgs =@$AnalysisArgs;+ //對參數(shù)進行修改,以適應(yīng)新的Clang編譯器+ my @NewCmdArgs;+ foreach my $one (@CmdArgs){+ if($one eq “-Qignore-c-std-not-allowed-with-cplusplus”+ || $one eq “-fobjc-default-synthesize-properties”+ || $one eq “-fno-cxx-missing-return-semantics”)+ {next;}+ if($one eq “-disable-global-ctor-const-promotion”){+ push(@NewCmdArgs,“-disable-cgp-ext-ld-promotion”);+ next;+ }

$one);+ @CmdArgs = @NewCmdArgs;

代碼4.替換新的Clang編譯前端if($pid == 0){ close FROM_CHILD; open(STDOUT,“>&”,*TO_PARENT); open(STDERR,“>&”,*TO_PARENT);+ //置為實驗修改的Clang的二進制的地址+ $Cmd = “xxx”;exec $Cmd,@CmdArgs; }

再如代碼4所示,修改/prebuilts/misc/linux-x86/analyzer/bin/ccc-analyzer文件,修改內(nèi)部使用的$Cmd變量.從而完成對 Android 源碼的修改.此時,已經(jīng)可以使用Clang3.8正常編譯分析Android系統(tǒng)源代碼.

4.2 添加stp約束求解器

首先,安裝 stp約束求解庫,需要安裝 minisat庫和 stp 庫.然后,進入 llvm 源碼,在 tools/clang/lib/Static-Analyzer/Core/目錄下仿照現(xiàn)有的RangeConstraint-Manager.cpp編寫調(diào)用stp求解器的STPConstraint-Manager.cpp,并對外提供接口CreateSTPConstraint-Manager返回STPConstraintManager類的實例供靜態(tài)分析核心使用.

STPConstraintManager.cpp可以參考網(wǎng)絡(luò)上已有的樣例約束求解器代碼進行修改,但是需要注意因為本文使用的Clang是新版的,必須注意代碼的兼容性問題(過時的接口、類或結(jié)構(gòu)體的成員的變動),否則程序無法正常執(zhí)行.

最后,如代碼 5 所示,在 tools/clang/include/clang/StaticAnalyzer/Core/Analyses.def中加入如下一行聲明(注意要和STPConstraintManager類的接口Create-STPConstraintManager名稱相同),可以支持在命令行選擇實際使用的求解器(range求解器或者stp求解器),方便進行對比實驗分析.

代碼5.增加新的約束求解器ANALYSIS_CONSTRAINTS(STPConstraints,“stp”,“Use STP solver”,CreateSTPConstraintManager)

4.3 改進Clang的Checker

如圖1所示,Clang編譯前端在靜態(tài)分析中,真正執(zhí)行缺陷判斷的是一系列的Checker.所以,為了增強Clang的靜態(tài)檢測能力,必須對Clang的一系列的Checker進行增強.

污點傳播部分,修改LLVM代碼里的toolsclanglibStaticAnalyzerCheckersGenericTaintChecker.cpp.這個Checker支持對C的函數(shù)進行污點標(biāo)記和傳播,但是不支持對C++類的處理.對這個Checker進行增強,加入對C++類的判斷和處理.

因為Android系統(tǒng)代碼的復(fù)雜性,系統(tǒng)代碼對相當(dāng)一部分的文件和內(nèi)存操作都進行了封裝.在對C++的成員方法進行分析時,可以對參數(shù)或者返回值進行污點標(biāo)注.在實際標(biāo)注的時候可以根據(jù)待分析代碼的具體特征(例如:通用buffer緩沖類,及其他文件操作、內(nèi)存操作的通用類)添加特定處理,來進行污點設(shè)定.開啟 (默認(rèn) C l a n g不開啟)這個修改過的Checker即可實現(xiàn)數(shù)據(jù)的污點標(biāo)記.

“敏感函數(shù)污點分析”部分可以通過表1中check::CheckPreCall搶在函數(shù)調(diào)用之前,進行分析.“污點數(shù)據(jù)類型轉(zhuǎn)換”可以通過check::CheckPreStmt進行攔截判斷,通過對Expr的判斷,抽取其中的隱式轉(zhuǎn)換和顯式轉(zhuǎn)換,進行分析.“分支條件判斷污點”可以通過check::CheckBranchCondition對條件分支進行攔截,并對其中的Stmt進行判斷.

表1 Clang 的路徑敏感分析接口

圖2中的“溢出判斷”可以通過Clang內(nèi)置的SValBuilder類的evalBinOpNN方法對污點變量的范圍進行估計,測試污點變量是否經(jīng)過正確約束.

圖2中的“規(guī)則判斷”則可以通過ASTContext類的getParents(node)方法獲取父節(jié)點,或者通過node本身自帶的各種方法獲取其子結(jié)點.甚至可以使用Clang內(nèi)置的RecursiveASTVisitor類實現(xiàn)對某個結(jié)點的子結(jié)點進行自動遞歸查詢.

4.4 漏洞代碼的特征分析及處理

代碼6展示了CVE-2015-1538的部分補丁.

代碼6.CVE-2015-1538部分補丁代碼mTimeToSampleCount = U32_AT(&header[4]);- uint64_t allocSize = mTimeToSampleCount * 2 * sizeof(uint32_t);+ uint64_t allocSize = mTimeToSampleCount * 2 *(uint64_t)sizeof(uint32_t);

代碼6中的缺陷存在著固定的模式:污點數(shù)據(jù)由uint32類型參與運算提升為uint64類型,但程序員沒有意識到溢出發(fā)生在類型的隱式轉(zhuǎn)換之前.所以引入了潛在的溢出風(fēng)險,故補丁加入了強制轉(zhuǎn)換.

但是,代碼6里的補丁仍舊是錯誤的!這導(dǎo)致了后序的漏洞CVE-2015-6601.仔細(xì)觀察代碼6中的補丁,程序員的補丁里顯然意識到了污點數(shù)據(jù)隱式轉(zhuǎn)換的危險性,但是程序員忘記了計算是從左到右執(zhí)行的.強制轉(zhuǎn)換太遲了,污點數(shù)據(jù)仍舊可以先溢出,再提升類型.

如代碼6所示,U32_AT是libstagefright從緩沖區(qū)讀取數(shù)據(jù)的公共方法,類似的還有U16_AT、U64_AT.U32_AT函數(shù)會觸發(fā)圖2中的“敏感函數(shù)污點標(biāo)記”,使mTimeToSampleCount變量被標(biāo)記.代碼6中對allocSize的賦值操作中,實際上發(fā)生了類型提升(未打補丁是隱式提升,打了錯誤的補丁是顯式提升).如果表達(dá)式中包含污點數(shù)據(jù)且存在類型提升,則Chekcer觸發(fā)圖2中的“污點數(shù)據(jù)類型轉(zhuǎn)換”會對其中的類型轉(zhuǎn)換進行檢查.

代碼7展示了CVE-2015-6604的部分補丁.

代碼7.CVE-2015-6604部分補丁代碼return false;}- if (offset + dataSize + 10 > mSize){+ if (dataSize > mSize-10- offset){return false;}

代碼7中的缺陷存在著固定的模式:在一個條件分支語句中,程序員忽視了污點數(shù)據(jù)的存在,過分相信變量,直接讓污點數(shù)據(jù)參與了計算,之后再參與比較判斷.

如代碼 7所示,其中 dataSize的數(shù)據(jù),由 U32_AT方式獲取,故被標(biāo)記為污點數(shù)據(jù).但是在if條件判斷語句中,因為條件判斷表達(dá)式含有污點數(shù)據(jù),故觸發(fā)圖2中的“分支條件判斷污點”,對條件表達(dá)式進行求值分析.

4.5 Clang的報告生成

在4.3章中使用Clang的Checker對待檢測代碼進行分析之后,如果發(fā)現(xiàn)潛在的問題,則使用Clang自帶的BugReport進行風(fēng)險代碼的報告.通過定義一個自定義BugReport,可以實現(xiàn)特定格式內(nèi)容的Bug報告.在分析結(jié)束之后,通過scan-view命令打開分析報告網(wǎng)頁,對分析結(jié)果進行查看.

5 實驗及結(jié)果分析

5.1 試驗環(huán)境

本文使用 Ubuntu16.04 LTS X64 操作系統(tǒng),處理器 Intel酷睿 i7 4750HQ(3.2 GHz),16 GB 內(nèi)存,80 GB交換分區(qū),1000 GB 機械硬盤.基于 Clang3.8 進行測試修改.靜態(tài)分析期間,不同時運行其他程序,以免影響時間和內(nèi)存使用的實驗結(jié)果.

Clang運行參數(shù)方面,除了第3章節(jié)所做的代碼修改和實驗過程中輸入的動態(tài)參數(shù),其余配置保持默認(rèn)參數(shù)不變.因為符號執(zhí)行會出現(xiàn)路徑爆炸問題,Clang會使用一個默認(rèn)最大循環(huán)執(zhí)行次數(shù)來進行限制,默認(rèn)值是4,本實驗不修改.

5.2 使用測試集對改進后的Clang進行驗證

經(jīng)過改進的Clang不能直接用于Android系統(tǒng)的代碼分析,需要首先確保修改的正確性,保證改進后的Clang編譯前端本身沒有邏輯錯誤.一個錯誤的Clang編譯前端在分析Android源代碼時的結(jié)果是不可信的.而改進的Clang編譯前端的代碼修改集中在符號執(zhí)行和整形溢出檢測上,所以需要一組整形溢出測試集驗證Clang的符號執(zhí)行精度和整形溢出檢測能力.

測試集的選取,選用的是從NIST網(wǎng)站下載的美國 NSA (National security agency)開發(fā)的 Juliet_Test_Suite[24]測試集.Juliet_Test_Suite 測試集包含多種CWE (Common weakness enumeration)[16]類型的常見漏洞代碼.本實驗選取其中的“CWE190_Integer_Overflow”測試集.其測試集下總共有5種類型的子測試集,分別編號 S01,S02,S03,S04,S05.

通過特定的宏定義,可以調(diào)整測試集的檢測特性.如:只檢測存在有安全缺陷的函數(shù)、只檢測不存在安全缺陷的函數(shù)、檢測全部函數(shù).表2顯示了5個子測試集的函數(shù)用例數(shù)量.

表2 測試集溢出漏洞用例數(shù)量 (個)

測試過程中,采用子測試集逐個進行測試的方式執(zhí)行.單個子測試集在測試的時候,分為六次測試.前兩次使用未修改的原生的Clang且使用自帶的range約束求解器分別測試安全函數(shù)和不安全函數(shù).中間兩次使用改進的Clang且使用自帶的range約束求解器分別測試安全函數(shù)和不安全函數(shù),后兩次使用改進的Clang且使用新加入的stp約束求解器分別測試安全函數(shù)和不安全函數(shù).運行靜態(tài)分析的時候,記錄分析所需要的時間,并分析所得到的結(jié)果,測試所需時間如表3所示.其中,good_origin_range 指原生的 Clang 使用自帶的range求解器只檢測安全函數(shù),good_improved_range指改進的Clang使用自帶的range求解器只檢測安全函數(shù),good_improved_stp指改進的Clang使用新加入的stp求解器只檢測安全函數(shù).bad_origin_range,bad_improved_range,bad_improved_stp 指相同的情況下只檢測不安全函數(shù).

表3 靜態(tài)分析所需時間 (秒)

通過表3分析發(fā)現(xiàn),不管是只檢測安全函數(shù)還是只檢測不安全函數(shù),在都使用自帶的range求解器的情況下,改進的Clang比原生的Clang檢測時間增長了約兩倍,這是因為改進的Clang增加了污點傳播等更多的檢測規(guī)則,導(dǎo)致檢測時間的增大.同樣是改進的Clang,使用新增加的stp求解器比使用range求解器耗費的時間都要多,但是基本不多于10%,這是因為stp的求解能力更強,規(guī)則更復(fù)雜,導(dǎo)致了耗費時間的增加.

表4 中“good_origin_range”和“bad_origin_range”分別指原生Clang使用自帶的range求解器測試安全用例和不安全用例的情況.通過測試發(fā)現(xiàn),基本只能找到“Dead assignment”,“Dead initialization”,“Memory leak”這三種錯誤.不管是安全測試用例還是不安全測試用例,均無法檢出任何溢出漏洞.這是因為原生的Clang本身無對應(yīng)的檢測規(guī)則.

表4 檢出溢出類型漏洞數(shù)量 (個)

表4 中的“good_improved_range”和“good_improved_stp”分別指改進的Clang使用自帶range求解器或stp求解器分別對安全用例的檢測情況.改進的Clang,因為檢測規(guī)則的增加,已經(jīng)可以檢測溢出漏洞.但是,安全測試用例中是沒有不安全的用例的.所以,通過比較,在使用 range求解器的情況下,有超高的誤報,而stp的誤報則是非常的低.具體原因是range求解器的能力過弱,很多復(fù)雜約束不能處理,導(dǎo)致實際上沒有成功加入約束條件,導(dǎo)致了大量的誤報.其中誤報的數(shù)量甚至超過了測試用例的數(shù)量,一個原因是某些用例有多種測試方法,此外如圖2所示,改進的Clang有3種觸發(fā)方式進行缺陷分析,一個函數(shù)由若干行的代碼構(gòu)成,所以一個函數(shù)體可能檢出不少于1個漏洞.

不安全測試用例在源代碼的對應(yīng)代碼行的注釋中,進行了標(biāo)注.表4 中的“bad_improved_range”和“bad_improved_stp”分別指改進的Clang使用自帶range求解器或stp求解器分別對不安全用例的檢測情況.通過對測試報告的排查,stp求解器雖然檢出的結(jié)果比較少,但是非常準(zhǔn)確.range求解器檢出的結(jié)果存在大量的誤報,將測試用例的源代碼中,沒有標(biāo)記為缺陷位置的代碼檢測為存在缺陷.

收集測試用例的靜態(tài)分析結(jié)果,同時收集靜態(tài)分析日志,結(jié)合在一塊進行分析,可以得出結(jié)論:stp 求解器雖然在時間耗費上比range求解器稍多,但是在約束求解精度上,stp求解器有很大的提高; 同時結(jié)合靜態(tài)分析日志和測試用例源代碼,對比stp求解器的約束區(qū)間,可以發(fā)現(xiàn)求解器計算出了正確約束區(qū)間.

5.3 使用改進的Clang編譯前端對Android源碼進行分析

參考第4節(jié)的“Android代碼靜態(tài)分析的實現(xiàn)”里的實現(xiàn),整個Android源代碼在編譯和修改完畢之后,運行代碼8里的指令,即可使用改進的Clang且使用stp約束求解器對Android源碼進行靜態(tài)分析.

代碼8.執(zhí)行靜態(tài)分析$source build/envsetup.sh$lunch aosp_arm-eng$WITH_STATIC_ANALYZER=1 mmm model_path -B

本實驗主要通過“WITH_STATIC_ANALYZER=1 mmm frameworks/av/media/libstagefright/-B”對Android源代碼的libstagefright模塊進行分析.通過對Android不同版本的源碼進行靜態(tài)分析,對于未打補丁的源碼可以找出以下高危漏洞,其漏洞CVE編號分別如下:CVE-2015-1538,CVE-2016-6601,CVE2015-3832,CVE-2015-3831,CVE-2015-6604.

圖3 CVE-2015-1538 漏洞檢測結(jié)果界面

5.4 分析過程的時間復(fù)雜度、空間復(fù)雜度及優(yōu)化

本實驗的分析工具在時間復(fù)雜度上耗時較大,分析簡單的libmedia模塊需要十幾分鐘,但是分析復(fù)雜的libstagefright模塊就需要幾十個小時.通過使用linux下的perf性能調(diào)優(yōu)工具對分析過程(不能直接分析第5.3節(jié)中的mmm命令,分析mmm函數(shù)解析后的命令)進行分析,發(fā)現(xiàn)耗時的TOP-50函數(shù)均是來自libstp.so和libminisat.so里的函數(shù),兩個庫文件里的函數(shù)總共占用了95%以上的運行時間.其中l(wèi)ibstp.so是分析工具所依賴的STP求解器的庫文件,libminisat.so是libstp.so所依賴的庫文件.運行時間主要耗費在求解表達(dá)式.

本實驗的分析工具在空間復(fù)雜度上耗費也較大.如分析 libmedia 模塊需要 1–2 GB 內(nèi)存,分析 libstagefright模塊需要 2–4 GB 內(nèi)存,短時間會使用 16 GB 以上內(nèi)存.通過使用linux下的gdb和valgrind內(nèi)存分析工具對分析過程進行分析,主要發(fā)現(xiàn)libstp.so庫文件與加入的STP求解器代碼存在內(nèi)存泄露問題,其中存在少數(shù)沒及時釋放的大內(nèi)存塊,導(dǎo)致了大量的內(nèi)存占用.

針對時間復(fù)雜度和空間復(fù)雜度的問題,對本實驗的分析工具進行對應(yīng)的優(yōu)化,在加入的STP求解器的代碼部分,加入了遺漏的釋放資源的代碼,降低內(nèi)存占用,減少了部分內(nèi)存泄露.同時對Checker里的檢測代碼進行優(yōu)化,盡量用循環(huán)來取代遞歸,同時將符號執(zhí)行里的污點數(shù)據(jù)按照符號執(zhí)行地址存放在公共map數(shù)據(jù)結(jié)構(gòu)里,進行加速,以此節(jié)約內(nèi)存和時間.

6 結(jié)語

本文提出了使用改進的Clang對Android源代碼進行靜態(tài)分析的研究和實現(xiàn),通過新增Clang的約束求解器并對靜態(tài)檢測功能進行改進,實現(xiàn)了對Android部分類型漏洞的靜態(tài)分析檢測,并成功檢測到部分漏洞.最終實現(xiàn)了可用的對Android源代碼進行分析檢測的實用靜態(tài)分析工具.

但是分析工具自身還存在一些問題,例如:時間耗費較長、內(nèi)存耗費較大,經(jīng)過第5.4節(jié)的優(yōu)化,解決了部分問題,但是內(nèi)存泄露問題沒有徹底去除,耗時仍舊偏長; 此外靜態(tài)分析自身的符號執(zhí)行存在一定偏差,面對特別復(fù)雜的約束條件和調(diào)用過程,不能準(zhǔn)確地進行約束求解.而且,圖2的“溢出判斷”中的判斷方法有些粗糙,容易造成漏報,“溢出判斷”需要對加減乘除等各種情況進行仔細(xì)地處理,這些處理需要大量的細(xì)節(jié)進行完善.

1Dietz W,Li P,Regehr J,et al.Understanding integer overflow in C/C++.ACM Trans.on Software Engineering and Methodology (TOSEM),2015,25(1):2.

2Bush WR,Pincus JD,Sielaff DJ.A static analyzer for finding dynamic programming errors.Software-Practice &Experience,2000,30(7):775–802.

3Schmidt D,Steffen B.Program analysis as model checking of abstract interpretations.International Static Analysis Symposium.Pisa,Italy.1998.351–380.

4Cadar C,Dunbar D,Engler D.KLEE:Unassisted and automatic generation of high-coverage tests for complex systems programs.Proc.of the 8th USENIX Conference on Operating Systems Design and Implementation.San Diego,California,USA.2008.209–224.

5Kremenek T.Finding Software Bugs with the Clang Static Analyzer.California:Apple Inc,2008.

6Xu ZX,Kremenek T,Zhang J.A memory model for static analysis of C programs.International Symposium on Leveraging Applications of Formal Methods,Verification and Validation.Heraklion,Crete,Greece.2010.535–548.

7Khedker U,Sanyal A,Sathe B.Data Flow Analysis:Theory and Oractice.Boca Raton,FL:CRC Press,2009.

8Xu ZB,Zhang J,Xu ZX.Melton:A practical and precise memory leak detection tool for C programs.Frontiers of Computer Science,2015,9(1):34–54.[doi:10.1007/s11704-014-3460-8]

9Reps T,Horwitz S,Sagiv M.Precise interprocedural dataflow analysis via graph reachability.Proc.of the 22nd ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages.San Francisco,California,USA.1995.49–61.

10Liu T,Huuck R.Case study:Static security analysis of the android goldfish kernel.International Symposium on Formal Methods.Oslo,Norway.2015.589–592.

11Muntean P,Rahman M,Ibing A,et al.SMT-constrained symbolic execution engine for integer overflow detection in C code.Proc.of 2015 Information Security for South Africa(ISSA).Johannesburg,Azania.2015.1–8.

12Wang TL,Wei T,Lin ZQ,et al.IntScope:Automatically detecting integer overflow vulnerability in X86 binary using symbolic execution.Proc.of the Network and Distributed System Security Symposium.San Diego,California,USA.2009.

13Cadar C,Godefroid P,Khurshid S,et al.Symbolic execution for software testing in practice:Preliminary assessment.Proc.of the 33rd International Conference on Software Engineering.Honolulu,HI,USA.2011.1066–1071.

14Sui YL,Yu D,Xue JL.Static memory leak detection using full-sparse value-flow analysis.Proc.of the 2012 International Symposium on Software Testing and Analysis.Minneapolis,MN,USA.2012.254–264.

15Li L,Cifuentes C,Keynes N.Practical and effective symbolic analysis for buffer overflow detection.Proc.of the 18th ACM SIGSOFT International Symposium on Foundations of Software Engineering.Santa Fe,New Mexico,USA.2010.317–326.

16Sui YL,Xue JL.SVF:Interprocedural static value-flow analysis in LLVM.Proc.of the 25th International Conference on Compiler Construction.Barcelona,Spain.2016.265–266.

17Enck W,Gilbert P,Han S,et al.TaintDroid:An informationflow tracking system for realtime privacy monitoring on smartphones.ACM Trans.on Computer Systems (TOCS),2014,32(2):5.

18Arzt S,Rastofher S,Fritz C,et al.Flowdroid:Precise context,flow,field,object-sensitive and lifecycle-aware taint analysis for android apps.ACM SIGPLAN Notices,2014,49(6):259–269.[doi:10.1145/2666356]

19Horváth G,Pataki N.Clang matchers for verified usage of the C++ standard template library.Annales Mathematicae et Informaticae,2015,44:99–109.

20Android的全系統(tǒng)符號執(zhí)行工具-Android_S2E.http://www.infoq.com/cn/presentations/whole-system-symbol-Implementation-tools-android-s2e.[2017-01-05].

21Lattner C,Adve V.LLVM:A compilation framework for lifelong program analysis & transformation.Proc.International Symposium on Code Generation and Optimization.San Jose,CA,USA.2004.75–86.

22Spreitzenbarth M,Schreck T,Echtler F,et al.Mobilesandbox:Combining static and dynamic analysis with machine-learning techniques.International Journal of Information Security,2015,14(2):141–153.[doi:10.1007/s10207-014-0250-0]

23Zhang JX,Li ZJ,Zheng XC.PathWalker:A dynamic symbolic execution tool based on LLVM byte code instrumentation.International Symposium on Dependable Software Engineering:Theories,Tools,and Applications.Nanjing,China.2015.227–242.

24Software Assurance Reference Dataset.https://samate.nist.gov/SRD/testsuite.php.[2016-11-10].

Android Source Code Static Analysis Technology Based on Clang Compiler Front-Ends

CAO Yuan-Ye1,2,DING Li-Ping1

1(Lab of Fundamental Software,Institute of Software,Chinese Academy of Sciences,Beijing 100190,China)2(University of Chinese Academy of Sciences,Beijing 100049,China)

Android phones have a large market share in the world,and the third-party system based on Android-derived is also very popular.As the security issues appear in Android systems frequently,this paper uses Clang to compile Android source code for static analysis.This analysis extracts rules and models from published CVE vulnerabilities,and uses the improved Clang to statically analyze Android source code to detect potentially unsafe code snippets.During the analysis of the Android source code,the Clang static analyzer taints attack surface,and calls the new added STP constrained solver.Then it taints sensitive data through the symbolic execution,and makes taint analysis on the sensitive functions,sensitive operations,sensitive rules,finally reports unsafe code snippets if there are potential security risks.Through experimental analysis,this method can accurately identify unsafe source code snippets that exist in the Android source code with the same type of security risk,and this method can detect five high-risk CVE vulnerabilities in the libstagefright module.

Clang compiler; Android; static analysis; taint analysis; symbolic execution

曹原野,丁麗萍.基于Clang編譯前端的Android源代碼靜態(tài)分析技術(shù).計算機系統(tǒng)應(yīng)用,2017,26(10):1–10.http://www.c-s-a.org.cn/1003-3254/6013.html

國家高技術(shù)研究發(fā)展計劃(“863”計劃)(2015AA016003)

2017-01-16; 采用時間:2017-02-23

猜你喜歡
污點源代碼靜態(tài)
基于代碼重寫的動態(tài)污點分析
最新進展!中老鐵路開始靜態(tài)驗收
靜態(tài)隨機存儲器在軌自檢算法
基于TXL的源代碼插樁技術(shù)研究
黑螞蟻
污點
保護好自己的“源代碼”
解密別克安全“源代碼”
油罐車靜態(tài)側(cè)傾穩(wěn)定角的多體仿真計算
純 白
昌吉市| 辽宁省| 丰城市| 旌德县| 光山县| 长葛市| 高邮市| 奎屯市| 武夷山市| 乌鲁木齐市| 洪湖市| 中西区| 九江县| 文山县| 华阴市| 乌鲁木齐市| 嘉定区| 武宁县| 内黄县| 滨海县| 泗阳县| 偏关县| 读书| 澎湖县| 寻乌县| 建平县| 邯郸县| 沅江市| 清苑县| 通江县| 铁岭市| 电白县| 彩票| 柘荣县| 平塘县| 克山县| 青川县| 沁源县| 兴和县| 焉耆| 田阳县|