李志明,劉壽春,歐陽(yáng)飛帆,李婷婷,申利民
1(燕山大學(xué) 信息科學(xué)與工程學(xué)院,河北 秦皇島 066004) 2(河北省計(jì)算機(jī)虛擬技術(shù)與系統(tǒng)集成重點(diǎn)實(shí)驗(yàn)室,河北 秦皇島 066004) 3(河北省軟件工程重點(diǎn)實(shí)驗(yàn)室,河北 秦皇島 066004)
Android系統(tǒng)的開(kāi)源特性使其快速發(fā)展的同時(shí),也給Android應(yīng)用帶來(lái)了嚴(yán)重的安全隱患.逆向人員可輕易通過(guò)靜態(tài)攻擊、動(dòng)態(tài)攻擊以及重打包攻擊等多種手段對(duì)未加固的Android應(yīng)用進(jìn)行逆向破解,并植入非法代碼,形成惡意應(yīng)用后再重新發(fā)布到應(yīng)用市場(chǎng)[1].在用戶(hù)不知情的情況下,惡意應(yīng)用通過(guò)私自扣費(fèi)、隱私竊取、系統(tǒng)破壞、自動(dòng)訪問(wèn)不良信息等行為給用戶(hù)造成損失.
通常,軟件開(kāi)發(fā)者采用多種防護(hù)措施保護(hù)其應(yīng)用不被逆向破解.目前,主流的防護(hù)措施有代碼混淆[2,3]、權(quán)限控制[4,5]以及應(yīng)用加固3類(lèi),其中,應(yīng)用加固是Android應(yīng)用安全防護(hù)的首選措施.按照加固對(duì)象不同,應(yīng)用加固可分為Dex文件加固和so文件加固兩類(lèi).
Dex文件,包含Android應(yīng)用的所有源代碼,是逆向人員的主要攻擊對(duì)象.為此,眾多研究者針對(duì)Dex文件提出了很多加固方法,例如,Dex分塊加載技術(shù)[6]、VMP保護(hù)技術(shù)[7]以及加殼技術(shù)[8-10]等,其中,加殼技術(shù)是最為有效且被廣泛應(yīng)用的方法.但是,現(xiàn)有加殼技術(shù)存在兩點(diǎn)缺陷:1)將源apk文件直接放到解殼程序的資源文件中,易于被逆向人員獲取;2)缺乏對(duì)解殼程序的保護(hù),導(dǎo)致逆向人員可以通過(guò)重打包方式植入非法代碼實(shí)現(xiàn)對(duì)解殼程序的篡改.盡管Dex文件加固在一定程度上提升了Android應(yīng)用的安全性,但Android系統(tǒng)的開(kāi)源性使得Dex文件在安全性方面與由c/c++編寫(xiě)的so文件相比存在一定差距.
JNI (Java Native Interface)機(jī)制[11],使得開(kāi)發(fā)人員可以在Java代碼中調(diào)用so文件中的Native函數(shù),這樣,開(kāi)發(fā)人員便可將Android應(yīng)用的函數(shù)代碼轉(zhuǎn)換為C/C++代碼置于so文件中,以達(dá)到進(jìn)一步保護(hù)函數(shù)代碼的目的.但隨著逆向人員技術(shù)水平的提高,so文件被逆向破解的情況也時(shí)有發(fā)生,因此,亟需采取相應(yīng)措施對(duì)so文件進(jìn)行加固防護(hù).
從加固原理角度,so文件加固可分為Native函數(shù)混淆[12]、符號(hào)表隱藏[13]及自定義so加載器[14]3種方案.這3種方案均以整個(gè)so文件作為加固對(duì)象,存在對(duì)應(yīng)用性能影響過(guò)大的問(wèn)題.
綜上,現(xiàn)有以Dex文件加固為核心的加殼技術(shù),存在著源apk文件易被獲取以及解殼程序易被篡改的問(wèn)題;現(xiàn)有so文件加固方案以整個(gè)so文件作為加固對(duì)象,存在著加固后的Android應(yīng)用運(yùn)行效率下降等問(wèn)題[15].
針對(duì)上述問(wèn)題,融合JNI機(jī)制、動(dòng)態(tài)加載技術(shù)[16]以及云平臺(tái)理念,提出一種面向Android應(yīng)用的安全加固模型,并對(duì)其中涉及的基于JNI機(jī)制的函數(shù)代碼加固方案、基于云平臺(tái)的加殼解殼方案開(kāi)展研究工作,進(jìn)而形成一種基于JNI機(jī)制與云平臺(tái)的細(xì)粒度Android應(yīng)用加固方法.該方法可使得加固應(yīng)用在未顯著增加Dalvik虛擬機(jī)的工作負(fù)擔(dān)的前提下,具有抵御靜態(tài)攻擊及重打包攻擊能力.
為了便于后續(xù)描述,將面向Android應(yīng)用的安全加固模型命名為RMAA(reinforce model for Android App)加固模型,其框架如圖1所示.
由圖1可知,RMAA加固模型對(duì)Android應(yīng)用的加固環(huán)節(jié)主要集中在云平臺(tái)的安全加固功能區(qū),可有效降低逆向人員通過(guò)分析加固原理對(duì)加固應(yīng)用破解的風(fēng)險(xiǎn).此外,將源apk的加密Dex文件和簽名的SHA-1值等重要文件及信息存儲(chǔ)于云平臺(tái)的持久化區(qū),保證了校驗(yàn)機(jī)制的有效性及Android應(yīng)用的安全性.其中,基于JNI機(jī)制的函數(shù)代碼加固及基于云平臺(tái)的加殼解殼技術(shù)方案是實(shí)現(xiàn)RMAA加固模型的關(guān)鍵問(wèn)題,需要開(kāi)展深入研究.
基于JNI機(jī)制的函數(shù)代碼加固方案的流程如圖2所示,其核心思想在于以修改smali指令的方式實(shí)現(xiàn)JNI機(jī)制,將用戶(hù)選取的待加固的Java層函數(shù)與加固后so文件中相應(yīng)Native函數(shù)建立映射關(guān)系,以達(dá)到細(xì)粒度化加固函數(shù)代碼安全性的目的.
由圖2可知,基于JNI機(jī)制的函數(shù)代碼加固方案的優(yōu)勢(shì)有兩點(diǎn):1)細(xì)粒度的核心函數(shù)代碼加固方式可有效地減少Dalvik虛擬機(jī)的額外工作負(fù)擔(dān),從而使得加固應(yīng)用對(duì)系統(tǒng)資源的消耗不會(huì)有明顯增加;2)通過(guò)JNI機(jī)制實(shí)現(xiàn)Java層函數(shù)與so文件中相應(yīng)Native函數(shù)間建立映射關(guān)系,達(dá)到了Dex文件加固與so文件加固的有機(jī)結(jié)合目的.
為了實(shí)現(xiàn)基于JNI機(jī)制的函數(shù)代碼加固方案,需對(duì)其中涉及的Dex文件類(lèi)及成員函數(shù)抽取算法、基于section的細(xì)粒度so文件加固方法、基于JNI機(jī)制的函數(shù)映射等問(wèn)題展開(kāi)研究工作.
Dex文件中類(lèi)及其成員函數(shù)信息抽取的目的,在于獲取源apk文件中類(lèi)及其成員函數(shù)信息,并將獲取到的信息存儲(chǔ)于自定義的ClassInfoMap和MethodInfoMap結(jié)構(gòu)體中,以供用戶(hù)在其中選擇其需要加固的核心函數(shù).
針對(duì)Dex文件結(jié)構(gòu)[17],提出Dex文件類(lèi)及其成員函數(shù)信息抽取的流程如圖3所示,其步驟如下:
1)提取DexHeader結(jié)構(gòu)體中的mapOff屬性值,并根據(jù)mapOff屬性值找到DexMapList后,轉(zhuǎn)至2).
2)判斷是否遍歷DexMapList集合中的所有DexMapItem結(jié)構(gòu)體實(shí)例,若是轉(zhuǎn)至11),否則轉(zhuǎn)至3).
3)在DexMapList集合中獲取一個(gè)DexMapItem結(jié)構(gòu)體實(shí)例.
4)判斷該DexMapItem結(jié)構(gòu)體實(shí)例中的type屬性值與kDexTypeClassDefItem值是否相同,若相同,則根據(jù)其offset屬性值找到描述類(lèi)信息的DexClassDef結(jié)構(gòu)體實(shí)例,轉(zhuǎn)至5),否則轉(zhuǎn)至2).

