本發(fā)明涉及應(yīng)用程序安全領(lǐng)域,特別是涉及一種應(yīng)用程序的加固方法和裝置。
背景技術(shù):
隨著網(wǎng)絡(luò)技術(shù)的發(fā)展,網(wǎng)絡(luò)已成為人們生活的一部分,給人們的生活帶來了便利。為了滿足不同的需求,提供各種服務(wù)的應(yīng)用程序被開發(fā)和發(fā)布使用。應(yīng)用程序的開發(fā)花費(fèi)了開發(fā)者大量的人力和財力,然而,大量的應(yīng)用程序被破解,重新打包,并構(gòu)建了大量的山寨應(yīng)用,并在山寨應(yīng)用程序中植入惡意指令、廣告插件及其它惡意行為等。用戶下載和安裝了山寨應(yīng)用程序后,山寨應(yīng)用程序內(nèi)的惡意指令會竊取用戶的數(shù)據(jù),威脅用戶的個人信息和財產(chǎn)安全。
技術(shù)實現(xiàn)要素:
基于此,有必要針對傳統(tǒng)的應(yīng)用程序破解后被植入惡意指令導(dǎo)致用戶數(shù)據(jù)易被竊取的問題,提供一種應(yīng)用程序的加固方法和裝置,能提高應(yīng)用程序的安全性,防止用戶數(shù)據(jù)被竊取。
一種應(yīng)用程序的加固方法,包括以下步驟:
靜態(tài)掃描應(yīng)用程序安裝包,獲取待加密的資源文件;
對所述待加密的資源文件進(jìn)行加密,生成包含資源文件密文的應(yīng)用程序安裝包;
向所述包含資源文件密文的應(yīng)用程序安裝包添加解密模塊,生成包含所述解密模塊和資源文件密文的應(yīng)用程序安裝包。
一種應(yīng)用程序的加固裝置,包括:
掃描模塊,用于靜態(tài)掃描應(yīng)用程序安裝包,獲取待加密的資源文件;
加密模塊,用于對所述待加密的資源文件進(jìn)行加密,生成包含資源文件密文的應(yīng)用程序安裝包;
添加模塊,用于向所述包含資源文件密文的應(yīng)用程序安裝包添加解密模塊,生成包含所述解密模塊和資源文件密文的應(yīng)用程序安裝包。
上述應(yīng)用程序的加固方法和裝置,通過掃描應(yīng)用程序安裝包,獲取待加密的資源文件,并對待加密的資源文件進(jìn)行加密,并將解密模塊添加到包含資源文件密文的應(yīng)用程序安裝包中,當(dāng)系統(tǒng)運(yùn)行應(yīng)用程序時,使用解密模塊對資源文件密文進(jìn)行解密成資源文件明文,確保應(yīng)用程序的正常執(zhí)行,當(dāng)使用破解工具從應(yīng)用程序安裝包里提取資源文件時,獲取到的是資源文件密文,使得資源文件不被竊取及修改,提高了應(yīng)用程序的安全性,防止用戶數(shù)據(jù)被竊取。
附圖說明
圖1A中的終端的內(nèi)部結(jié)構(gòu)示意圖;
圖1B為一個實施例中服務(wù)器的內(nèi)部結(jié)構(gòu)示意圖;
圖2為一個實施例中應(yīng)用程序的加固方法的流程圖;
圖3為另一個實施例中應(yīng)用程序的加固方法的流程圖;
圖4為一個實施例中通過解密模塊透明解密資源文件密文為資源文件明文的具體流程圖;
圖5為訪問應(yīng)用程序資源文件的示意圖;
圖6為一個實施例中應(yīng)用程序的加固裝置的結(jié)構(gòu)框圖;
圖7為另一個實施例中應(yīng)用程序的加固裝置的結(jié)構(gòu)框圖。
具體實施方式
為了使本發(fā)明的目的、技術(shù)方案及優(yōu)點(diǎn)更加清楚明白,以下結(jié)合附圖及實施例,對本發(fā)明進(jìn)行進(jìn)一步詳細(xì)說明。應(yīng)當(dāng)理解,此處所描述的具體實施例僅僅用以解釋本發(fā)明,并不用于限定本發(fā)明。
可以理解,本發(fā)明所使用的術(shù)語“第一”、“第二”等可在本文中用于描述各種元件,但這些元件不受這些術(shù)語限制。這些術(shù)語僅用于將第一個元件與另一個元件區(qū)分。舉例來說,在不脫離本發(fā)明的范圍的情況下,可以將第一客戶端稱為第二客戶端,且類似地,可將第二客戶端稱為第一客戶端。第一客戶端 和第二客戶端兩者都是客戶端,但其不是同一客戶端。
圖1A中的終端的內(nèi)部結(jié)構(gòu)示意圖。如圖1A所示,該終端包括通過系統(tǒng)總線連接的處理器、存儲介質(zhì)、內(nèi)存和網(wǎng)絡(luò)接口、聲音采集裝置、顯示屏、揚(yáng)聲器和輸入裝置。其中,終端的存儲介質(zhì)存儲有操作系統(tǒng),還包括一種應(yīng)用程序的加固裝置,該應(yīng)用程序的加固裝置用于實現(xiàn)一種應(yīng)用程序的加固方法。該處理器用于提供計算和控制能力,支撐整個終端的運(yùn)行。終端中的內(nèi)存為存儲介質(zhì)中的應(yīng)用程序的加固裝置的運(yùn)行提供環(huán)境,網(wǎng)絡(luò)接口用于與服務(wù)器進(jìn)行網(wǎng)絡(luò)通信,如發(fā)送應(yīng)用程序下載請求至服務(wù)器,接收服務(wù)器返回的應(yīng)用程序安裝包等。終端的顯示屏可以是液晶顯示屏或者電子墨水顯示屏等,輸入裝置可以是顯示屏上覆蓋的觸摸層,也可以是終端外殼上設(shè)置的按鍵、軌跡球或觸控板,也可以是外接的鍵盤、觸控板或鼠標(biāo)等。該終端可以是手機(jī)、平板電腦或者個人數(shù)字助理。本領(lǐng)域技術(shù)人員可以理解,圖1A中示出的結(jié)構(gòu),僅僅是與本申請方案相關(guān)的部分結(jié)構(gòu)的框圖,并不構(gòu)成對本申請方案所應(yīng)用于其上的終端的限定,具體的終端可以包括比圖中所示更多或更少的部件,或者組合某些部件,或者具有不同的部件布置。
圖1B為一個實施例中服務(wù)器的內(nèi)部結(jié)構(gòu)示意圖。如圖1B所示,該服務(wù)器包括通過系統(tǒng)總線連接的處理器、存儲介質(zhì)、內(nèi)存和網(wǎng)絡(luò)接口。其中,該服務(wù)器的存儲介質(zhì)存儲有操作系統(tǒng)、數(shù)據(jù)庫和應(yīng)用程序的加固裝置,數(shù)據(jù)庫中存儲有應(yīng)用程序的安裝包等,該應(yīng)用程序的加固裝置用于實現(xiàn)適用于服務(wù)器的一種應(yīng)用程序的加固方法。該服務(wù)器的處理器用于提供計算和控制能力,支撐整個服務(wù)器的運(yùn)行。該服務(wù)器的內(nèi)存為存儲介質(zhì)中的應(yīng)用程序的加固裝置的運(yùn)行提供環(huán)境。該服務(wù)器的網(wǎng)絡(luò)接口用于據(jù)以與外部的終端通過網(wǎng)絡(luò)連接通信,比如接收終端發(fā)送的應(yīng)用程序的下載請求以及向終端返回應(yīng)用程序安裝包等。服務(wù)器可以用獨(dú)立的服務(wù)器或者是多個服務(wù)器組成的服務(wù)器集群來實現(xiàn)。本領(lǐng)域技術(shù)人員可以理解,圖1B中示出的結(jié)構(gòu),僅僅是與本申請方案相關(guān)的部分結(jié)構(gòu)的框圖,并不構(gòu)成對本申請方案所應(yīng)用于其上的服務(wù)器的限定,具體的服務(wù)器可以包括比圖中所示更多或更少的部件,或者組合某些部件,或者具有不同的部件布置。
圖2為一個實施例中應(yīng)用程序的加固方法的流程圖。如圖2所示,一種應(yīng)用程序的加固方法,包括以下步驟:
步驟202,靜態(tài)掃描應(yīng)用程序安裝包,獲取待加密的資源文件。
具體地,一個APK(應(yīng)用程序安裝包)安裝包是一個ZIP格式的壓縮文件,里面包含了一款移動APP(應(yīng)用程序)里的所需的代碼、圖片、布局、聲音、動畫、字符串、XML(Extensible Markup Language,可擴(kuò)展標(biāo)記語言)文件、配置文件、資源索引文件及其它二進(jìn)制數(shù)據(jù)。其中,圖片、布局、聲音、動畫、字符串、XML文件及其它二進(jìn)制數(shù)據(jù)屬于APP的資源。它們以文件的形式保存在APK文件的assets、res目錄中,res目錄存儲圖片、布局、聲音、動畫、字符串、XML文件,assets目錄存儲其它二進(jìn)制數(shù)據(jù)文件,布局文件是指存儲在res/layout或者res/layout-xxx(xxx表示任何字符)中AXML文件(XML文件經(jīng)過aidl編譯生成的一種二進(jìn)制文件),用來描述APP界面中各種控件的擺放位置及屬性。
需要說明的是,應(yīng)用程序的加固是指對應(yīng)用程序的安裝包進(jìn)行安全重構(gòu),防止應(yīng)用程序被反編譯、惡意篡改、保護(hù)應(yīng)用數(shù)據(jù)不被竊取及其它重打包后可以進(jìn)行的惡意攻擊等。
步驟202包括:靜態(tài)掃描應(yīng)用程序安裝包,預(yù)判只在應(yīng)用程序安裝包的用戶進(jìn)程中加載的資源文件作為待加密的資源文件。
例如,當(dāng)掃描發(fā)現(xiàn)應(yīng)用程序內(nèi)包括將圖片資源A傳遞給創(chuàng)建桌面圖標(biāo)相關(guān)的API的代碼邏輯時,則預(yù)判圖片資源A將在系統(tǒng)服務(wù)進(jìn)程中加載,因為圖片資源A被系統(tǒng)服務(wù)進(jìn)程加載,所以圖片資源A將不被加密。
靜態(tài)掃描應(yīng)用程序安裝包包括:
(1)讀取資源文件的索引文件,獲取每個資源文件對應(yīng)的資源文件標(biāo)識,并獲取資源文件標(biāo)識對應(yīng)的資源文件保存在待加密資源列表中。
具體地,讀取資源文件的索引文件(resources.arsc),獲取索引文件中指向的第一個圖片的路徑,作為獲取混淆后的res目錄路徑(某些App會將res目錄改名,所以res文件名不固定,需從這里獲取),保存為第一資源路徑;讀取資源文件的索引文件,獲取第一資源路徑內(nèi)每個資源文件對應(yīng)的資源文件ID(標(biāo) 識)。將assets目錄作為第二資源路徑。遍歷第一資源路徑和第二資源路徑里的所有資源文件,并將所有資源文件保存在待加密資源列表中。
(2)掃描配置文件,獲取配置文件中引用到的資源文件標(biāo)識,并獲取引用到的資源文件標(biāo)識對應(yīng)的資源文件名稱,加入到第一排除列表。
掃描配置文件AndroidManifest.xml,獲取配置文件中引用到的所有資源文件ID,并獲取資源文件ID對應(yīng)的資源文件名稱,并將對應(yīng)的資源文件名稱加入到第一排除列表中。
(3)掃描代碼文件,獲取調(diào)用了預(yù)設(shè)應(yīng)用程序接口的資源文件標(biāo)識,并獲取該資源文件標(biāo)識對應(yīng)的資源文件名稱,加入到第二排除列表。
可預(yù)先設(shè)置API接口數(shù)據(jù)庫,掃描應(yīng)用程序文件的代碼時,檢測到調(diào)用的API接口在預(yù)先設(shè)置的API接口數(shù)據(jù)庫查找得到,則代碼傳入的資源參數(shù)所對應(yīng)的資源文件不能加密。
掃描代碼文件(classes.dex),獲取調(diào)用了以下API的方法:
"Landroid/content/Intent$ShortcutIconResource;->fromContext(Landroid/content/Context;I)Landroid/content/Intent$ShortcutIconResource;";
"Landroid/app/Notification;-><init>()V";
"Landroid/app/Notification;-><init>(ILjava/lang/CharSequence;J)V";
"Landroid/app/Notification;->setLatestEventInfo(Landroid/content/Context;Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/app/PendingIntent;)V";
"Landroid/app/NotificationManager;->cancel(I)V";
"Landroid/app/NotificationManager;->cancel(Ljava/lang/String;I)V";
"Landroid/app/NotificationManager;->notify(ILandroid/app/Notification;)V";
"Landroid/app/NotificationManager;->notify(Ljava/lang/String;ILandroid/app/Notification;)V";
"Landroid/support/v4/app/NotificationCompat$Builder;-><init>(Landroid/content/Context;)V";
"Landroid/support/v4/app/NotificationCompat$Builder;->setSmallIcon(I)Landroid/support/v4/app/NotificationCompat$Builder";
"Landroid/app/WallpaperManager;->setResource(I)V";
"Landroid/widget/RemoteViews;-><init>(Ljava/lang/String;I)V"。
將上一步獲取的方法的所有定義類型的指令(如指令字節(jié)碼為0x14),其后面跟著的就是整型的值,將其作為資源文件ID,獲取該資源文件ID對應(yīng)的資源文件名稱,將得到的資源文件名稱加入第二排除列表中。
(3)將待加密資源列表中的資源文件減去第一排除列表和第二排除列表中的資源文件,剩余的資源文件作為待加密資源文件。
此外,還可從剩余的資源文件中篩選出圖片、布局資源作為待加密資源文件。
步驟204,對該待加密的資源文件進(jìn)行加密,生成包含資源文件密文的應(yīng)用程序安裝包。
具體地,根據(jù)安全需求,獲取一對公鑰和私鑰,使用私鑰對該待加密的資源文件進(jìn)行加密,將加密后的資源文件打包進(jìn)應(yīng)用程序安裝包中,生成包含資源文件密文的應(yīng)用程序安裝包,并將公鑰與待加密資源列表作為資源文件打包進(jìn)包含資源文件密文的應(yīng)用程序安裝包。
步驟206,向該包含資源文件密文的應(yīng)用程序安裝包添加解密模塊,生成包含該解密模塊和資源文件密文的應(yīng)用程序安裝包。
具體地,解密模塊可為so解密模塊,即內(nèi)嵌在移動APP里的透明解密模塊,它是由native語言開發(fā)的一個so文件。將so解密模塊嵌入到應(yīng)用程序安裝包,具體包括:將so解密模塊以資源文件的形式打包進(jìn)Assets目錄,生成包含解密模塊的應(yīng)用程序安裝包。
Assets目錄用于向移動APP提供二進(jìn)制的文件存儲能力。將so解密模塊的arm版本與x86版本一起以資源文件的形式保存在Assets目錄中。
將so解密模塊以資源文件的形式打包進(jìn)Assets目錄中,生成包含解密模塊的應(yīng)用程序安裝包的步驟包括:
(1)掃描配置文件,獲取入口方法。
在AndroidManifest.xml文件中,描述有application結(jié)點(diǎn)、activity結(jié)點(diǎn)、service結(jié)點(diǎn)。每個結(jié)點(diǎn)都有若干屬性,其中,android:name屬性用于描述該結(jié)點(diǎn) 對應(yīng)組件所在的類,android:process屬性用于描述該結(jié)點(diǎn)對應(yīng)組件所在的進(jìn)程程,結(jié)點(diǎn)下面又會有子結(jié)點(diǎn)、孫子結(jié)點(diǎn)。當(dāng)application結(jié)點(diǎn)包含android:name,將該組件所在的類添加到入口類集合,否則包含孫子結(jié)點(diǎn)<actionandroid:name="android.intent.action.MAIN"/>的activity組件所在的類添加到入口類集合;當(dāng)service結(jié)點(diǎn)包含android:process屬性時,將該組件所在的類添加到入口類集合。
將入口類集合的onCreate方法定為入口方法集合。
(2)在該入口方法中插入釋放so解密模塊,并加載so解密模塊。
具體地,修改classes.dex文件中描述入口方法的代碼指令,添加以下邏輯:釋放so解密模塊至APP目錄;加載釋放出來的so解密模塊。
(3)調(diào)整該入口方法的寄存器。
由于入口方法的寄存器數(shù)量可能不足以執(zhí)行新增的代碼指令,所以需要進(jìn)行調(diào)整,同時還要修改原本代碼里的try和handler的指令偏移,使入口方法的原功能不受影響。
修改完dex文件后重新寫入classes.dex的校驗值,然后打包到包括解密模塊的第一應(yīng)用程序安裝包,生成包括解密模塊的第二應(yīng)用程序安裝包,輸出為經(jīng)加固的應(yīng)用程序安裝包。
上述應(yīng)用程序的加固方法,通過掃描應(yīng)用程序安裝包,獲取待加密的資源文件,并對待加密的資源文件進(jìn)行加密,并將解密模塊添加到包含資源文件密文的應(yīng)用程序安裝包中,當(dāng)系統(tǒng)運(yùn)行應(yīng)用程序時,使用解密模塊對資源文件密文進(jìn)行解密成資源文件明文,確保應(yīng)用程序的正常執(zhí)行,當(dāng)使用破解工具從應(yīng)用程序安裝包里提取資源文件時,獲取到的是資源文件密文,使得資源文件不被竊取及修改,提高了應(yīng)用程序的安全性,防止用戶數(shù)據(jù)被竊取。
圖3為另一個實施例中應(yīng)用程序的加固方法的流程圖。圖3中的應(yīng)用程序的加固方法與圖2的區(qū)別在于,增加了在移動終端上安裝及運(yùn)行應(yīng)用程序安裝包的過程。如圖3所示,一種應(yīng)用程序的加固方法,包括以下步驟:
步驟302,靜態(tài)掃描應(yīng)用程序安裝包,獲取待加密的資源文件。
步驟304,對該待加密的資源文件進(jìn)行加密,生成包含資源文件密文的應(yīng)用 程序安裝包。
步驟306,向該包含資源文件密文的應(yīng)用程序安裝包添加解密模塊,生成包含該解密模塊和資源文件密文的應(yīng)用程序安裝包。
步驟308,安裝該包含解密模塊和資源文件密文的應(yīng)用程序安裝包。
具體地,將加固后的APK安裝包傳給開發(fā)者用戶,開發(fā)者用戶使用自己的證書對該APK安裝包進(jìn)行簽名,生成待發(fā)布的APK安裝包,將待發(fā)布的APK安裝包,上傳到應(yīng)用市場或其他發(fā)布途徑,作為已發(fā)布APK安裝包。用戶通過各種可獲取到APK,安裝至移動終端上。該移動終端可為手機(jī)、平板電腦、個人數(shù)字助理等。
步驟310,在運(yùn)行該應(yīng)用程序安裝包時,加載該解密模塊,并掛鉤系統(tǒng)函數(shù),得到掛鉤回調(diào)函數(shù)。
具體地,運(yùn)行經(jīng)加固的APP,加載so解密模塊會在APP的功能代碼之前先執(zhí)行,將so解密模塊從assets目錄釋放到APP目錄,然后加載該so解密模塊。
So解密模塊首先會掛鉤系統(tǒng)代碼里的AssetManager類的open、openNonAsset函數(shù),這兩個函數(shù)在系統(tǒng)每次訪問資源文件的過程中都會被調(diào)用,函數(shù)open經(jīng)過C++編譯器的編譯后得到的符號名為:
_ZN7android12AssetManager4openEPKcNS_5Asset10AccessModeE;
方法openNonAsset有兩個多態(tài)實現(xiàn),經(jīng)編譯后,其符號名為:
_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeE;
_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeE
對于Android 5.0及以后的系統(tǒng),方法openNonAsset的導(dǎo)出符號為:
_ZN7android12AssetManager12openNonAssetEPvPKcNS_5Asset10AccessModeE;
_ZN7android12AssetManager12openNonAssetEiPKcNS_5Asset10AccessModeE。
系統(tǒng)會把資源文件的全路徑轉(zhuǎn)給open、openNonAsset函數(shù),這兩個函數(shù), 再從APK安裝包里,讀取該路徑指向的資源文件密文,將其構(gòu)造成第一類數(shù)據(jù)的對象,即_FileAsset類的對象,并最終返回指向該對象的Asset類指針。Asset類是_FileAsset的父類,系統(tǒng)上層不識別_FileAsset類,只通過Asset類的指針去訪問一個資源文件。
So解密模塊掛鉤系統(tǒng)函數(shù)得到掛鉤回調(diào)函數(shù)。具體地,So解密模塊默認(rèn)使用Got Hook進(jìn)行掛鉤,掛鉤的是libandroid_runtime.so模塊里的got表,部分移動的rom經(jīng)過修改,libandroid_runtime.so模塊,以致該掛鉤方式失敗,則使用Inline Hook進(jìn)行掛鉤,掛鉤模塊是libutils.so(android 4.0及以下版本)或libandroidfw.so(android 4.1及以上版本),掛鉤了open、openNonAsset函數(shù)后,系統(tǒng)上層再調(diào)用這些函數(shù),就會轉(zhuǎn)到so解密模塊的掛鉤回調(diào)函數(shù)hook_open、hook_openNonAsset,同時保存掛鉤前的原函數(shù)original_open、original_openNonAsset。隨后,so解密模塊就開始等待系統(tǒng)上層調(diào)用open、openNonAsset函數(shù)。
該掛鉤系統(tǒng)函數(shù)包括以下符號:
"_ZN7android12AssetManager4openEPKcNS_5Asset10AccessModeE";
"_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeE";
"_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeEPi";
"_ZN7android12AssetManager12openNonAssetEPvPKcNS_5Asset10AccessModeE";
"_ZN7android12AssetManager12openNonAssetEiPKcNS_5Asset10AccessModeE"。
步驟312,通過解密模塊透明解密資源文件密文為資源文件明文。
圖4為一個實施例中通過解密模塊透明解密資源文件密文為資源文件明文的具體流程圖。如圖4所示,通過解密模塊透明解密資源文件密文為資源文件明文的步驟包括:
步驟402,獲取資源文件訪問請求。
具體地,當(dāng)移動APP需要使用某些資源文件時,則產(chǎn)生獲取資源文件訪問請求。
步驟404,根據(jù)該訪問請求中所指向的第一類數(shù)據(jù),獲取資源文件密文,解密該資源文件密文得到資源文件明文,并將該資源文件明文保存為第二類數(shù)據(jù)。
具體地,根據(jù)該訪問請求,系統(tǒng)上層會首先調(diào)用AssetManager類的open、openNonAsset函數(shù)去打開訪問請求中所指向的第一類數(shù)據(jù),即_FileAsset類中的該資源文件,獲取用于讀取資源文件的Asset對象指針。由于open、openNonAsset函數(shù)已經(jīng)被掛鉤,該調(diào)用會跳轉(zhuǎn)到掛鉤回調(diào)函數(shù)hook_open、hook_openNonAsset中,通過傳入?yún)?shù)(參數(shù)可為char*字符串指針)獲取要待打開資源文件路徑,若該路徑不包含在待加密資源列表中,則直接返回ori_open、ori_openNonAsset的調(diào)用結(jié)果;若該路徑包含在待加密資源列表中,則獲取資源文件密文,解密該資源文件密文得到資源文件明文的步驟包括:
調(diào)用ori_open、ori_openNonAsset獲取資源文件密文的Asset對象指針;
調(diào)用資源文件密文Asset對象指針的getBuffer函數(shù),獲取資源文件密文;
使用公鑰解密資源文件密文,生成資源文件明文。
從資源文件明文數(shù)據(jù)構(gòu)建第二類數(shù)據(jù)(第二類數(shù)據(jù)可為_HookAsset對象),若系統(tǒng)版本為Android 4.1及以下版本,則構(gòu)建32位版的_HookAsset對象,32位版的_HookAsset對象與64位版的_HookAsset對象的差異在于32位版的參數(shù)或返回值里的size_t或offset_t類型為32位無符號整型,需要一個通用寄存器傳值,而64位的是64位無符號整型,需要兩個通用寄存器傳值,將該對象轉(zhuǎn)換為Asset對象指針返還給系統(tǒng)上層。_HookAsset類繼承于Asset類,重載以下方法:
read返回文件指針?biāo)谄铺幹付ㄩL度的明文數(shù)據(jù);
seek將文件指針置為指定依??;
close釋放明文數(shù)據(jù)內(nèi)存;
getBuffer返回明文數(shù)據(jù)的起始地址;
getLength返回明文數(shù)據(jù)的長度;
getRemainingLength返回明文數(shù)據(jù)長度減文件偏移的差;
openFileDescriptor將資源文明文釋放到文件系統(tǒng),保存為第三類數(shù)據(jù)文件,再返回第三類數(shù)據(jù)文件的文件描述符;
isAllocated返回true;
getAssetSource獲取資源文件路徑。
步驟406,偽造用于訪問第二類數(shù)據(jù)的對象。
具體地,偽造用于訪問第二類數(shù)據(jù)的對象可為_HookAsset對象。
該偽造用于訪問第二類數(shù)據(jù)的對象,該第二類數(shù)據(jù)的對象滿足以下條件:
繼承于系統(tǒng)的Asset類或Asset類的子類;
重載Asset類的所有方法,將所有對第一類數(shù)據(jù)的訪問重定向為對第二類數(shù)據(jù)的訪問;
重載Asset類的openFileDescriptor方法,將第二類數(shù)據(jù)保存為文件系統(tǒng)中的第三類數(shù)據(jù),再返回該第三類數(shù)據(jù)的文件描述符。
步驟408,在掛鉤回調(diào)函數(shù)中,用該偽造的第二類數(shù)據(jù)的對象替換第一類數(shù)據(jù)的對象,并將該第二類數(shù)據(jù)的對象表示的資源文件明文作為訪問結(jié)果返回。
具體地,采用第二類數(shù)據(jù)(代表資源文件明文)的對象(_HookAsset對象)替換第一類數(shù)據(jù)(代表資源文件密文)的對象(_FileAsset對象),將第二類數(shù)據(jù)的對象表示的資源文件明文數(shù)據(jù)作為訪問結(jié)果返回。
在一個實施例中,在掛鉤回調(diào)函數(shù)中,用該偽造的第二類數(shù)據(jù)的對象替換第一類數(shù)據(jù)的對象,并將該第二類數(shù)據(jù)的對象作為訪問結(jié)果返回的步驟之后,該應(yīng)用程序的加固方法還包括:資源使用結(jié)束后,銷毀第二類數(shù)據(jù)的對象。銷毀第二數(shù)據(jù)的對象可防止其被破解工具提取,提高數(shù)據(jù)的安全性。同時,節(jié)省存儲空間。
圖5為訪問應(yīng)用程序資源文件的示意圖。如圖5所示,某APP應(yīng)用程序訪問一個資源文件(例如,使用setContentView(R.layout.activity)方法設(shè)置當(dāng)前Activity的布局),安卓系統(tǒng)通過調(diào)用openNonAsset函數(shù)去獲取資源文件res/layout/activity.xml的_FileAsset對象,由于該資源文件已經(jīng)被加密,所以得到的是加密的資源文件,在隨后Android系統(tǒng)使用Asset->read讀取資源文件數(shù)據(jù)時,獲取到無法識別數(shù)據(jù)導(dǎo)致進(jìn)程崩潰。加載so解密模塊,對該系統(tǒng)函數(shù)進(jìn)行 掛鉤,掛鉤openNonAsset,用_HookAsset替換_FileAsset,將代表資源文件密文的_FileAsset對象替換為代表資源文件明文的_HookAsset對象,隨后Android系統(tǒng)使用Asset->read讀取數(shù)據(jù)時,調(diào)用的是_HookAsset->read,讀取的是資源文件明文數(shù)據(jù)。
當(dāng)調(diào)用的指定接口為Asset->openFileDescriptor接口時,指定資源文件目錄可為assets/splash.png。將資源文件密文解密到/data/data/包名/files/txres/splash.png,以后再調(diào)用openFileDescriptor接口時,直接使用解密的資源文件明文。對于未調(diào)用該指定接口的資源文件,只在每次接收到操作請求后開始解密,不在文件系統(tǒng)中保存明文數(shù)據(jù)。通過指定接口調(diào)用資源文件,可以實現(xiàn)對資源系統(tǒng)透明,操作方便,且安全。
圖6為一個實施例中應(yīng)用程序的加固裝置的結(jié)構(gòu)框圖。圖6中的應(yīng)用程序的加固裝置為基于應(yīng)用程序的加固方法所構(gòu)建的虛擬裝置,其所構(gòu)建的功能模塊不限于此處描述的劃分,還可有其他劃分方式,功能模塊的功能描述不詳細(xì)之處可參照應(yīng)用程序的加固方法中描述。如圖6所示,一種應(yīng)用程序的加固裝置,包括掃描模塊610、加密模塊620和添加模塊630。
掃描模塊610用于靜態(tài)掃描應(yīng)用程序安裝包,獲取待加密的資源文件。
具體地,一個APK(應(yīng)用程序安裝包)安裝包是一個ZIP格式的壓縮文件,里面包含了一款移動APP(應(yīng)用程序)里的所需的代碼、圖片、布局、聲音、動畫、字符串、XML(Extensible Markup Language,可擴(kuò)展標(biāo)記語言)文件、配置文件、資源索引文件及其它二進(jìn)制數(shù)據(jù)。其中,圖片、布局、聲音、動畫、字符串、XML文件及其它二進(jìn)制數(shù)據(jù)屬于APP的資源。它們以文件的形式保存在APK文件的assets、res目錄中,res目錄存儲圖片、布局、聲音、動畫、字符串、XML文件,assets目錄存儲其它二進(jìn)制數(shù)據(jù)文件,布局文件是指存儲在res/layout或者res/layout-xxx(xxx表示任何字符)中AXML文件(XML文件經(jīng)過aidl編譯生成的一種二進(jìn)制文件),用來描述APP界面中各種控件的擺放位置及屬性。
進(jìn)一步的,掃描模塊610還用于靜態(tài)掃描應(yīng)用程序安裝包,預(yù)判只在應(yīng)用 程序安裝包的用戶進(jìn)程中加載的資源文件作為待加密的資源文件。
進(jìn)一步的,掃描模塊610還用于讀取資源文件的索引文件,獲取每個資源文件對應(yīng)的資源文件標(biāo)識,并獲取資源文件標(biāo)識對應(yīng)的資源文件保存在待加密資源列表中,再掃描配置文件,獲取配置文件中引用到的資源文件標(biāo)識,并獲取引用到的資源文件標(biāo)識對應(yīng)的資源文件名稱,加入到第一排除列表;以及掃描代碼文件,獲取調(diào)用了預(yù)設(shè)應(yīng)用程序接口的資源文件標(biāo)識,并獲取該資源文件標(biāo)識對應(yīng)的資源文件名稱,加入到第二排除列表;并將待加密資源列表中的資源文件減去第一排除列表和第二排除列表中的資源文件,剩余的資源文件作為待加密資源文件。
此外,還可從剩余的資源文件中篩選出圖片、布局資源作為待加密資源文件。
加密模塊620用于對該待加密的資源文件進(jìn)行加密,生成包含資源文件密文的應(yīng)用程序安裝包。
具體地,根據(jù)安全需求,獲取一對公鑰和私鑰,使用私鑰對該待加密的資源文件進(jìn)行加密,將加密后的資源文件打包進(jìn)應(yīng)用程序安裝包中,生成包含資源文件密文的應(yīng)用程序安裝包,并將公鑰與待加密資源列表作為資源文件打包進(jìn)包含資源文件密文的應(yīng)用程序安裝包。
添加模塊630用于向該包含資源文件密文的應(yīng)用程序安裝包添加解密模塊,生成包含該解密模塊和資源文件密文的應(yīng)用程序安裝包。
具體地,解密模塊可為so解密模塊,即內(nèi)嵌在移動APP里的透明解密模塊,它是由native語言開發(fā)的一個so文件。將so解密模塊嵌入到應(yīng)用程序安裝包,具體包括:將so解密模塊以資源文件的形式打包進(jìn)Assets目錄,生成包含解密模塊的應(yīng)用程序安裝包。
Assets目錄用于向移動APP提供二進(jìn)制的文件存儲能力。將so解密模塊的arm版本與x86版本一起以資源文件的形式保存在Assets目錄中。
將so解密模塊以資源文件的形式打包進(jìn)Assets目錄中,生成包含解密模塊的應(yīng)用程序安裝包的過程包括:
(1)掃描配置文件,獲取入口方法。
在AndroidManifest.xml文件中,描述有application結(jié)點(diǎn)、activity結(jié)點(diǎn)、service結(jié)點(diǎn)。每個結(jié)點(diǎn)都有若干屬性,其中,android:name屬性用于描述該結(jié)點(diǎn)對應(yīng)組件所在的類,android:process屬性用于描述該結(jié)點(diǎn)對應(yīng)組件所在的進(jìn)程程,結(jié)點(diǎn)下面又會有子結(jié)點(diǎn)、孫子結(jié)點(diǎn)。當(dāng)application結(jié)點(diǎn)包含android:name,將該組件所在的類添加到入口類集合,否則包含孫子結(jié)點(diǎn)<actionandroid:name="android.intent.action.MAIN"/>的activity組件所在的類添加到入口類集合;當(dāng)service結(jié)點(diǎn)包含android:process屬性時,將該組件所在的類添加到入口類集合。
將入口類集合的onCreate方法定為入口方法集合。
(2)在該入口方法中插入釋放so解密模塊,并加載so解密模塊。
具體地,修改classes.dex文件中描述入口方法的代碼指令,添加以下邏輯:釋放so解密模塊至APP目錄;加載釋放出來的so解密模塊。
(3)調(diào)整該入口方法的寄存器。
由于入口方法的寄存器數(shù)量可能不足以執(zhí)行新增的代碼指令,所以需要進(jìn)行調(diào)整,同時還要修改原本代碼里的try和handler的指令偏移,使入口方法的原功能不受影響。
修改完dex文件后重新寫入classes.dex的校驗值,然后打包到包括解密模塊的第一應(yīng)用程序安裝包,生成包括解密模塊的第二應(yīng)用程序安裝包,輸出為經(jīng)加固的應(yīng)用程序安裝包。
上述應(yīng)用程序的加固裝置,通過掃描應(yīng)用程序安裝包,獲取待加密的資源文件,并對待加密的資源文件進(jìn)行加密,并將解密模塊添加到包含資源文件密文的應(yīng)用程序安裝包中,當(dāng)系統(tǒng)運(yùn)行應(yīng)用程序時,使用解密模塊對資源文件密文進(jìn)行解密成資源文件明文,確保應(yīng)用程序的正常執(zhí)行,當(dāng)使用破解工具從應(yīng)用程序安裝包里提取資源文件時,獲取到的是資源文件密文,使得資源文件不被竊取及修改,提高了應(yīng)用程序的安全性,防止用戶數(shù)據(jù)被竊取。
圖7為另一個實施例中應(yīng)用程序的加固裝置的結(jié)構(gòu)框圖。如圖7所示,一種應(yīng)用程序的加固裝置,包括掃描模塊610、加密模塊620和添加模塊630,還包 括安裝模塊640、加載及掛鉤模塊650、請求獲取模塊660、明文獲取模塊670、對象偽造模塊680、替換模塊690、返回模塊692、銷毀模塊694。
安裝模塊640用于安裝該包含解密模塊和資源文件密文的應(yīng)用程序安裝包。
具體地,將加固后的APK安裝包傳給開發(fā)者用戶,開發(fā)者用戶使用自己的證書對該APK安裝包進(jìn)行簽名,生成待發(fā)布的APK安裝包,將待發(fā)布的APK安裝包,上傳到應(yīng)用市場或其他發(fā)布途徑,作為已發(fā)布APK安裝包。用戶通過各種可獲取到APK,安裝至移動終端上。該移動終端可為手機(jī)、平板電腦、個人數(shù)字助理等。
加載及掛鉤模塊650用于在運(yùn)行所述應(yīng)用程序安裝包時,加載該解密模塊,并掛鉤系統(tǒng)函數(shù),得到掛鉤回調(diào)函數(shù),并通過該解密模塊透明解密該資源文件密文為資源文件明文。
具體地,運(yùn)行經(jīng)加固的APP,加載so解密模塊會在APP的功能代碼之前先執(zhí)行,將so解密模塊從assets目錄釋放到APP目錄,然后加載該so解密模塊。
So解密模塊首先會掛鉤系統(tǒng)代碼里的AssetManager類的open、openNonAsset函數(shù),這兩個函數(shù)在系統(tǒng)每次訪問資源文件的過程中都會被調(diào)用,函數(shù)open經(jīng)過C++編譯器的編譯后得到的符號名為:
_ZN7android12AssetManager4openEPKcNS_5Asset10AccessModeE;
方法openNonAsset有兩個多態(tài)實現(xiàn),經(jīng)編譯后,其符號名為:
_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeE;
_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeE
對于Android 5.0及以后的系統(tǒng),方法openNonAsset的導(dǎo)出符號為:
_ZN7android12AssetManager12openNonAssetEPvPKcNS_5Asset10AccessModeE;
_ZN7android12AssetManager12openNonAssetEiPKcNS_5Asset10AccessModeE。
系統(tǒng)會把資源文件的全路徑轉(zhuǎn)給open、openNonAsset函數(shù),這兩個函數(shù), 再從APK安裝包里,讀取該路徑指向的資源文件密文,將其構(gòu)造成第一類數(shù)據(jù)的對象,即_FileAsset類的對象,并最終返回指向該對象的Asset類指針。Asset類是_FileAsset的父類,系統(tǒng)上層不識別_FileAsset類,只通過Asset類的指針去訪問一個資源文件。
So解密模塊掛鉤系統(tǒng)函數(shù)得到掛鉤回調(diào)函數(shù)。具體地,So解密模塊默認(rèn)使用Got Hook進(jìn)行掛鉤,掛鉤的是libandroid_runtime.so模塊里的got表,部分移動的rom經(jīng)過修改,libandroid_runtime.so模塊,以致該掛鉤方式失敗,則使用Inline Hook進(jìn)行掛鉤,掛鉤模塊是libutils.so(android 4.0及以下版本)或libandroidfw.so(android 4.1及以上版本),掛鉤了open、openNonAsset函數(shù)后,系統(tǒng)上層再調(diào)用這些函數(shù),就會轉(zhuǎn)到so解密模塊的掛鉤回調(diào)函數(shù)hook_open、hook_openNonAsset,同時保存掛鉤前的原函數(shù)original_open、original_openNonAsset。隨后,so解密模塊就開始等待系統(tǒng)上層調(diào)用open、openNonAsset函數(shù)。
該掛鉤系統(tǒng)函數(shù)包括以下符號:
"_ZN7android12AssetManager4openEPKcNS_5Asset10AccessModeE";
"_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeE";
"_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeEPi";
"_ZN7android12AssetManager12openNonAssetEPvPKcNS_5Asset10AccessModeE";
"_ZN7android12AssetManager12openNonAssetEiPKcNS_5Asset10AccessModeE"。
請求獲取模塊660用于獲取資源文件訪問請求。
具體地,當(dāng)移動APP需要使用某些資源文件時,則產(chǎn)生獲取資源文件訪問請求。
明文獲取模塊670用于根據(jù)該訪問請求中所指向的第一類數(shù)據(jù),獲取資源文件密文,解密該資源文件密文得到資源文件明文,并將該資源文件明文保存 為第二類數(shù)據(jù)。
對象偽造模塊680用于偽造用于訪問第二類數(shù)據(jù)的對象。
具體地,該偽造用于訪問第二類數(shù)據(jù)的對象,該第二類數(shù)據(jù)的對象滿足以下條件:
繼承于系統(tǒng)的Asset類或Asset類的子類;
重載Asset類的所有方法,將所有對第一類數(shù)據(jù)的訪問重定向為對第二類數(shù)據(jù)的訪問;
重載Asset類的openFileDescriptor方法,將第二類數(shù)據(jù)保存為文件系統(tǒng)中的第三類數(shù)據(jù),再返回該第三類數(shù)據(jù)的文件描述符。
替換模塊690用于在掛鉤回調(diào)函數(shù)中,用該偽造的第二類數(shù)據(jù)的對象替換第一類數(shù)據(jù)的對象。
返回模塊692用于將該第二類數(shù)據(jù)的對象表示的資源文件明文作為訪問結(jié)果返回。
具體地,采用第二類數(shù)據(jù)(代表資源文件明文)的對象(_HookAsset對象)替換第一類數(shù)據(jù)(代表資源文件密文)的對象(_FileAsset對象),將第二類數(shù)據(jù)的對象表示的資源文件明文數(shù)據(jù)作為訪問結(jié)果返回。
銷毀模塊694用于在資源使用結(jié)束后,銷毀第二類數(shù)據(jù)的對象。
銷毀第二數(shù)據(jù)的對象可防止其被破解工具提取,提高數(shù)據(jù)的安全性。同時,節(jié)省存儲空間。
本領(lǐng)域普通技術(shù)人員可以理解實現(xiàn)上述實施例方法中的全部或部分流程,是可以通過計算機(jī)程序來指令相關(guān)的硬件來完成,所述的程序可存儲于一非易失性計算機(jī)可讀取存儲介質(zhì)中,該程序在執(zhí)行時,可包括如上述各方法的實施例的流程。其中,所述的存儲介質(zhì)可為磁碟、光盤、只讀存儲記憶體(Read-OnlyMemory,ROM)等。
以上所述實施例僅表達(dá)了本發(fā)明的幾種實施方式,其描述較為具體和詳細(xì),但并不能因此而理解為對本發(fā)明專利范圍的限制。應(yīng)當(dāng)指出的是,對于本領(lǐng)域的普通技術(shù)人員來說,在不脫離本發(fā)明構(gòu)思的前提下,還可以做出若干變形和改進(jìn),這些都屬于本發(fā)明的保護(hù)范圍。因此,本發(fā)明專利的保護(hù)范圍應(yīng)以所附 權(quán)利要求為準(zhǔn)。