安全動(dòng)態(tài)

Android應(yīng)用存儲(chǔ)安全與加固

來(lái)源:聚銘網(wǎng)絡(luò)    發(fā)布時(shí)間:2016-07-13    瀏覽次數(shù):
 

信息來(lái)源:比特網(wǎng) 

       

       目前移動(dòng)領(lǐng)域已經(jīng)出現(xiàn)了相當(dāng)部分的安全問(wèn)題,新的惡意軟件層出不窮,另一方面,企業(yè)對(duì)敏感數(shù)據(jù)保密性意識(shí)日益提高,作為移動(dòng)開發(fā)者,有責(zé)任對(duì)最終用戶的隱私和安全承擔(dān)更多責(zé)任。

本文主要討論移動(dòng)安全存儲(chǔ)策略,設(shè)計(jì)了安全加固方案,實(shí)現(xiàn)了移動(dòng)應(yīng)用逆向分析、安全代碼自動(dòng)注入等全流程的一鍵式加固工具,并進(jìn)行了驗(yàn)證。

1.移動(dòng)數(shù)據(jù)存儲(chǔ)

Android平臺(tái)實(shí)現(xiàn)數(shù)據(jù)存儲(chǔ)的5種基本方式:

數(shù)據(jù)共享(SharedPreferences)

--內(nèi)部存儲(chǔ)(File)

--SQLite數(shù)據(jù)庫(kù)存儲(chǔ)

--外部存儲(chǔ)

--網(wǎng)絡(luò)存儲(chǔ)

本文主要討論前三種數(shù)據(jù)存儲(chǔ)類型,實(shí)現(xiàn)了加密解密SDK,并實(shí)現(xiàn)對(duì)APP的安全存儲(chǔ)注入。首先我們來(lái)簡(jiǎn)單討論下Android中數(shù)據(jù)存儲(chǔ)的位置——考慮數(shù)據(jù)安全,有必要更改android應(yīng)用的存儲(chǔ)位置嗎?

在非root設(shè)備上,數(shù)據(jù)已可通過(guò)沙盒得到很好地安全保護(hù)(當(dāng)然,我們也不可以完全忽略設(shè)備存在內(nèi)核漏洞或虛擬機(jī)漏洞時(shí)可能發(fā)生的后果)?!白远x存儲(chǔ)位置”也是一種設(shè)計(jì)方式,使破解者難以確定存儲(chǔ)的路徑,并完全控制了存儲(chǔ)實(shí)現(xiàn),以進(jìn)行加密和解密保護(hù)。但這樣做,失去了Android自身完善的特權(quán)分離機(jī)制(安全沙盒),將數(shù)據(jù)文件完全暴露在沙盒外,弊大于利,實(shí)際上意義不大。

因此這里仍選擇沙盒作為數(shù)據(jù)的存儲(chǔ)位置,接下來(lái)主要討論對(duì)于root的設(shè)備,如何增強(qiáng)數(shù)據(jù)的安全性。在root設(shè)備上,需要通過(guò)數(shù)據(jù)擦除或數(shù)據(jù)加密,實(shí)現(xiàn)數(shù)據(jù)的安全存儲(chǔ),降低數(shù)據(jù)暴露的可能性。

2.加密方案選擇

涉及到了加密,我們需要選擇一種加密算法,加密算法的選擇無(wú)窮無(wú)盡,本文采用AES加密算法,選擇128位秘鑰加密方式。以下是三種存儲(chǔ)類型在AES算法下的具體實(shí)現(xiàn)方式:

SharedPreferences存儲(chǔ)加密解密方式:對(duì)key和value同時(shí)加密,存儲(chǔ)類型都為String類型,數(shù)據(jù)讀取時(shí)根據(jù)需要進(jìn)行類型轉(zhuǎn)換。

File文件存儲(chǔ)加密解密方式:對(duì)數(shù)據(jù)流進(jìn)行加密解密。

SQLite數(shù)據(jù)庫(kù)存儲(chǔ)加密解密方式:基于Sqlcipher進(jìn)行實(shí)現(xiàn)。

3.代碼注入方案設(shè)計(jì)3.1注入方案比較

在”哪里”或者如何將我們提供的SDK注入到已有APP中,以及如何修改此APP中的實(shí)現(xiàn)。這里注入的層面可以是:java字節(jié)碼(.class)或DEX字節(jié)碼(.smali),二者分別對(duì)應(yīng)反編譯和反匯編過(guò)程。這里選擇后者作為注入方案,原因如下:

(1) smali語(yǔ)法定義明確,易于直接替換對(duì)象類型;

(2)在反編譯流程中,更直接。

3.2 DEX字節(jié)碼

Dalvik虛擬機(jī)運(yùn)行Dalvik字節(jié)碼,由java字節(jié)碼轉(zhuǎn)換而來(lái),又稱為” Dalvik匯編語(yǔ)言”,是Dalvik指令集組成的代碼,Dalvik指令集是Dalvik虛擬機(jī)為自己專門設(shè)計(jì)的一套指令集。但嚴(yán)格說(shuō)它不屬于正式語(yǔ)言,它的特點(diǎn)如下:

Dalvik指令在調(diào)用格式上模仿了C語(yǔ)言的調(diào)用約定;

--根據(jù)字節(jié)碼的大小與不同,一些字節(jié)碼添加了名稱后綴以消除歧義;

32位常規(guī)類型的字節(jié)碼未添加任何后綴

64位常規(guī)類型的字節(jié)碼添加-wide后綴

特殊類型的字節(jié)碼根據(jù)具體類型添加后綴,如-boolean、-byte、-char、-void等

--根據(jù)字節(jié)碼的布局與選項(xiàng)不同,一些字節(jié)碼添加了字節(jié)碼后綴以消除歧義,這些后綴通過(guò)在字節(jié)碼主名稱后添加斜杠(/)來(lái)分隔開;

--在指令集的描述中,寬度值中每隔字母表示寬度為4位。

我們來(lái)看一下它對(duì)方法的定義:

invoke-virtual {p0, v2, v3},

Landroid/content/Context;->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;

move-result-object v1

這里調(diào)用了類android.content.Context的getSharedPreferences方法,其中p0寄存器存儲(chǔ)context實(shí)例,方法的參數(shù)是兩個(gè):一個(gè)是java.lang.String類型,一個(gè)是int類型,兩個(gè)參數(shù)分別保存在寄存器v2和v3中,返回值是android.content.SharedPreferences類型,并把返回值保存到v1寄存器中。

Dalvik字節(jié)碼中使用了寄存器保存變量和參數(shù)。我們知道,Java虛擬機(jī)基于棧架構(gòu),程序需頻繁從棧上讀取或?qū)懭霐?shù)據(jù),會(huì)耗費(fèi)CPU(指令分派、內(nèi)存訪問(wèn)次數(shù));Dalvik虛擬機(jī)基于寄存器架構(gòu),數(shù)據(jù)訪問(wèn)通過(guò)寄存器直接傳遞。兩者都為每個(gè)線程維護(hù)一個(gè)PC計(jì)數(shù)器與調(diào)用棧,PC計(jì)數(shù)器以字節(jié)為單位記錄當(dāng)前運(yùn)行位置距離方法開頭的偏移量。不同的是,Java棧記錄Java方法調(diào)用的活動(dòng)記錄,以幀為單位保存線程的運(yùn)行狀態(tài),每調(diào)用一個(gè)方法就會(huì)分配新的棧幀壓入Java棧上,方法返回則彈出并撤銷相應(yīng)的棧幀;而Dalvik棧維護(hù)一份寄存器表。

每個(gè)Dalvik寄存器都是32位,對(duì)于大于這個(gè)長(zhǎng)度的類型,用兩個(gè)相鄰寄存器存儲(chǔ)。寄存器被設(shè)計(jì)為兩種表示方法:v命名法和p命名法。具體請(qǐng)參考相關(guān)資料。

4.加固流程設(shè)計(jì)

App加固總流程如下:

apk反匯編 -> sdk注入 -> Smali文件掃描 -> 代碼修正 -> 正向匯編 -> apk簽名

5.加固流程實(shí)現(xiàn)

這里以SharedPreferences存儲(chǔ)為例,例舉SDK和代碼修正的實(shí)現(xiàn)方式。(其他步驟實(shí)現(xiàn)略)

5.1安全存儲(chǔ)SDK

SDK中提供了針對(duì)SharedPreferences存儲(chǔ)類型的加密解密方式,我們對(duì)外提供了一個(gè)SecureSharedPreferences類,它實(shí)現(xiàn)了android.content.SharedPreferences接口,并實(shí)現(xiàn)了接口所提供的各個(gè)方法,將android.content.SharedPreferences類型實(shí)例作為參數(shù),傳遞給構(gòu)造方法。當(dāng)讀取數(shù)據(jù)時(shí),使用這個(gè)參數(shù)進(jìn)行查詢并返回值,當(dāng)存儲(chǔ)數(shù)據(jù)時(shí),在edit方法處,返回一個(gè)實(shí)現(xiàn)android.content.SharedPreferences.Editor接口的類,進(jìn)行數(shù)據(jù)的添加。

這樣的SDK設(shè)計(jì)使得代碼注入可行,并只需要較少的修正量。

5.2 代碼修正

在調(diào)用SharedPreferences存儲(chǔ)時(shí),某種實(shí)現(xiàn)方式可以是(java代碼):

SharedPreferences sp =context.getSharedPreferences("config", 0);

我們需要將其修正為調(diào)用我們提供的SDK方式來(lái)實(shí)例化sp對(duì)象。DEX字節(jié)碼如下:

invoke-virtual {p0, v2, v3},

Landroid/content/Context;->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;

我們首先將這個(gè)結(jié)果保存到一個(gè)寄存器下,這里可以使用v2或者v3寄存器,它們分別對(duì)應(yīng)兩個(gè)類型的參數(shù):java.lang.String和int,而且之后不會(huì)再對(duì)它們進(jìn)行使用,因而它們是可用的兩個(gè)寄存器。這里我們選擇v3寄存器:

move-result-object v3

接下來(lái)新建一個(gè)SecureSharedPreferences對(duì)象,并將它放到某寄存器下,這個(gè)寄存器需要是java中sp對(duì)象存儲(chǔ)的寄存器,并且用這個(gè)寄存器的值進(jìn)行SharedPreferences方法的調(diào)用,如v1寄存器:

new-instance v1,Lcom/…/SecureSharedPreferences;

繼而需要調(diào)用這個(gè)對(duì)象的構(gòu)造函數(shù),并把之前保存在v3寄存器中的值作為參數(shù)傳遞(SharedPreferences類型):

invoke-direct {v1, v3},

Lcom/…/SecureSharedPreferences;->(Landroid/content/SharedPreferences;)V

這樣就完成了修正過(guò)程。

其他存儲(chǔ)類型以及調(diào)用方式的修正方式與以上類似,這里不再贅述。

6.驗(yàn)證實(shí)踐

這里我們將整個(gè)流程所需的各個(gè)依賴包、庫(kù)文件、各個(gè)工具、代碼修正實(shí)現(xiàn)及我們提供的SDK集成到一起,形成一個(gè)一鍵式的加固工具(bat形式)。以一個(gè)DEMO為例,DEMO中實(shí)現(xiàn)了以上三種存儲(chǔ)方式的數(shù)據(jù)存儲(chǔ)和讀取,其中存儲(chǔ)都以默認(rèn)方式(明文)實(shí)現(xiàn),沒(méi)有進(jìn)行安全加密。

將DEMO APK放到工作目錄下,啟動(dòng)并得到加固后的安全APK(secure_demo.apk),其中demo文件夾為中間過(guò)程產(chǎn)生的數(shù)據(jù)文件。

將它運(yùn)行到一個(gè)root的Android測(cè)試機(jī)上,并使用R.E.Explorer工具查看存儲(chǔ),可見數(shù)據(jù)已經(jīng)過(guò)了加密存儲(chǔ),并能夠正確的解密并獲得原始數(shù)據(jù)。SQLite數(shù)據(jù)庫(kù)對(duì)存儲(chǔ)本身進(jìn)行了加密,因而加密后,通過(guò)工具(android內(nèi)置查看器或SQLite Expert Professional查看工具)已無(wú)法打開db文件。

7.總結(jié)與討論

本文主要討論了Android設(shè)備數(shù)據(jù)存儲(chǔ)安全問(wèn)題,重點(diǎn)關(guān)注于針對(duì)一個(gè)已有的、非安全存儲(chǔ)的移動(dòng)應(yīng)用,如何將其加固為一個(gè)達(dá)到安全存儲(chǔ)結(jié)果的應(yīng)用。

希望各位讀者們批評(píng)指正,并如若有更好的實(shí)踐或心得,及時(shí)交流和討論,十分感謝。最后附加了實(shí)現(xiàn)中幾點(diǎn)細(xì)節(jié)的討論:

(1)ART架構(gòu)

Android Art架構(gòu)和Dalvik架構(gòu)主要區(qū)別在于應(yīng)用的執(zhí)行是否使用即時(shí)編譯器,對(duì)于Art架構(gòu)來(lái)說(shuō),以軟件安裝即時(shí)性為犧牲,完成了代碼編譯,以提高程序運(yùn)行效率,而Dalvik架構(gòu)仍然需要即時(shí)編譯器的輔助。而無(wú)論是哪種架構(gòu),與本文中討論的加固方案應(yīng)該是不發(fā)生沖突的。

(2)AES Seed

AES算法中是目前電子數(shù)據(jù)加密中被廣泛接受的方案,雖然密鑰是隨機(jī)生成的,但仍然需要一個(gè)密鑰種子,而這個(gè)秘鑰種子的安全性也是決定整個(gè)加密算法安全性的關(guān)鍵。在一個(gè)移動(dòng)應(yīng)用中,密鑰種子的生成算法可以以本地代碼方式提供(.so),雖然so文件也不是絕對(duì)不可以被反編譯的,但是相對(duì)的會(huì)提高安全性。此外,谷歌還提出一種基于云存儲(chǔ)的方案:

Google recently announced a cloud-based storagesolution for apps, so you could consider storing the key there. Or its seemsthat getting the key outside the device, like on a server, is better.”

(3)加密效率

AES算法處理過(guò)程復(fù)雜,導(dǎo)致大數(shù)據(jù)文件加密和解密效率不是很高,對(duì)于幾十兆的大文件加密,不是一個(gè)很好的選擇,因而企業(yè)在選擇大數(shù)據(jù)文件作為敏感數(shù)據(jù)保護(hù)目標(biāo)的話,需要對(duì)加密方式另行評(píng)估。


 
 

上一篇:思科安全——企業(yè)安全棋局的“宇宙流”

下一篇:“聚力、賦能” 阿里安全峰會(huì)在京召開 用生態(tài)的觀點(diǎn)做安全