圖2 基于JNI機(jī)制的函數(shù)代碼加固流程Fig.2 Flow of the function code reinforcement based on JNI mechanism
5)將該DexClassDef結(jié)構(gòu)體實(shí)例中的classIds、accessFlags和sourceFilesIdx屬性值存放于自定義ClassInfoMap結(jié)構(gòu)體實(shí)例的相應(yīng)屬性中,完成類(lèi)信息的提取,轉(zhuǎn)至6).

圖3 Dex文件類(lèi)及成員函數(shù)信息抽取流程Fig.3 Extraction process of Dex file class and member function information
6)根據(jù)該DexClassDef結(jié)構(gòu)體實(shí)例的classDataoff屬性值找到DexClassData結(jié)構(gòu)體實(shí)例,轉(zhuǎn)至7).
7)讀取DexClassData結(jié)構(gòu)體實(shí)例中的direcMethods屬性值找到DexMethod集合,轉(zhuǎn)至8).
8)是否遍歷DexMethod集合中所有DexMethodId結(jié)構(gòu)體實(shí)例,若是轉(zhuǎn)至2),否則轉(zhuǎn)至9).
9)獲取一個(gè)DexMethod集合中的DexMethodId結(jié)構(gòu)體實(shí)例,轉(zhuǎn)至10).
10)將該DexMethodId結(jié)構(gòu)體實(shí)例中的nameIdx、protoIdx和returnIdx屬性值提取并存放于自定義MethodInfoMap結(jié)構(gòu)體實(shí)例的相應(yīng)屬性中,轉(zhuǎn)至8).
11)結(jié)束.
現(xiàn)有so文件加固的方法,多以整個(gè)so文件作為加固對(duì)象.這種方式,使得加固應(yīng)用運(yùn)行時(shí)給Dalvik虛擬機(jī)造成較大的工作負(fù)荷,并以應(yīng)用性能下降的形式展現(xiàn)出來(lái).為此,提出一種基于section的細(xì)粒度so文件加固方法.該方法選取so文件中承載Native函數(shù)的section作為基本加固對(duì)象,從而實(shí)現(xiàn)對(duì)so文件的細(xì)粒度加固.
3.2.1 自定義section聲明
若用戶(hù)需要將so文件中的某個(gè)Native函數(shù)置于特定的section中,則需在用于編譯so文件的源文件中,在特定函數(shù)名的前面添加__attribute__((section("sectionName")))用以完成編譯后so文件中自定義section的聲明.
3.2.2 自定義section加固
若要對(duì)自定義section進(jìn)行加固,需要首先確定自定義section在so文件中的位置.so文件頭部結(jié)構(gòu)[17]中的e_shoff屬性給出了第一個(gè)section的相對(duì)位置.
在section結(jié)構(gòu)[17]中,sh_name、sh_size屬性分別代表section的名稱(chēng)及大小,且各個(gè)section在so文件中的存放位置是相鄰的,因此,第i+1個(gè)section的起始位置為第i個(gè)section的偏移量加上其sh_size屬性的值.
在準(zhǔn)確提取section地址的基礎(chǔ)上,形成對(duì)單個(gè)自定義section加固的步驟如下.
1)讀取so文件頭部結(jié)構(gòu)中的e_shstrnd屬性值,檢索其中是否存在自定義section名稱(chēng),若有,則轉(zhuǎn)至2);若無(wú),則轉(zhuǎn)至6).
2)讀取so文件頭部結(jié)構(gòu)中的e_shoff屬性值,并定位到第一個(gè)section的位置.
3)根據(jù)so文件頭部結(jié)構(gòu)中的e_shnum屬性值得到該so文件中存在的section數(shù)量.
4)以e_shnum屬性值為終止條件,按照前述section位置的計(jì)算方法逐一比對(duì)section名稱(chēng)與自定義section的名稱(chēng)是否匹配.若匹配,則將自定義section的內(nèi)容讀取到臨時(shí)變量enc_content中,并將該section的位置偏移量及其大小分別存儲(chǔ)于define_section_offset及define_section_size變量中.
5)采用異或算法[18]對(duì)enc_content變量中的內(nèi)容進(jìn)行加密,并用加密后的內(nèi)容替換so文件中自定義section的內(nèi)容.
6)結(jié)束.
3.2.3 自定義section解密
欲對(duì)加固后的自定義section解密,則需先確定自定義section在內(nèi)存中的地址空間.so文件被加載到內(nèi)存的起始地址是不固定的,因此,so文件在內(nèi)存起始地址的獲取是確定自定義section在內(nèi)存中地址空間的關(guān)鍵所在.
so文件被加載至內(nèi)存后,Android系統(tǒng)會(huì)自動(dòng)向proc/
在上述基礎(chǔ)上,定義滿(mǎn)足A≤X≤B的內(nèi)存段為自定義section在內(nèi)存空間的地址范圍,記為[A,B]={X|A≤X≤B},其中A為首地址,B為尾地址,則自定義section在內(nèi)存中地址范圍的計(jì)算方式如式(1)所示.
[A,B]={X|sr+es+dso≤x≤sr+es+dso+dss}
(1)
式中,sr表示so文件在內(nèi)存中的起始地址,es表示so文件的頭部結(jié)構(gòu)大小(固定為52字節(jié)),dso表示自定義section在so文件中的位置偏移量,dss表示自定義section的大小.
通過(guò)以上分析,形成對(duì)單個(gè)自定義section的解密步驟如下.
1)通過(guò)“cat maps|grep”命令得到so文件在內(nèi)存的相關(guān)信息,并獲取該文件在內(nèi)存中的首地址,賦值給式(1)中sr變量.
2)將對(duì)自定義section加固步驟中,記錄的define_section_offset和define_section_size變量分別賦值給式(1)中dso變量和dss變量.
3)按式(1)計(jì)算自定義section在內(nèi)存中的地址空間范圍.
4)根據(jù)第3)步的計(jì)算結(jié)果,提取自定義section內(nèi)容,并將其存放于臨時(shí)變量dec_content中.
5)采用異或算法對(duì)dec_content變量中的內(nèi)容進(jìn)行解密,并用解密后的內(nèi)容替換內(nèi)存中so文件的自定義section的內(nèi)容.
6)結(jié)束.
為使Android應(yīng)用能夠正常調(diào)用so文件中的Native函數(shù),則需建立Java層函數(shù)與so文件中相應(yīng)Native函數(shù)的映射關(guān)系.本文采用修改smali指令[17]實(shí)現(xiàn)JNI機(jī)制的方式建立函數(shù)映射關(guān)系.
為了敘述方便,假設(shè)用戶(hù)選擇的待加固函數(shù)為MainActivity類(lèi)中的getString()函數(shù),則建立Java層getString()函數(shù)與so文件中g(shù)etString()函數(shù)之間映射關(guān)系的步驟如下.
1)在反編譯apk文件后形成的smali文件夾下查找MainActivity.smali文件.
2)在MainActivity.smali文件中,根據(jù)正則表達(dá)式const(.method)(.*?)*getString.*(.end method).查找getString()函數(shù)的smali指令.
3)刪除smali指令中g(shù)etString()函數(shù)的功能實(shí)現(xiàn)部分.
4)在MainActivity.smali文件的getString()函數(shù)功能實(shí)現(xiàn)部分,添加相應(yīng)smali指令,實(shí)現(xiàn)利用JNI機(jī)制調(diào)用加固后so文件中的getString()函數(shù).修改smali指令會(huì)導(dǎo)致所需寄存器數(shù)量發(fā)生變化,因此,在修改smali指令后需要重新計(jì)算并修改該函數(shù)所需的寄存器數(shù)量[17].
經(jīng)過(guò)以上步驟,Java層getString()函數(shù)的功能實(shí)現(xiàn)代碼轉(zhuǎn)移到了so文件的相應(yīng)函數(shù)中,并建立起了二者之間映射關(guān)系.至此,即使逆向人員利用apktool、jadx-ju等工具對(duì)源apk文件進(jìn)行反編譯,也不能直接獲得getString()函數(shù)的代碼內(nèi)容.由此可見(jiàn),該方法可使得Android應(yīng)用Java層函數(shù)代碼的安全性得以提高.
針對(duì)現(xiàn)有加殼解殼方案中源apk文件易于獲取及缺乏對(duì)解殼程序保護(hù)的問(wèn)題,在RMAA加固模型基礎(chǔ)上,融合簽名校驗(yàn)及動(dòng)態(tài)加載技術(shù),提出一種基于云平臺(tái)的加殼解殼方案,其流程如圖4所示.

