周立博,梁 彬,游 偉,黃建軍,石文昌
中國(guó)人民大學(xué)信息學(xué)院 北京 中國(guó) 100872
根據(jù)國(guó)際數(shù)據(jù)公司IDC 發(fā)布的統(tǒng)計(jì)資料,近五年來(lái),安卓系統(tǒng)的市場(chǎng)份額穩(wěn)定在85%以上[1],安卓應(yīng)用生態(tài)一片繁榮。但與此同時(shí),安卓應(yīng)用也面臨著嚴(yán)重的重打包威脅。Zhou 等人[2]的研究顯示,有85%以上的惡意應(yīng)用是重打包應(yīng)用。
為了有效降低惡意重打包應(yīng)用所帶來(lái)的危害,如圖 1 安卓應(yīng)用重打包威脅模型所示,研究人員從開(kāi)發(fā)者、應(yīng)用市場(chǎng)和應(yīng)用安全服務(wù)商三個(gè)角度出發(fā),提出了不同的重打包攻擊對(duì)抗方式:①開(kāi)發(fā)者實(shí)施重打包防御策略,對(duì)應(yīng)用進(jìn)行加固,提高攻擊者構(gòu)建重打包應(yīng)用的難度。常見(jiàn)的策略有防篡改檢查[3-4]、代碼混淆[5-7]、應(yīng)用反調(diào)試和信息隱藏等。這種方式部署靈活,開(kāi)發(fā)者可以根據(jù)需要配置不同的防御策略,保護(hù)通過(guò)不同渠道發(fā)布的應(yīng)用。②應(yīng)用市場(chǎng)對(duì)應(yīng)用進(jìn)行靜態(tài)重打包應(yīng)用檢測(cè),通過(guò)重打包應(yīng)用與原應(yīng)用的相似性[8-17]進(jìn)行檢測(cè),限制重打包應(yīng)用通過(guò)應(yīng)用市場(chǎng)傳播。③應(yīng)用安全服務(wù)商在應(yīng)用安裝和執(zhí)行時(shí)收集特征信息來(lái)進(jìn)行重打包應(yīng)用檢測(cè)。常見(jiàn)的檢測(cè)方式有安裝時(shí)簽名校驗(yàn),運(yùn)行時(shí)UI 相似度檢測(cè)[18-20]等。
在上述對(duì)抗方式中,開(kāi)發(fā)者利用安卓應(yīng)用重打包工具的實(shí)現(xiàn)缺陷來(lái)加固應(yīng)用,中斷圖 1 中的反編譯環(huán)節(jié),是一種有效的重打包防御策略。但目前僅有少數(shù)工作對(duì)其進(jìn)行研究,Tim Strazzere[21]指出可以利用反編譯工具解析dex 文件的一個(gè)特定缺陷來(lái)中斷重打包工具對(duì)APK 的解析操作。盡管該缺陷目前已被修復(fù),但證明了該思路的可行性。自然地,我們想要知道,如何系統(tǒng)化地發(fā)現(xiàn)更多重打包工具中的缺陷?
針對(duì)這一問(wèn)題,我們提出了一種面向重打包對(duì)抗的重打包工具可利用缺陷檢測(cè)方法。如圖 2 所示,本方法能夠盡可能地檢出重打包工具中的可利用缺陷。開(kāi)發(fā)者可以利用這些缺陷對(duì)應(yīng)用進(jìn)行加固,加固后的應(yīng)用可以在目標(biāo)安卓設(shè)備中正常運(yùn)行而無(wú)法被重打包工具正常解析。與其它由開(kāi)發(fā)者實(shí)施的重打包攻擊對(duì)抗技術(shù)(如防篡改檢查、代碼混淆、應(yīng)用反調(diào)試和信息隱藏等)相比,本文提出的方法具有易于實(shí)施、運(yùn)行時(shí)開(kāi)銷(xiāo)小等優(yōu)勢(shì)。同時(shí),該方法與其它加固方法互補(bǔ),能夠與其他加固方法共同使用,進(jìn)一步提高應(yīng)用抗重打包的能力。
本方法利用重打包工具中缺陷與異常的聯(lián)系將對(duì)缺陷的檢測(cè)轉(zhuǎn)換到對(duì)重打包工具中潛在異常點(diǎn)的研究上來(lái)。這一轉(zhuǎn)換基于我們的以下觀察:①重打包工具中的文件解析缺陷能夠?qū)е缕鋵?duì)APK 的解析失敗,使得重打包工具不能輸出正確的反編譯結(jié)果。這一特性可用于對(duì)安卓應(yīng)用進(jìn)行加固。②重打包工具中的文件解析缺陷主要由程序執(zhí)行過(guò)程中未經(jīng)處理的異常引起?,F(xiàn)有工作[21]中對(duì)重打包工具解析缺陷的利用證明了我們觀察的合理性。此外,我們?cè)谘芯窟^(guò)程中發(fā)現(xiàn),一些知名的應(yīng)用程序(如作業(yè)幫、Instagram)也基于類(lèi)似觀察進(jìn)行應(yīng)用加固。
本工作的主要貢獻(xiàn)有以下兩點(diǎn):
1) 提出了一種面向重打包對(duì)抗的重打包工具解析APK 文件的實(shí)現(xiàn)缺陷檢測(cè)方法,以發(fā)現(xiàn)可利用的缺陷來(lái)加固應(yīng)用。該方法利用重打包工具文件解析缺陷與異常的聯(lián)系,把對(duì)缺陷的檢測(cè)轉(zhuǎn)換為對(duì)重打包工具中潛在異常點(diǎn)的定位、觸發(fā)和可利用性確認(rèn)。
2) 我們以當(dāng)下最流行的重打包工具Apktool[22]作為實(shí)驗(yàn)對(duì)象,在Apktool 2.4.1 中找到了12 個(gè)未知的可利用的解析缺陷。并利用這些缺陷對(duì)真實(shí)應(yīng)用進(jìn)行了加固,加固后的應(yīng)用不能被Apktool 重打包,證明了方法的實(shí)際價(jià)值。
為了對(duì)應(yīng)用進(jìn)行重打包,攻擊者可能會(huì)使用多種重打包工具對(duì)APK(Android package)文件進(jìn)行解析。常見(jiàn)的重打包工具有Apktool、Jadx、dex2Jar 等。在眾多重打包工具中,Apktool 使用最為廣泛,是本文的重點(diǎn)研究對(duì)象。為了便于讀者對(duì)本文檢測(cè)方法的理解,本節(jié)對(duì)Apktool 和重打包工具中的文件解析異常進(jìn)行簡(jiǎn)要介紹。
Apktool 是主要由Ryszard Wi?niewski 與Connor Tumbleson 開(kāi)發(fā)和維護(hù)的開(kāi)源安卓重打包工具。Apktool 功能完善,能夠反編譯resources.arsc、dex文件、png 格式的圖像文件和二進(jìn)制的xml 文件(包括AndroidManifest.xml 文件與res 目錄下壓縮后的xml 資源文件等)并在之后對(duì)其進(jìn)行回編譯。其使用Java 語(yǔ)言實(shí)現(xiàn)對(duì)APK 的反編譯,利用安卓官方提供的打包工具aapt 或aapt2 進(jìn)行回編譯生成未簽名的重打包應(yīng)用。
APK 文件本質(zhì)上是ZIP 格式的壓縮文件,重打包功能提供對(duì)壓縮文件中部分或全部文件的解析功能。重打包工具對(duì)文件的解析通常是順序進(jìn)行的,即一次解析壓縮文件中一個(gè)或一組文件。當(dāng)重打包工具中存在文件解析缺陷時(shí),重打包工具可能會(huì)因?yàn)槟承┪募馕鍪《K止運(yùn)行導(dǎo)致APK 解析失敗。而重打包工具的文件解析過(guò)程通?;谔囟ǖ奈募袷?。當(dāng)遇到不符合工具開(kāi)發(fā)者設(shè)定格式的文件時(shí),程序通常會(huì)產(chǎn)生異常,若開(kāi)發(fā)者認(rèn)為該異常無(wú)法被處理,則重打包工具則會(huì)因?yàn)樵摦惓6K止執(zhí)行。但如果此時(shí)安卓操作系統(tǒng)能夠?qū)υ搼?yīng)用正常解析,我們就可以認(rèn)為重打包工具在實(shí)現(xiàn)上具有缺陷。由這一思路出發(fā),本文提出了重打包工具解析缺陷的檢測(cè)方法,第三節(jié)是對(duì)這一方法的具體介紹。
本方法的指導(dǎo)思想是通過(guò)檢測(cè)重打包工具解析APK 文件的實(shí)現(xiàn)缺陷,以發(fā)現(xiàn)能夠用于加固應(yīng)用的可利用缺陷。我們?cè)O(shè)計(jì)了包含二次模糊測(cè)試的缺陷檢測(cè)方法,通過(guò)尋找可利用的異常點(diǎn)來(lái)檢測(cè)重打包工具中的缺陷。我們以當(dāng)下最流行的重打包工具Apktool 為研究對(duì)象,對(duì)本方法的具體實(shí)現(xiàn)進(jìn)行介紹。
圖3 是本方法的總體流程圖。如圖所示,本方法分可主要分為潛在異常點(diǎn)定位、基于模糊測(cè)試的異常觸發(fā)和包含二次模糊測(cè)試的異常點(diǎn)可利用性確認(rèn)三個(gè)階段。首先,在異常定位階段,我們使用靜態(tài)分析的方法對(duì)應(yīng)用代碼進(jìn)行掃描,確定潛在的異常點(diǎn);其次,在異常觸發(fā)階段,我們使用模糊測(cè)試的方式來(lái)生成測(cè)試應(yīng)用,根據(jù)Apktool 解析測(cè)試應(yīng)用的日志判斷異常是否被觸發(fā);最后,在異常點(diǎn)可利用性確認(rèn)階段,確認(rèn)潛在異常點(diǎn)能否用于應(yīng)用加固,并對(duì)部分無(wú)法直接確認(rèn)可利用性的異常點(diǎn)進(jìn)行第二次模糊測(cè)試。
下面,我們對(duì)本方法的每個(gè)環(huán)節(jié)的具體實(shí)現(xiàn)進(jìn)行詳細(xì)介紹。
在進(jìn)行異常定位前,我們首先要了解Apktool 中的異常。由前文我們對(duì)Apktool 的介紹可知,Apktool進(jìn)行APK 解析部分的代碼由Java 語(yǔ)言編寫(xiě)。Java 語(yǔ)言提供了良好的錯(cuò)誤處理機(jī)制,其使用Throwable 類(lèi)的眾多子類(lèi)來(lái)描述各種不同的異常,為開(kāi)發(fā)者提供了try,catch 語(yǔ)句捕獲和處理異常。
在本方法中,我們將Java 語(yǔ)言中的潛在異常點(diǎn)分為兩類(lèi):顯式異常點(diǎn)和隱式異常點(diǎn)。顯式異常點(diǎn)指使用throw 關(guān)鍵字拋出異常的語(yǔ)句,如圖 4 中第12行和第18 行所示。隱式異常點(diǎn)指的是,開(kāi)發(fā)者沒(méi)有主動(dòng)進(jìn)行異常處理的可能導(dǎo)致運(yùn)行時(shí)異常的代碼塊。圖 4 中的array函數(shù)包含了一個(gè)隱式異常點(diǎn)實(shí)例,在第23 行,參數(shù)x沒(méi)有經(jīng)過(guò)檢查就被當(dāng)作數(shù)組初始化的下標(biāo)使用。當(dāng)參數(shù)x為負(fù)值時(shí),程序會(huì)在運(yùn)行時(shí)拋出異常Java.lang.NegativeArraySizeException,同時(shí)沒(méi)有異常處理語(yǔ)句對(duì)此異常進(jìn)行捕獲處理。在本工作中,我們僅關(guān)注那些可能導(dǎo)致重打包工具解析終止的異常點(diǎn),過(guò)濾掉被已被捕獲處理的異常點(diǎn)。圖4 中test1函數(shù)僅在invoke函數(shù)中被調(diào)用(第3 行),其拋出的異常會(huì)在invoke函數(shù)中被捕獲處理(4~6 行),因此我們將忽略test1函數(shù)中的異常點(diǎn)。
為了進(jìn)行潛在異常點(diǎn)的定位,我們實(shí)現(xiàn)了基于Soot[23]的代碼掃描工具。其工作流程如圖5 所示。首先,掃描器將輸入的Java 字節(jié)碼轉(zhuǎn)換為Jimple 中間代碼,生成程序的函數(shù)調(diào)用圖(Call Graph,CG)和控制流圖(Control Flow Graph,CFG)。在生成的CFG 中包含從throw 子句到catch 模塊的邊和從隱式異常點(diǎn)的前驅(qū)節(jié)點(diǎn)到異常處理語(yǔ)句的邊。我們可以在遍歷過(guò)程中獲得可能的異常點(diǎn)。然后,如算法1 所示,通過(guò)嘗試匹配異常點(diǎn)與其try 模塊來(lái)確認(rèn)其是否被捕獲處理,過(guò)濾掉那些已經(jīng)被捕獲處理的異常點(diǎn)。
算法1 異常過(guò)濾
由于不是所有異常點(diǎn)都能夠被觸發(fā),我們需要通過(guò)異常觸發(fā)測(cè)試篩選出可觸發(fā)的潛在異常點(diǎn)。如圖 6 所示,這一階段的主要步驟包括:①通過(guò)重打包工具插樁和測(cè)試獲得異常可能被觸發(fā)時(shí)所處的解析階段和對(duì)應(yīng)的解析文件類(lèi)型;②根據(jù)待檢測(cè)的異常和其對(duì)應(yīng)解析文件類(lèi)型生成變異應(yīng)用;③使用Apktool 解析測(cè)試應(yīng)用,確認(rèn)異常觸發(fā)情況。
異常點(diǎn)對(duì)應(yīng)觸發(fā)文件類(lèi)型關(guān)系獲取
本階段的目的是獲得APK 中不同的文件類(lèi)型可能觸發(fā)的異常點(diǎn),以此加速后續(xù)的模糊測(cè)試。在整個(gè)方案中,該步驟只需進(jìn)行一次。我們首先對(duì)Apktool正常解析APK 獲得的日志進(jìn)行分析,發(fā)現(xiàn)Apktool對(duì)APK 中不同部分的解析相對(duì)獨(dú)立,每一段解析開(kāi)始時(shí)均會(huì)輸出特定的日志??梢愿鶕?jù)日志區(qū)分Apktool 開(kāi)始解析不同類(lèi)型文件的順序,在該日志輸出處插入相應(yīng)的開(kāi)關(guān)變量,標(biāo)識(shí)相應(yīng)的解析流程。Apktool 對(duì)不同類(lèi)型文件的解析順序如表 1 所示。
表1 Apktool 對(duì)安卓應(yīng)用中不同類(lèi)型文件的解析順序Table 1 The order of parsing files of different types in Apks with Apktool
接下來(lái)我們依據(jù)Apktool 的解析流程和已獲得的異常點(diǎn)進(jìn)行代碼插樁操作。圖 7 展示了我們的插樁結(jié)果:在Apktool中加入Phase類(lèi),使用靜態(tài)域now表明當(dāng)前屬于哪個(gè)分析階段。在異常點(diǎn)所在控制流的第一個(gè)條件跳轉(zhuǎn)語(yǔ)句前添加日志輸出語(yǔ)句,記錄可能觸發(fā)的異常。
插樁工作完成后,我們使用插樁后的Apktool 對(duì)測(cè)試應(yīng)用進(jìn)行解析,獲得輸出日志之后就可以根據(jù)日志信息確定對(duì)應(yīng)異常觸發(fā)與APK 中文件類(lèi)型的對(duì)應(yīng)關(guān)系。圖8 展示了插樁后的Apktool 解析多看閱讀應(yīng)用的實(shí)例,根據(jù)日志片段,我們可以看到StringBlock 類(lèi)中的getUtf8與getUtf16函數(shù)中存在的異??赡軙?huì)在AndroidManifest.xml 和res 目錄下資源文件解析的過(guò)程中被觸發(fā)。
·變異應(yīng)用生成
由于APK 本質(zhì)上是一個(gè)ZIP 格式的壓縮文檔,而ZIP 文件中存在大量文件有效性檢查。例如,ZIP文件的本地文件頭中的CRC-32 校驗(yàn)值,核心目錄頭中存儲(chǔ)的其相對(duì)本地目錄頭的偏移量,對(duì)這些變量的修改會(huì)導(dǎo)致APK 無(wú)法通過(guò)ZIP 格式校驗(yàn)。
為此,我們采用變異解壓后的文件,再重新壓縮,簽名的方式生成用于測(cè)試的變異應(yīng)用。本質(zhì)而言,我們的模糊測(cè)試是一種以字節(jié)為單位進(jìn)行變異的針對(duì)特定目標(biāo)文件和特定異常點(diǎn)的定向模糊測(cè)試。其中的關(guān)鍵環(huán)節(jié)包括變異文件選擇和具體的文件變異方式。
1) 變異文件選擇
首先根據(jù)需要探測(cè)的異常點(diǎn)和APK 中文件類(lèi)型之間的對(duì)應(yīng)關(guān)系,確定可能觸發(fā)異常點(diǎn)的文件類(lèi)型。接著遍歷APK 內(nèi)的文件,從滿(mǎn)足類(lèi)型且在之前的測(cè)試中沒(méi)有被選中的文件中,找到體積最小的文件作為輸出結(jié)果。通過(guò)變異文件的選擇,我們可以減小每次測(cè)試過(guò)程中進(jìn)行變異的選擇范圍,提高模糊測(cè)試效率。
2) 具體的文件變異方式如圖 9 所示,對(duì)于每一個(gè)文件,我們以單字節(jié)為基本單位對(duì)文件進(jìn)行變異。這主要是因?yàn)橹卮虬ぞ咄ǔR宰止?jié)作為單位進(jìn)行讀取,因此以字節(jié)為基本單位進(jìn)行變異是一個(gè)自然的選擇。從文件頭開(kāi)始,逐字節(jié)將原始位置變異為0x00-0xFF 之間的一個(gè)隨機(jī)值。每變異一個(gè)字節(jié)生成一個(gè)新文件,用“源文件名_文件名_位置_變異值”的方式命名變異后的文件。在后續(xù)的測(cè)試過(guò)程中,Apktool 測(cè)試輸出的日志同樣按照此規(guī)律進(jìn)行命名,根據(jù)日志文件名就可以確定對(duì)應(yīng)測(cè)試應(yīng)用變異的字節(jié),避免因存儲(chǔ)大量變異應(yīng)用而帶來(lái)的存儲(chǔ)開(kāi)銷(xiāo)。
·Apktool 異常觸發(fā)確認(rèn)
生成變異應(yīng)用以后,我們使用Apktool 對(duì)測(cè)試應(yīng)用進(jìn)行解析,生成對(duì)應(yīng)的日志文件。此時(shí),若日志文件中存在報(bào)錯(cuò)信息且應(yīng)用解析提前停止,我們就認(rèn)為異常被觸發(fā),可以從日志文件中得到異常的相關(guān)信息。否則,我們認(rèn)為這次變異沒(méi)有導(dǎo)致異常被觸發(fā)。
為了保證利用缺陷加固的應(yīng)用在使Apktool 解析出錯(cuò)的同時(shí)能夠在目標(biāo)安卓設(shè)備上正常運(yùn)行,我們對(duì)應(yīng)用進(jìn)行異常點(diǎn)可利用性確認(rèn)。確認(rèn)流程如圖 10所示,包含兩個(gè)主要流程:執(zhí)行監(jiān)測(cè)和第二次模糊測(cè)試。下面對(duì)這兩階段進(jìn)行詳細(xì)介紹。
·執(zhí)行監(jiān)測(cè)
在應(yīng)用執(zhí)行監(jiān)測(cè)環(huán)節(jié),我們需要判斷變異應(yīng)用能否在目標(biāo)安卓系統(tǒng)上正常運(yùn)行。因此,我們需要對(duì)應(yīng)用的正常運(yùn)行狀態(tài)進(jìn)行刻畫(huà)??紤]到變異應(yīng)用可能會(huì)影響原始應(yīng)用的正常功能,而從市場(chǎng)下載的應(yīng)用正常功能對(duì)于測(cè)試而言是未知的。同時(shí)可能存在其他反重打包措施導(dǎo)致變異應(yīng)用無(wú)法直接運(yùn)行。因此我們考慮直接開(kāi)發(fā)一個(gè)測(cè)試應(yīng)用作為兩次模糊測(cè)試的種子應(yīng)用。為了使種子應(yīng)用能夠觸發(fā)盡可能多的解析異常,我們根據(jù)合法APK 所可能包含的內(nèi)容,在應(yīng)用中添加對(duì)應(yīng)資源,如在res/目錄下添加menu,assets 等非必須資源項(xiàng),并在相應(yīng)的Activity 進(jìn)行加載和調(diào)用。同時(shí)為了便于測(cè)試,我們將對(duì)不同資源的訪(fǎng)問(wèn)分布在不同的Activity 下,通過(guò)配置Activity 的
·進(jìn)一步模糊測(cè)試
在執(zhí)行檢測(cè)過(guò)程中,我們發(fā)現(xiàn)一些異常能夠使Apktool 在解析APK時(shí)崩潰,同時(shí)對(duì)應(yīng)變異應(yīng)用無(wú)法在安卓手機(jī)上正常執(zhí)行。圖 12 展示了一個(gè)此類(lèi)待確認(rèn)異常。
在對(duì)測(cè)試應(yīng)用中res/layout 目錄下一個(gè)布局文件進(jìn)行變異后,該異常被觸發(fā)并導(dǎo)致Apktool 崩潰,但變異應(yīng)用無(wú)法在安卓系統(tǒng)上正常運(yùn)行。圖 13 展示了其在實(shí)際執(zhí)行中產(chǎn)生的崩潰日志。
我們認(rèn)為對(duì)于此類(lèi)異常已經(jīng)體現(xiàn)了重打包工具與安卓系統(tǒng)在解析APK 上的差異,通過(guò)后續(xù)人工分析造成差異的原因可能將此類(lèi)異常利用起來(lái)。接著我們將此變異測(cè)試應(yīng)用作為模糊測(cè)試的種子,對(duì)該文件進(jìn)行變異。根據(jù)日志分析判斷對(duì)應(yīng)的測(cè)試應(yīng)用所變異的字節(jié)與待確定異常是否相關(guān)。
在本章,我們將用實(shí)驗(yàn)來(lái)評(píng)估我們的方案在Apktool 上的具體實(shí)現(xiàn)。首先,我們對(duì)實(shí)驗(yàn)中的環(huán)境和使用的數(shù)據(jù)做簡(jiǎn)要介紹(4.1 節(jié));接著,我們對(duì)通過(guò)實(shí)驗(yàn)找到的可利用異常進(jìn)行介紹,并對(duì)其中的部分實(shí)例進(jìn)行解析(4.2 節(jié));然后,我們對(duì)本方法的性能開(kāi)銷(xiāo)進(jìn)行分析(4.3 節(jié));最后,我們以L(fǎng)inkedIn 為例,展示了兩個(gè)可利用異常對(duì)實(shí)際應(yīng)用進(jìn)行加固的過(guò)程和效果(4.4 節(jié))。
我們?cè)贘ava 環(huán)境中實(shí)現(xiàn)了對(duì)Apktool 字節(jié)碼的靜態(tài)分析和插樁工作,使用Python 語(yǔ)言編寫(xiě)腳本進(jìn)行模糊測(cè)試和應(yīng)用在安卓設(shè)備上運(yùn)行情況監(jiān)測(cè)。實(shí)驗(yàn)用到的PC 配置為16GB 內(nèi)存,6 個(gè)2.1GHz 內(nèi)核和1TB 硬盤(pán),安卓手機(jī)型號(hào)是小米6,安卓系統(tǒng)版本為9.0。
我們的實(shí)驗(yàn)主要有以下兩個(gè)數(shù)據(jù)來(lái)源:
1) 測(cè)試應(yīng)用:測(cè)試應(yīng)用集合來(lái)自豌豆莢與Apkpure。其中包含豌豆莢應(yīng)用分類(lèi)排行榜14 個(gè)分類(lèi)中,每類(lèi)的前50 個(gè)應(yīng)用,Apkpure 中分類(lèi)排行榜32個(gè)分類(lèi)中每類(lèi)前10 個(gè)應(yīng)用,總測(cè)試應(yīng)用共計(jì)有1020個(gè)。在異常點(diǎn)對(duì)應(yīng)觸發(fā)文件類(lèi)型關(guān)系獲取階段,我們使用插樁后的Apktool 對(duì)測(cè)試應(yīng)用進(jìn)行解析,獲得異常和APK 壓縮包中文件類(lèi)型之間的對(duì)應(yīng)關(guān)系。
2) 種子應(yīng)用:我們?cè)谶M(jìn)行模糊測(cè)試時(shí)使用自己開(kāi)發(fā)的測(cè)試應(yīng)用作為種子應(yīng)用,以避免應(yīng)用市場(chǎng)中包含重打包檢測(cè),代碼混淆和資源混淆的應(yīng)用對(duì)實(shí)驗(yàn)結(jié)果造成影響。
通過(guò)實(shí)驗(yàn)與人工分析,在Apktool 2.4.1 上共發(fā)現(xiàn)343 個(gè)異常,總共確認(rèn)了12 個(gè)未知的可利用的缺陷,與缺陷相關(guān)的可利用異常點(diǎn)的詳細(xì)信息如表2所示,下面我們對(duì)找到的異常及其拋出這些異常的解析缺陷進(jìn)行分析。
表2 可利用異常點(diǎn)Table 2 Available exception points
·拋出顯式異常的解析缺陷
圖14 展示了ExtDataInput 類(lèi)中被確認(rèn)的顯式異常。在異常定位階段,我們能夠通過(guò)對(duì)代碼的解析,定位到該throw 語(yǔ)句,并逐級(jí)檢查該函數(shù)拋出的異常有沒(méi)有被調(diào)用者用catch 語(yǔ)句捕獲。最終我們能夠從找到從main函數(shù)到該函數(shù)的路徑,確認(rèn)在main函數(shù)拋出的異常中可能包含此異常,因此將其作為可能的異常。之后在變異arsc 文件的過(guò)程中得到的變異應(yīng)用觸發(fā)了該異常,且能夠在目標(biāo)設(shè)備上正常運(yùn)行。由此我們確認(rèn)其是一個(gè)可利用異常。
·拋出隱式異常的解析缺陷
圖15 展示了ARSCDecoder 類(lèi)中的一個(gè)隱式異常,該隱式異常同樣與數(shù)組操作相關(guān)。圖中packageCount變量從文件中獲取,后續(xù)作為數(shù)組的大小在初始化時(shí)被使用。與StringBlock 類(lèi)中的例子類(lèi)似,該值同樣可能為負(fù)值,導(dǎo)致拋出Java.lang.NegativeArraySizeException 異常。
但 Android 系統(tǒng)去解析 APK 時(shí),并不關(guān)心packageCount對(duì)應(yīng)的字節(jié)。該解析差異導(dǎo)致此異常被觸發(fā)的同時(shí),應(yīng)用能夠在手機(jī)上正常運(yùn)行。
·需要進(jìn)一步探測(cè)的解析缺陷
以3.3 節(jié)我們討論的異常為例,在使用種子應(yīng)用進(jìn)行模糊測(cè)試測(cè)試的過(guò)程中我們注意到,若在第一輪探測(cè)中當(dāng)變換res/layout/activity_main.xml 中第64個(gè)字節(jié)為0xFF 時(shí),會(huì)導(dǎo)致第318 行offset值為負(fù)值,觸發(fā)Java.lang.NegativeArraySizeException 異常。但該應(yīng)用無(wú)法在手機(jī)上正常運(yùn)行。于是我們將此變異測(cè)試應(yīng)用作為模糊測(cè)試的種子進(jìn)行第二輪fuzz操作。
通過(guò)這種方式,我們可以發(fā)現(xiàn)異常的關(guān)鍵輸入,如圖 16所示。確認(rèn)了arsc文件中與其對(duì)應(yīng)的關(guān)鍵字節(jié),通過(guò)觀察可以得知其儲(chǔ)存著值res/layout/activity_main.xml,即我們變異的文件。經(jīng)過(guò)進(jìn)一步分析,我們可以從中獲得一種加固應(yīng)用的新方法:向res/layout 目錄下插入無(wú)意義的損壞布局文件,同時(shí)在對(duì)應(yīng)的索引文件中添加相應(yīng)的索引值。這樣由于Apktool 會(huì)依據(jù)索引值對(duì)APK 中的文件進(jìn)行解析,重打包工具將會(huì)在解析到我們添加的損壞布局文件時(shí)出錯(cuò)。而無(wú)意義的布局文件不會(huì)在系統(tǒng)中被解析,使得加固后的安卓應(yīng)用能夠在目標(biāo)安卓設(shè)備上正常執(zhí)行。
本文方案在實(shí)現(xiàn)上可以大致分為三個(gè)階段:潛在異常點(diǎn)定位、異常觸發(fā)和異??衫眯源_認(rèn)。在潛在異常點(diǎn)定位階段,我們主要對(duì)Apktool 進(jìn)行靜態(tài)分析,這一步驟需要對(duì)重打包應(yīng)用的CG 和CFG 進(jìn)行遍歷。靜態(tài)分析階段在整個(gè)方案中僅需執(zhí)行一次,即使消耗時(shí)間較長(zhǎng)也在可接受范圍內(nèi)。在異常觸發(fā)階段,會(huì)進(jìn)行大量變異操作并使用Apktool 進(jìn)行解析,消耗時(shí)間較長(zhǎng)。在異??捎眯源_認(rèn)階段,我們能夠利用異常觸發(fā)階段的結(jié)果,跳過(guò)部分可能導(dǎo)致異常的變異探測(cè),從而加速關(guān)鍵字節(jié)的探測(cè)過(guò)程。每個(gè)階段的詳細(xì)耗時(shí)情況如表3 所示。
從表3 可以看出,異常查找花費(fèi)時(shí)間最少,平均時(shí)間在1.05 s 左右,異常觸發(fā)花費(fèi)時(shí)間最長(zhǎng),平均每個(gè)異常被觸發(fā)需要十分鐘以上。在異常利用階段因?yàn)橐呀?jīng)獲得觸發(fā)階段的數(shù)據(jù),平均每個(gè)異常耗時(shí)600 s 要低于異常觸發(fā)階段,符合我們的預(yù)期。
表3 各階段耗時(shí)統(tǒng)計(jì)Table 3 Time consuming statistics of each stage
在實(shí)例驗(yàn)證階段,我們從豌豆莢和Apkpure 中挑選了9 個(gè)真實(shí)應(yīng)用,使用已檢測(cè)到的缺陷進(jìn)行應(yīng)用加固驗(yàn)證。9 個(gè)應(yīng)用可以按大小分為三組,1~3 號(hào)小型應(yīng)用(1~20MB),4~6 號(hào)中型應(yīng)用(20~100MB),7~9 號(hào)大型應(yīng)用。每組應(yīng)用從來(lái)自豌豆莢中的測(cè)試應(yīng)用中隨機(jī)選出,為了體現(xiàn)Apkpure 商店與豌豆莢的差異,我們使用Apkpure 特有的應(yīng)用替換部分測(cè)試應(yīng)用。得到了最終的真實(shí)應(yīng)用列表,如表 4 所示。
表4 真實(shí)應(yīng)用列表Table 4 Real application list
接下來(lái)我們以常見(jiàn)的LinkedIn 應(yīng)用為例,展示我們利用4.2 節(jié)已分析的部分異常點(diǎn)對(duì)實(shí)際應(yīng)用的加固效果和加固細(xì)節(jié)。如圖 17 所示,在應(yīng)用加固前后,應(yīng)用功能和用戶(hù)界面沒(méi)有發(fā)生變化,加固后應(yīng)用能夠在目標(biāo)安卓設(shè)備上正常運(yùn)行。
下面介紹應(yīng)用的加固細(xì)節(jié)。skipCheckShort函數(shù)中異常對(duì)應(yīng)的解析缺陷是Apktool 在解析arsc 文件時(shí)對(duì)Entry 資源項(xiàng)數(shù)值讀取的額外檢查。進(jìn)行檢查的語(yǔ)句為 ARSCDecoder 類(lèi)readValue方法中的mIn.skipCheckShort((short) 8),該語(yǔ)句檢查讀入的數(shù)值是否為0x08,當(dāng)檢測(cè)到的值不是0x08 時(shí),拋出顯式異常。由此,我們首先對(duì)LinkedIn 應(yīng)用中arsc 文件的部分Entry 項(xiàng)進(jìn)行修改,將對(duì)應(yīng)的0x08 替換成0xFF,如圖 18 所示。
接著用修改后的arsc 文件替換原arsc 文件生成LinkedIn 的重打包應(yīng)用com.linkedin.android_1.apk。重打包應(yīng)用能夠在手機(jī)上正常運(yùn)行,使用Apktool 無(wú)法正常進(jìn)行解析,在解析過(guò)程中拋出異常:brut.androlib.AndrolibException:Could not decode arsc file。同樣的,我們也可以利用隱式異常使得Apktool 拋出運(yùn)行時(shí)異常。圖 19 展示了對(duì)readTableHeader函數(shù)中隱式異常的利用。
通過(guò)變異arsc 文件起始的第9~12 個(gè)字節(jié),使預(yù)期對(duì)應(yīng)的packageCount值為–1,最終導(dǎo)致Apktool在解析過(guò)程中拋出異常:Exception in thread "main"Java.lang.NegativeArraySizeException。
類(lèi)似地,我們可以利用其他缺陷對(duì)應(yīng)用進(jìn)行加固。加固后的應(yīng)用在目標(biāo)設(shè)備上正常運(yùn)行地同時(shí)能夠使Apktool 解析異常。限于文章篇幅,其他異常點(diǎn)的利用情況不再一一贅述。
文件變異方式:在本文中,我們以單字節(jié)為基本單位對(duì)文件進(jìn)行變異。這主要是因?yàn)橹卮虬ぞ咄ǔR宰止?jié)作為單位進(jìn)行讀取,因此以字節(jié)為基本單位進(jìn)行變異是一個(gè)自然的選擇。另一個(gè)可能的選擇是以比特為單位進(jìn)行變異,這種變異方式可能會(huì)提高觸發(fā)異常的可能性,但是在模糊測(cè)試階段會(huì)帶來(lái)較大的性能開(kāi)銷(xiāo)。在未來(lái)工作中,我們將深入探索不同變異策略的異常觸發(fā)效果及性能開(kāi)銷(xiāo)。
方法自動(dòng)化程度提升:本方法在執(zhí)行檢測(cè)環(huán)節(jié),根據(jù)日志判斷應(yīng)用是否在目標(biāo)系統(tǒng)上正常運(yùn)行。目前,應(yīng)用不能正常運(yùn)行的具體原因需要人工對(duì)日志內(nèi)容進(jìn)行分析確認(rèn)。在實(shí)驗(yàn)過(guò)程中,我們發(fā)現(xiàn)從日志中提取出的關(guān)鍵字能夠反映出應(yīng)用不能正常運(yùn)行的原因。在未來(lái)工作中,我們擬設(shè)計(jì)啟發(fā)式規(guī)則,根據(jù)日志內(nèi)容提取出的關(guān)鍵字,確定應(yīng)用崩潰原因。
方法有效性:本工作提出了一種新的應(yīng)用自我保護(hù)策略來(lái)對(duì)抗安卓應(yīng)用重打包技術(shù)——利用安卓應(yīng)用重打包工具解析APK 的實(shí)現(xiàn)缺陷對(duì)應(yīng)用進(jìn)行加固。盡管目前在本方案中發(fā)現(xiàn)的Apktool 解析缺陷可能在后續(xù)版本中被修復(fù),但這一思路能夠被應(yīng)用加固廠商借鑒,將其擴(kuò)展到其他重打包工具如jadx,dex2jar 等,并發(fā)現(xiàn)新版本中可能存在的缺陷。對(duì)于攻擊者來(lái)說(shuō),通過(guò)本方案加固的應(yīng)用能夠增加其重打包應(yīng)用的難度。即使攻擊者已經(jīng)獲得了可能會(huì)導(dǎo)致重打包工具出錯(cuò)的異常點(diǎn),也要對(duì)重打包工具或加固后的應(yīng)用進(jìn)行修改。提高了其進(jìn)行攻擊的時(shí)間成本,在一定程度上能夠起到提高重打包攻擊技術(shù)門(mén)檻的效果。
對(duì)于如何抵抗安卓重打包攻擊,目前主要有三種防御方法:一是開(kāi)發(fā)者對(duì)應(yīng)用進(jìn)行加固,在應(yīng)用中實(shí)施自我保護(hù)策略;二是在應(yīng)用市場(chǎng)方面進(jìn)行的靜態(tài)重打包應(yīng)用檢測(cè);三是在應(yīng)用安裝或執(zhí)行時(shí)由可靠的應(yīng)用安全服務(wù)提供商進(jìn)行動(dòng)態(tài)重打包應(yīng)用檢測(cè)。
應(yīng)用重打包對(duì)抗的一種主流方式是開(kāi)發(fā)者進(jìn)行應(yīng)用加固,既在應(yīng)用中實(shí)施應(yīng)用自我保護(hù)策略,常見(jiàn)的策略有防篡改檢查、代碼混淆、應(yīng)用反調(diào)試和信息隱藏等。防篡改檢查是指在應(yīng)用中添加代碼檢測(cè)應(yīng)用自身是否被篡改。為了加強(qiáng)防篡改檢查代碼的安全性,Luo 等人[3]在應(yīng)用中分散插入大量檢測(cè)代碼來(lái)使得攻擊者難以定位所有檢測(cè)代碼,Zeng等人[4]在方案BombDroid 中創(chuàng)造性地利用經(jīng)常在惡意軟件中使用的邏輯炸彈來(lái)檢測(cè)攻擊者對(duì)應(yīng)用的修改。代碼混淆技術(shù)通過(guò)對(duì)應(yīng)用的控制流[5]、程序中涉及到的標(biāo)識(shí)符和字符串進(jìn)行混淆[6-7],通過(guò)提高攻擊者分析混淆代碼難度來(lái)對(duì)應(yīng)用進(jìn)行保護(hù)。應(yīng)用反調(diào)試則通過(guò)在應(yīng)用中添加調(diào)試檢測(cè)代碼來(lái)進(jìn)行判斷應(yīng)用執(zhí)行狀態(tài),阻礙攻擊者通過(guò)調(diào)試進(jìn)行動(dòng)態(tài)分析。提高攻擊者重打包應(yīng)用的難度。信息隱藏技術(shù)是指通過(guò)加密等方式隱藏部分關(guān)鍵代碼,提高攻擊者對(duì)代碼進(jìn)行分析的難度。本質(zhì)而言,本文提出的方法屬于由開(kāi)發(fā)者實(shí)施的重打包攻擊對(duì)抗技術(shù)。相比于已有的防篡改檢查、代碼混淆、應(yīng)用反調(diào)試等策略,本文提出的方法具有易于實(shí)施、運(yùn)行時(shí)開(kāi)銷(xiāo)小等優(yōu)勢(shì)。同時(shí),該方法與其它加固方法互補(bǔ),能夠與其他加固方法共同使用,進(jìn)一步提高應(yīng)用抗重打包的能力。
重打包應(yīng)用檢測(cè)技術(shù)以重打包應(yīng)用與原應(yīng)用之間的相似性為基礎(chǔ),通過(guò)特征選取,相似性比較來(lái)判斷待檢測(cè)應(yīng)用是否為重打包應(yīng)用。根據(jù)選取特征的方式,重打包應(yīng)用檢測(cè)技術(shù)可以進(jìn)一步分為兩種類(lèi)型:靜態(tài)重打包應(yīng)用檢測(cè)和動(dòng)態(tài)重打包應(yīng)用檢測(cè)。靜態(tài)重打包應(yīng)用檢測(cè)對(duì)APK 進(jìn)行靜態(tài)分析,選取不同的應(yīng)用特征如應(yīng)用代碼、API 調(diào)用序列、代碼中包含的控制流信息、應(yīng)用功能、資源文件等作為相似性度量的基礎(chǔ)。Zhou 等人[8]在安卓發(fā)展的早期就實(shí)現(xiàn)了一款名為DroidMoss 的相似性度量系統(tǒng)。該系統(tǒng)從dex 文件中抽取指令序列作為待測(cè)應(yīng)用的初步特征,接著計(jì)算指令序列的模糊哈希(Fuzzy Hashing)值作為該應(yīng)用的指紋信息,最后通過(guò)兩兩計(jì)算應(yīng)用指紋之間的編輯距離來(lái)確定第三方市場(chǎng)中是否存在重打包應(yīng)用。文獻(xiàn)[9-10]發(fā)現(xiàn)大量第三方庫(kù)的使用會(huì)導(dǎo)致基于dex文件的相似性檢測(cè)系統(tǒng)產(chǎn)生誤報(bào),提出了兩階段的檢測(cè)方案:在進(jìn)行特征提取前首先對(duì)應(yīng)用使用的庫(kù)進(jìn)行檢測(cè),移除第三方庫(kù)代碼后再進(jìn)行特征提取操作。Chen 等[11]的團(tuán)隊(duì)與 Marastoni 等[12]團(tuán)隊(duì)對(duì)代碼做進(jìn)一步處理,將代碼之間的控制流信息作為相似性比較的基礎(chǔ)。Marastoni 等人為了獲得更好的檢測(cè)效果,還額外提取了API 的調(diào)用情況作為第二特征來(lái)刻畫(huà)應(yīng)用。Abdurrahman 等人[13]與Fan等人[14]利用機(jī)器學(xué)習(xí)技術(shù),從程序的API 調(diào)用情況出發(fā)訓(xùn)練分類(lèi)器進(jìn)行重打包應(yīng)用的檢測(cè)。文獻(xiàn)[15-17]基于重打包應(yīng)用與原應(yīng)用UI 的高度相似性,提出不同的檢測(cè)方法,對(duì)重打包應(yīng)用進(jìn)行檢測(cè)。
應(yīng)用安全服務(wù)提供商常用動(dòng)態(tài)重打包檢測(cè)來(lái)進(jìn)行重打包應(yīng)用檢測(cè)。他們可以在應(yīng)用執(zhí)行時(shí)收集應(yīng)用特征來(lái)進(jìn)行重打包應(yīng)用檢測(cè)。文獻(xiàn)[18-20]收集應(yīng)用運(yùn)行時(shí)產(chǎn)生的UI 信息來(lái)進(jìn)行相似性檢測(cè),文獻(xiàn)[24]提出了一種收集程序運(yùn)行時(shí)API 調(diào)用信息作為檢測(cè)依據(jù)的方法,文獻(xiàn)[25]提出了一種向應(yīng)用中添加水印信息并在運(yùn)行過(guò)程中進(jìn)行檢查的重打包應(yīng)用檢測(cè)方式。
本文提出了一種面向重打包對(duì)抗的重打包工具可利用缺陷檢測(cè)方法,能夠發(fā)現(xiàn)可用于加固應(yīng)用的重打包工具文件解析缺陷。首先,我們使用靜態(tài)代碼分析的方式對(duì)重打包應(yīng)用進(jìn)行代碼掃描,定位可能的異常點(diǎn);其次,使用模糊測(cè)試技術(shù)觸發(fā)異常,獲得異常對(duì)應(yīng)的關(guān)鍵輸入;然后,監(jiān)測(cè)觸發(fā)異常的變異應(yīng)用在目標(biāo)安卓設(shè)備上的運(yùn)行情況,對(duì)異常的可用性進(jìn)行確認(rèn),并進(jìn)行進(jìn)一步的模糊測(cè)試來(lái)輔助研究者構(gòu)建能被用于對(duì)抗重打包攻擊的異常觸發(fā)向量。在以重打包工具Apktool 2.4.1 為實(shí)驗(yàn)對(duì)象的測(cè)試中,我們總共發(fā)現(xiàn)了12 個(gè)未知的可利用的缺陷。所有這些缺陷都已被證明可用于實(shí)際應(yīng)用中,能夠有效對(duì)抗重打包攻擊,證明了本工作的可用性。
盡管已經(jīng)可以利用本方法檢測(cè)出Apktool 中未知的可利用缺陷,但本工作仍存在一定不足和需要改進(jìn)的地方。
一是在其他重打包工具上進(jìn)行推廣驗(yàn)證。當(dāng)前我們針對(duì)Apktool 進(jìn)行實(shí)驗(yàn)驗(yàn)證,未來(lái)我們將在后續(xù)工作中將本方法推廣應(yīng)用到其他重打包工具上。
二是增加對(duì)其他重打包階段的考慮。應(yīng)用的重打包過(guò)程通常需要經(jīng)歷反編譯與回編譯兩個(gè)階段。在本文的工作中,我們主要考慮Apktool 在反編譯方面可能引起的異常,缺少對(duì)回編譯階段的分析。為此,我們要在將來(lái)的后續(xù)工作中加入對(duì)回編譯階段異常的利用,實(shí)現(xiàn)對(duì)重打包工具的全流程覆蓋。