999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?

基于LLVM 的Android 應用程序加固方法

2021-05-28 06:04:10江秋語殷芙萍
現代計算機 2021年11期
關鍵詞:指令

江秋語,殷芙萍

(1.四川大學計算機學院,成都610065;2.上海理工大學管理學院,上海200082)

0 引言

Android 平臺的開源特性使它在全球智能手機市場占據主導地位[1]。然而,近90%的Android 應用程序中存在重打包的現象,嚴重侵犯了開發者的知識產權。由于Java 類文件和DEX 文件保留了大部分的語義信息,攻擊者使用逆向工具可以輕而易舉地進行破解以獲取程序的源代碼。

為解決此問題,常用混淆技術對Android 應用程序進行加固。代碼混淆技術是一種代碼轉換機制,通過將易讀的代碼或數據進行保留語義的轉換、重組和整理來加大代碼分析難度,達到保護軟件安全的目的。但是對Java 代碼進行混淆會大大降低程序的性能,為了解決這個問題,本文提出了一種基于LLVM 的Android應用程序的混淆方法,利用LLVM 將DEX 文件中的Java 函數轉化為本地代碼,相比于Java 代碼,本地代碼具有更少的語義信息和更快的加載速度,能有效增加攻擊者分析的難度,減少混淆帶來的性能損失。

1 相關工作

近年來,由于本地代碼具有更少的語義信息和更快的加載速度的特點,Android 應用保護的研究方向也逐漸轉向本地代碼的保護,研究人員開始結合代碼混淆技術和虛擬化保護方法來保護Android 應用中的本地代碼。

Vivek Balachandran 等人[2]提出一種針對Java 層代碼的混淆保護方法,利用切片技術將函數劃分為多個代碼片段,通過pack 和switch 指令將代碼片段的控制流平展,同時插入垃圾代碼擴展分支語句來增強其控制流復雜程度,為了防止符號執行方法恢復混淆后的控制流,使用try 和catch 指令來隱藏控制流的跳轉。但僅僅增加控制流的復雜程度不能很好地增加攻擊者分析的難度,而且對APK 內所有基本塊進行切片并進行混淆會導致很大的性能開銷,因此只能選擇部分關鍵函數進行保護。

Kyeonghwan Lim 等人[3]進一步提出針對Android 本地代碼的保護方法,通過將Android 字節碼以更安全和高效的形式保存在本地代碼中并使用OLLVM 來對其進行混淆,以增強代碼最終的安全性,但是近年來有很多針對OLLVM 的反混淆研究,僅僅使用OLLVM 進行混淆保護不能很好的增加攻擊者分析的難度,因此需要增加混淆方式的多樣性和復雜性以便更好的保護Android 應用程序。

趙貝貝等人[4]提出了針對DEX 文件和SO 文件的多重虛擬化保護方法,通過將DEX 文件中的部分函數轉化為本地層函數,然后分別對其和SO 文件進行指令的虛擬化,大大增加的逆向分析的難度。由于虛擬化保護技術需要將被保護代碼全部轉化為自定義的虛擬指令,然后在運行的時候根據自定義的解釋器逐條翻譯虛擬指令,這樣會大大降低Android 應用程序的執行效率。

綜上所述,現有的Android 應用程序保護方法能夠在一定程度上提高程序的安全性,但是仍然存在性能開銷過大和無法有效抵御動態攻擊的問題。

2 具體實現

圖1 描述了本文所提Android 應用程序加固方法的五個步驟:首先是關鍵函數的提取,通過一個決策模型選擇被保護函數,將其反匯編為Smali 代碼;再對Smali 代碼進行解析,將其轉化為同語義的C++代碼;接著由LLVM[5]前端Clang 解析、驗證和診斷輸入的C++代碼;然后通過編寫LLVM 中端的優化模塊完成對LLVMIR 的優化、轉換、混淆[6]等一系列自定義操作,將優化后的指令轉化為本地代碼;最后將修改后的DEX文件和LLVM 后端生成的本地代碼重新打包為一個新的APK 文件。下面介紹一些關鍵技術的具體實現,如選擇關鍵函數、關鍵函數的轉化、控制流混淆、不透明謂詞混淆、整型數和字符串混淆。