圖4 基于云平臺(tái)的加殼解殼方案流程Fig.4 Flow of the shell and unshell solution based on cloud platform
平臺(tái)端應(yīng)用加殼程序的主要功能為,將源apk的Dex文件加密并存儲(chǔ)于云平臺(tái)的持久化區(qū),以供Android端應(yīng)用解殼程序下載;將源apk的剩余文件融合于源解殼程序的Dex文件中形成新Dex文件,并對(duì)新Dex文件的相關(guān)參數(shù)值進(jìn)行修正;采用Jarsigner工具對(duì)加固應(yīng)用apk文件進(jìn)行重簽名,并將該簽名的SHA-1值存放于持久化區(qū)(見(jiàn)圖1).
Dex文件頭部結(jié)構(gòu)中的checksum、signature及file_size是描述Dex文件規(guī)格信息的重要屬性,也是Dalvik虛擬機(jī)評(píng)判Dex文件是否可以被正常加載的依據(jù).將源apk剩余資源文件與源解殼程序Dex文件融合后形成的新Dex文件的內(nèi)容及規(guī)格勢(shì)必發(fā)生變化,因此,需要根據(jù)新Dex文件的規(guī)格對(duì)上述3個(gè)屬性的值進(jìn)行修正.
Android端應(yīng)用解殼程序的功能為,首先,從加固應(yīng)用apk文件的Dex文件中提取源apk剩余文件;其次,通過(guò)云平臺(tái)的服務(wù)接口下載源apk加密Dex文件,并利用AES算法對(duì)其解密;再次,將源apk剩余文件與解密后的源apk的Dex文件重新整合為源apk文件;最后,利用動(dòng)態(tài)加載技術(shù)將系統(tǒng)控制權(quán)轉(zhuǎn)交給源apk文件,使源apk文件按原邏輯正常運(yùn)行.基于此,設(shè)計(jì)的解殼程序流程如圖5所示,其中,解殼程序反篡改、動(dòng)態(tài)加載及其相關(guān)置換是其中的關(guān)鍵環(huán)節(jié).
4.2.1 解殼程序反篡改方案
在現(xiàn)有Android應(yīng)用加殼解殼方案中,通常,應(yīng)用的簽名校驗(yàn)邏輯存放在Android應(yīng)用Java層,逆向人員可通過(guò)API分析法[17]等手段找到簽名校驗(yàn)邏輯的代碼位置,然后刪除簽名校驗(yàn)邏輯或者將校驗(yàn)結(jié)果改為真,從而實(shí)現(xiàn)對(duì)解殼程序的逆向篡改.
針對(duì)上述問(wèn)題,提出一種基于云平臺(tái)技術(shù)的解殼程序反篡改方案,具體流程如下.
首先以加固應(yīng)用簽名的SHA-1值為參數(shù)訪問(wèn)云平臺(tái)提供下載源apk加密Dex文件的服務(wù)接口,若該SHA-1值與云平臺(tái)保存的SHA-1值一致則簽名校驗(yàn)通過(guò),允許下載源apk的Dex文件,否則退出加固應(yīng)用.

圖5 解殼程序流程Fig.5 Flow of the unshell
由此可見(jiàn),在基于云平臺(tái)的加殼解殼方案中,若逆向人員通過(guò)非法手段對(duì)解殼程序進(jìn)行逆向篡改后,由于篡改前后解殼程序的簽名SHA-1值發(fā)生了變化,導(dǎo)致無(wú)法從云平臺(tái)下載源apk加密Dex文件,從而有效防范加固應(yīng)用的非法運(yùn)行.
4.2.2 動(dòng)態(tài)加載及其相關(guān)置換
由圖5可知,為了使源apk文件能夠正常運(yùn)行,需要利用反射機(jī)制置換Dalvik虛擬機(jī)的默認(rèn)類(lèi)加載器為自定義類(lèi)加載器,以達(dá)到動(dòng)態(tài)加載源apk文件的目的.
在動(dòng)態(tài)加載源apk文件之后,Dalvik虛擬機(jī)將源apk文件加載至解殼程序所在的進(jìn)程中,但由于此時(shí)內(nèi)存中Application實(shí)例是解殼程序的Applicaiton對(duì)象,Dalvik虛擬機(jī)無(wú)法找到源apk文件的入口.因此,需要將此時(shí)的Application實(shí)例置換為源apk文件的Application對(duì)象.
此外,為了使源apk文件能夠正常運(yùn)行,還需要利用反射機(jī)制置換Resource類(lèi)中的mAssetsManager實(shí)例為自定義AsseManager對(duì)象,以保證Dalvik虛擬機(jī)可以正常訪問(wèn)源apk文件的資源文件.此處,自定義AsseManager對(duì)象是AssetsManager類(lèi)的一個(gè)實(shí)例,其addAssetPath()方法可以獲得相應(yīng)資源文件的訪問(wèn)路徑.
在RMAA加固模型總體框架的指引下,在基于JNI機(jī)制的函數(shù)代碼加固方案及基于云平臺(tái)的加殼解殼方案的研究基礎(chǔ)上,設(shè)計(jì)并開(kāi)發(fā)了RMAA加固系統(tǒng)原型,并從基于section的細(xì)粒度so文件加固有效性、基于JNI機(jī)制的函數(shù)映射有效性,以及應(yīng)用加固前后性能變化3個(gè)方面對(duì)基于JNI機(jī)制與云平臺(tái)的細(xì)粒度Android應(yīng)用加固方法的有效性進(jìn)行驗(yàn)證.
以自主開(kāi)發(fā)的用于人體健康風(fēng)險(xiǎn)評(píng)測(cè)的Android應(yīng)用healthEvl.apk文件作為測(cè)試用例,并輸入RMAA加固系統(tǒng).在RMAA加固系統(tǒng)完成對(duì)healthEvl.apk文件的反編譯、類(lèi)及其成員函數(shù)的信息抽取環(huán)節(jié)后,以用戶(hù)選擇用于疾病風(fēng)險(xiǎn)評(píng)估的Java層disRiskByMeridian函數(shù)為例,驗(yàn)證基于section的細(xì)粒度so文件加固的有效性.
利用IDAPro逆向工具反匯編加固前后的so文件,分別得到如圖6、圖7所示的逆向視圖.