圖1 本文所提加固方法的主要流程

2.1 選擇關鍵函數

對所有Java 層函數進行加固會造成巨大開銷[7],部分函數的程序框架,如窗口操作和界面渲染,已經被業內人士所熟知。相比于核心加密和通信邏輯的函數,這些函數本身調用了許多其他函數,無需浪費額外的資源對其進行加固,因此本文構建一個決策模型識別DEX 文件中的關鍵函數:

首先深度優先遍歷反匯編后的Smali 文件,生成每個函數的函數調用樹;其次選擇樹中的葉子節點,也就是不存在函數調用的函數,將函數名添加到被保護函數列表中,修改函數屬性為Native 類型;最后刪除原函數體并添加無用的垃圾指令來影響攻擊者逆向分析。

圖2 函數F調用樹

2.2 關鍵函數的轉化

將關鍵函數轉化為C++代碼通過指令逐條翻譯和程序語義恢復實現。

指令逐條翻譯:圖3 是一個函數反匯編生成的Smali 代碼,Smali 是基于寄存器的指令,由于同一個寄存器一般儲存多個不同類型的變量,因此在翻譯每一條指令時要對寄存器里的值進行區分。將Smali 指令逐條翻譯后如圖4 所示:為每一個寄存器操作分配一個新的臨時變量來翻譯指令,當該寄存器進行賦值操作后,用一個新的臨時變量替代之前的臨時變量。

圖3 Smali 指令

圖4 C++代碼

程序語義恢復:構建一個以每一條指令作為一個節點的指令圖,深度優先搜索圖中的每一個節點,根據每個節點的前驅節點和后繼節點以及節點的出度和入度,刪除不必要的變量并增加新的變量關聯,恢復程序正常的邏輯關系和上下文。

圖5 C++代碼的指令圖

圖6 優化后的C++代碼

2.3 控制流平坦化

控制流圖[8]是程序的抽象表現,圖中每一個節點代表一個基本塊。控制流平坦化將程序的控制流圖轉化為一個有很多分支的switch 結構,通過替換程序中的循環判斷條件和計數器,將程序的跳轉過程集中在switch 的判斷語句。一個函數的原始控制流圖,包含一些變量的賦值和一個循環,如圖7 所示。圖8 是對其進行控制流平坦化后的控制流圖,通過變量V 來控制程序的執行,每執行完一個基本塊后,對V 進行賦值操作來決定下一個要執行的基本塊。

圖7 函數的原始控制流圖

實現流程如下面的偽代碼所示:遍歷函數中所有的基本塊,選擇第一個基本塊作為函數的入口,若是有條件的基本塊,則將其轉為一個無條件的基本塊和一個有條件的基本塊,并將無條件的基本塊作為程序的入口;為每一個基本塊分配一個唯一的編號,并修改其結尾的跳轉指令,若當前基本塊為非條件跳轉,將變量V 的值賦值為要跳轉的基本塊的編號;若當前基本塊為條件跳轉,則需要修改為兩個條件賦值指令。最后,將基本塊插入到switch 結構中。

圖8 控制流平坦化后的控制流圖

圖9 偽代碼

2.4 不透明謂詞混淆

不透明謂詞[9]是一種布爾表達式,其結果為真或者為假。攻擊者只有在程序執行到一定階段才能利用逆向工具對它進行分析,因此不透明謂詞混淆可以抵御大部分靜態攻擊,本文選擇數論的結論來生成不透明謂詞。

實現過程如下:對基本塊進行拆分,直到每個基本塊都無法再被拆分,向前驅基本塊插入一個無條件跳轉指令指向其后繼基本塊,以保證程序的正確運行;生成一組不透明謂詞(pi,i=1,2,…,n,其中任意一個pi 的值為真時,其他所有不透明謂詞的值都為真)將其插入到拆分后的基本塊中,如圖10 所示。

圖10 不透明謂詞混淆