圖6 so文件加固前的逆向視圖Fig.6 Reverse view of so file before reinforcing
由圖6可知,反匯編未加固前的so文件,可顯示disRiskByMeridian()函數(shù)的完整匯編代碼;逆向人員可以通過(guò)對(duì)匯編代碼的分析掌握disRiskByMeridian()函數(shù)的實(shí)現(xiàn)過(guò)程.由圖7可知,對(duì)so文件中承載disRiskByMeridian()函數(shù)的section加密后,再次反匯編加固后的so文件時(shí)發(fā)生錯(cuò)誤,且無(wú)法得到disRiskByMeridian()函數(shù)的匯編代碼.由此,可驗(yàn)證基于section的細(xì)粒度so文件加固的有效性.

圖7 so文件加固后的逆向視圖Fig.7 Reverse view of so file after reinforcing
以RMAA加固系統(tǒng)加固healthEvl.apk文件中的ReasoningCenter類(lèi)的disRiskByMeridian函數(shù)得到的reinforce.apk文件為例,驗(yàn)證基于JNI機(jī)制的函數(shù)映射有效性.在驗(yàn)證reinforce.apk應(yīng)用功能正常的基礎(chǔ)上,利用jadx-gui逆向工具反編譯healthEvl.apk和reinforce.apk文件,分別得到如圖8和圖9所示的逆向視圖.

圖8 healthEvl.apk逆向視圖Fig.8 Reverse view on healthEvl.apk
對(duì)比圖8與圖9可知,healthEvl.apk經(jīng)加固后,disRiskByMeridian()函數(shù)的函數(shù)體由實(shí)現(xiàn)代碼變?yōu)榱薐NIManager.disRiskByMeridian(),從而驗(yàn)證了函數(shù)映射機(jī)制的有效性.
從理論角度分析,經(jīng)RMAA加固系統(tǒng)加固后的應(yīng)用,在apk文件大小、內(nèi)存占用量及啟動(dòng)時(shí)間等方面均會(huì)有所增加.apk文件大小增加的主要原因是在原有apk文件基礎(chǔ)上增加了解殼程序代碼和so文件;加固應(yīng)用在解殼過(guò)程中,對(duì)源apk的Dex文件解密以及對(duì)源apk文件的動(dòng)態(tài)加載環(huán)節(jié)需要開(kāi)辟額外的內(nèi)存空間,因此,在加固應(yīng)用的啟動(dòng)階段,內(nèi)存占用量及啟動(dòng)時(shí)間均會(huì)明顯增加.此外,下載Dex文件時(shí)消耗在網(wǎng)絡(luò)傳輸上的時(shí)間是啟動(dòng)時(shí)間增加的主要影響因素.