2.5 整型數替換

整型數替換相比于加密優勢在于,加密后的數據在內存中運行時解密,很容易被攻擊者發現并利用,而混淆后的數據在內存中保持原有的形式,攻擊者難以理解。整型數替換的原理是將一個整型數拆分為高位和低位長度相同的兩部分,分別儲存在寄存器中并對整型數的基本運算進行替換。例如,可以將一個長為2N 的整型數A 拆分為長度均為N 的Ah(高位)和Al(低位)。

對于加法運算A=B+C,

Al=(Bl+Cl)mod(1<>N)mod(1<

對于減法運算A=B-C,

Al=(Bl-Cl)mod(1<>N)mod(1<

對于比較運算,只需要先比較高位,若不相等則不需要再比較低位。

對于位運算,只需要同時對高位或低位進行相同的位運算操作即可。

對于移位運算A=B>>x,

其中0>x,Ah=Bh>>x

對于除法和乘法運算,LLVM 在編譯器優化過程會對乘除法指令進行替換,轉化為由移位和加法等指令等價表示的形式,由于乘法和除法的拆分會造成很大的開銷,因此不對存在乘法和除法的代碼進行整型數的拆分。

LLVMIR[10]使用了一個由%字符命名的無限寄存器集合,而不是一個固定的命名寄存器集合。整型變量的表示一般以i 為起始標志,i32 表示32 位整型數,all?oca i32 指令用于分配32 位長度的整型數變量。例如加法運算A=B+C,%1、%2、%3 分別用于儲存A、B、C的值,然后將B 和C 的值讀取出來,相加后儲存到A中;其進行整型數拆分的結果如圖11 所示,分別使用兩個寄存器儲存A、B、C 的值,首先是低位相加,再對65536 取模,完成低位相加,然后是高位相加的結果和低位和右移16 位的結果相加,最后對65536 取模完成高位相加。

圖11 混淆前的LLVMIR

圖12 混淆后的LLVMIR

2.6 字符串混淆

代碼中hashcode 的字符串可以在生成的binary 中查找到,因此增加破解的難度對字符串進行混淆很重要。常用方法是在編譯過程中使用密鑰對原字符串異或加密,然后在函數頭部插入解密代碼在運行時進行字符串解密[11],文件加載后,字符串在內存中仍是解密后的形式,因此,需要對字符串的解密進行隱藏。

實現過程如下:首先生成隨機密鑰對字符串異或加密,在函數要使用加密的字符串時調用解密函數。解密函數會首先申請一個與原字符串等長的棧空間,用于保存解密后的字符串,并修改原字符串的引用地址到當前棧的地址;字符串使用后會釋放棧的空間,解密后的字符串不會一直存在內存中,能一定程度上抵抗動態攻擊。

3 實驗

從手動分析、通用脫殼工具攻擊和運行性能三個

方面進行測試。編譯時系統使用Ubuntu 16.04 和LLVM 5.0 版本;測試端使用Android 5.0。

3.1 手動攻擊

本部分主要以攻擊者的角度,使用一些逆向工具來分析加固后的代碼。首先,使用JEB[12]的工具反編譯Android 應用程序。如圖13 所示,可以看到未加固代碼的邏輯是清晰可見,而加固后的代碼在Java 層中只有方法的聲明。攻擊者再進一步的分析,結合Java 文件中的函數聲明和從IDA[13]輸出的偽代碼,可以快速找到函數的實現,但是經過字符串和整型變量混淆以后,它們都沒有完整的語義,導致攻擊者很難理解。所以,攻擊者想要獲取應用程序的原始邏輯需要大量的時間和精力。

圖13 原始代碼反編譯結果

圖14 加固后代碼反編譯結果

3.2 通用脫殼工具攻擊

本部分主要選擇了六個常見的Android 脫殼工具,并使用它們來分析加固后的應用程序。DEXExtractor[14]原理是修改系統DVM 虛擬機模塊代碼DEXFile.cpp文件的DEXFileParse 函數,在系統調用DEXFileParse函數之前將原始DEX 文件從內存dump 出來。但是本文的方法已經將DEX 文件中的關鍵函數本地化,即使在內存中dump 出DEX 文件依然得不到函數的實現方式。Drizzledumper[15]原理是在root 環境下,通過ptrace附加需要脫殼的APK 進程,然后在脫殼的APK 進程的內存中進行DEX 文件頭的特征搜索,當搜索到DEX文件時進行DEX 文件的內存dump。由于函數經過本地化保護后在內存中找不到DEX 頭文件,因此這個工具對于本方法是無效的。ZjDroid[16]基于Xposed 框架,通過hook 每個應用進程在Java 級別獲取DEX 文件并利用獲得的mcookie dump 出DEX 文件,因此它無法在本地層還原代碼。DEXHunter[17]原理是在Android 系統代碼調用函數dvmDefineClass 進行類加載之前,主動地一次性加載并初始化DEX 文件所有的類。但它不能處理帶有代碼混淆和垃圾指令的加殼程序。Packer?Grind[18]從運行時跟蹤、系統跟蹤和指令跟蹤對加殼的App 進行監控和分析,最后進行還原。本文對代碼的控制流和數據都進行了混淆,不透明謂詞產生的虛假控制流使它無法決定哪個代碼是正確的。DROIDUN?PACK 可以對JNI 接口進行檢查,進而知道哪些函數已經本地化,本文的方法對數據進行了混淆,使得它很難將其還原為正確的指令執行。

結果如表1 所示,DROIDUNPACK 是目前最強大的脫殼工具,但是對本文提出的方法無效。這是因為本文的方法將DEX 字節碼編譯時混淆成本機代碼,在運行代碼時動態還原并在使用后再次加密。實驗結果表明,本文提出的加固方法克服了傳統加固方法容易被還原的缺點,對通用逆向工具有良好的抵抗能力。

表1 脫殼工具以及對應的脫殼結果

3.3 運行性能

本部分從CPU 占用率、大小和運行時內存使用率三個方面來評估加固前后程序的運行性能。選擇了六個常見的Android 應用,每一個應用程序都要運行10次,取其結果的平均值作為最后的實驗結果。在測試過程中,通過Monkey[19]觸發隨機點擊、幻燈片、文本或字符輸入模擬用戶的行為,隨機事件設置間隔為1s,每次數據收集的時間為10 分鐘。最后使用騰訊的開源性能測試工具GT[20]獲得了相應的實驗數據,如表2所示。

CPU 使用率:可以看出,加固后程序的CPU 使用率與原應用程序幾乎相同。

大小:從表中可以看出,所有加固后的應用程序比原應用程序約增加20%,原因是加固后的應用程序包含一個修改過的DEX 文件和一個新生成的SO 文件。雖然DEX 文件中的一些函數是在本機層中實現的,但它在原函數的指令中添加了JNI 注冊信息以及一些垃圾指令,因此它比原函數要占用更大的內存空間,并且在一定程度上增加了攻擊者逆向分析的難度。

內存使用:加固后,程序總內存使用量呈上升趨勢,但增幅不大,增加的內存消耗主要來自本機代碼的消耗。

綜上所述,由于本機層代碼直接執行效率更高、更直觀的CPU 指令,使得函數的本地化提高了程序的運行效率、抵消了部分混淆帶來的性能開銷,因此加固前后程序的性能未受到很大影響。

表2 加固前后程序運行性能對比

4 結語

本文提出了一種基于LLVM 的Android 應用加固方法,該方法將被保護程序中的Java 函數轉化為本地代碼并對其進行混淆保護,能夠有效抵抗逆向軟件的靜態分析和攻擊者的動態調試。將關鍵函數反匯編為Smali 指令后轉化為C++代碼,利用LLVM 框架的特點對C++代碼進行分析得到LLVM 中間表示,然后對LL?VMIR 指令進行優化和混淆,最后輸出機器碼。實驗結果表明,本文提出的方法具有較高的隱蔽性,相比其他混淆保護方法使用更少的性能消耗和代碼體積,且能夠抵御大部分通用脫殼工具的攻擊,因此本文的方法具有更優越的性能。

本文僅選擇不存在函數調用的函數作為保護的對象,在具有函數調用的函數中可能存在比較重要、需要被保護的函數。在以后的工作中,將考慮保護更多函數時應用程序性能的變化,以及如何在保證高安全性的前提下克服代碼混淆帶來的性能開銷。

猜你喜歡
指令
聽我指令:大催眠術
ARINC661顯控指令快速驗證方法
測控技術(2018年5期)2018-12-09 09:04:26
LED照明產品歐盟ErP指令要求解讀
電子測試(2018年18期)2018-11-14 02:30:34
殺毒軟件中指令虛擬機的脆弱性分析
電信科學(2016年10期)2016-11-23 05:11:56
巧用G10指令實現橢圓輪廓零件倒圓角
時代農機(2015年3期)2015-11-14 01:14:29
中斷與跳轉操作對指令串的影響
科技傳播(2015年20期)2015-03-25 08:20:30
基于匯編指令分布的惡意代碼檢測算法研究
一種基于滑窗的余度指令判別算法
歐盟修訂電氣及電子設備等產品安全規定
家電科技(2014年5期)2014-04-16 03:11:28
MAC指令推動制冷劑行業發展
汽車零部件(2014年2期)2014-03-11 17:46:27
主站蜘蛛池模板: 超清无码熟妇人妻AV在线绿巨人| 熟女成人国产精品视频| 国产91透明丝袜美腿在线| 国产欧美性爱网| 青草视频免费在线观看| 日韩精品亚洲一区中文字幕| 欧美在线国产| 一本久道久久综合多人| 女人18毛片水真多国产| 欧美精品啪啪一区二区三区| 日本在线亚洲| 色综合婷婷| 国产精品99久久久久久董美香| 88国产经典欧美一区二区三区| 精品无码一区二区三区在线视频| 免费全部高H视频无码无遮掩| 亚洲无码精彩视频在线观看| 性视频一区| 亚洲欧美色中文字幕| 亚洲第一网站男人都懂| 欧美在线视频不卡第一页| 日韩a在线观看免费观看| 无码人妻免费| 久久久久人妻精品一区三寸蜜桃| 国产欧美网站| 国产精品亚洲专区一区| 国产精品9| 久久综合一个色综合网| 国产女人水多毛片18| 自慰网址在线观看| 国产在线精品99一区不卡| 国产微拍一区| 91麻豆国产视频| 波多野结衣一级毛片| 99九九成人免费视频精品| 日本在线国产| 婷婷亚洲综合五月天在线| 日本高清免费不卡视频| 91精品最新国内在线播放| 中文字幕 欧美日韩| 欧美a在线看| 夜夜高潮夜夜爽国产伦精品| 日本一本在线视频| 国产在线高清一级毛片| 999精品在线视频| 亚洲AV永久无码精品古装片| 亚洲欧美成人综合| 福利一区在线| 亚洲欧美日韩中文字幕一区二区三区 | 2020国产精品视频| 2022国产91精品久久久久久| 日韩精品成人在线| 97视频精品全国免费观看| 伊人久久大香线蕉aⅴ色| 亚洲中文字幕在线观看| 亚洲综合精品香蕉久久网| 三级国产在线观看| 成年女人a毛片免费视频| 国产亚洲精久久久久久无码AV| 国产精品大白天新婚身材| 国产成人精品免费视频大全五级| 久久这里只精品热免费99| 精品国产网| 高清码无在线看| 91免费在线看| 久久窝窝国产精品午夜看片| 九九热免费在线视频| www精品久久| 天天色天天综合网| 在线欧美日韩国产| 午夜福利在线观看入口| 国产成人啪视频一区二区三区| 曰韩人妻一区二区三区| 欧美日本二区| 中文无码精品A∨在线观看不卡| 四虎影视库国产精品一区| 日韩av无码精品专区| 精品福利网| 亚洲无码高清视频在线观看| 亚洲午夜18| 国产精品30p| 国产最新无码专区在线|