圖9 reinforce.apk逆向視圖Fig.9 Reverse view on reinforce.apk
為了測(cè)試應(yīng)用加固前后實(shí)際的apk文件大小、啟動(dòng)階段內(nèi)存占用量及啟動(dòng)時(shí)間等方面的變化,從開(kāi)源社區(qū)Gitee下載5個(gè)未加固的apk文件.在經(jīng)RMAA加固系統(tǒng)加固過(guò)程中,每個(gè)應(yīng)用均選取1個(gè)函數(shù)進(jìn)行基于JNI機(jī)制的函數(shù)代碼加固.5個(gè)應(yīng)用加固前后apk文件大小、啟動(dòng)階段內(nèi)存占用量、啟動(dòng)時(shí)間的變化情況如表1所示.
由表1可知,加固應(yīng)用apk文件的大小增量變化平緩,穩(wěn)定在0.2MB左右,啟動(dòng)階段內(nèi)存增量穩(wěn)定在8MB左右,啟動(dòng)時(shí)間增量在500ms以下.由此可見(jiàn),在內(nèi)存增量方面,對(duì)于目前存儲(chǔ)容量為幾十乃至上百GB級(jí)別的Android終端的影響可以忽略不計(jì);在啟動(dòng)時(shí)間增量方面,用戶(hù)是難以感知的.

表1 應(yīng)用加固前后性能指標(biāo)對(duì)比Table 1 Comparison of performance indexes before and after reinforcing
本文針對(duì)現(xiàn)有Android應(yīng)用加固技術(shù)或方法的不足,提出一種基于JNI機(jī)制與云平臺(tái)的細(xì)粒度Android應(yīng)用加固方法.該方法采用基于JNI機(jī)制的函數(shù)代碼加固方案實(shí)現(xiàn)了so文件的細(xì)粒度加固,從而使得逆向人員不能通過(guò)逆向工具輕易獲取應(yīng)用的核心函數(shù)代碼,且加固應(yīng)用并未顯著增加Dalvik虛擬機(jī)工作負(fù)擔(dān);采用基于云平臺(tái)的加殼解殼方案,通過(guò)解殼程序運(yùn)行時(shí)以加固應(yīng)用簽名的SHA-1值為參數(shù)訪問(wèn)云平臺(tái)提供下載源apk加密Dex文件的服務(wù)接口方式,有效解決了源apk文件易被獲取以及解殼程序易被篡改的問(wèn)題.通過(guò)RMAA加固系統(tǒng)驗(yàn)證了基于JNI機(jī)制與云平臺(tái)的細(xì)粒度Android應(yīng)用加固方法的有效性,且加固應(yīng)用的啟動(dòng)時(shí)間、內(nèi)存占用量等并未顯著增加.
在后續(xù)的研究工作中,可采用機(jī)器學(xué)習(xí)手段開(kāi)展根據(jù)smali指令語(yǔ)義自動(dòng)生成相應(yīng)so文件的研究工作,從而進(jìn)一步提升該加固方法的自動(dòng)化程度.