天天看點

Android開發的安全性方案

Android 接入sdk是指某公司作為能力提供方經常以接入Sdk形式來暴露能力供使用者使用,這樣的能力對公司來說是财富實作的資本,不能被外界窺探或者破解成免費使用,那下面來分析下有哪些危害以及解決方案。

裸sdk的危害

裸Sdk是指sdk未進行加強,直接簡單的通過反編譯工具就可以看到其實作,現在混淆不算加強,但很多sdk就僅限于混淆而已,就沒有其他安全措施了,這樣就很容易暴露如下問題:

  1. 窺視内部實作方法
  2. 暴露了内部調用流程
  3. 避開流程直接調用關鍵代碼進而破解流程以達到某種目的 

    這種情況很多,如第3方sdk功能存在推廣或者界面不符合咱們使用,這個時候需要繞過其流程,如脫掉界面,直接繞過界面顯示在按鈕點選之後的功能才是我們需要的,這個時候可以檢視其調用的方法,不能顯示調用就直接反射調用。

  4. 洩漏核心技術

Sdk調用入口未鑒權

未鑒權導緻Sdk存在随意被其他未經授權使用者調用的情況,或者用來未經授權的應用使用Sdk,導緻能力未經許可而導緻損失

如何提高安全

1. 關鍵核心功能實作隐藏

java代碼實作代碼很容易被反編譯,轉而用Ndk開發實作生成so動态庫,提高反編譯難度,進一步可以通過加強so檔案加密,進而更難被反編譯檢視。同時要注意的so作為核心庫防到了反編譯時也要注意對方可以直接使用so庫,是以要對jni接口調用進行鑒權判斷,入口調用棧檢測,以及串聯下上下文,盡量避免僅僅是個工具庫,不要太解耦。
 關于如何具體開發Ndk jni代碼可以參考我的另一篇文章:[Android studio下Cmake配置編譯開發jni總結](http://blog.csdn.net/u010019468/article/details/78271965)
           
  • 1
  • 2
  • 3

2. Sdk中Dex和so檔案加密及加殼

Sdk中dex檔案和so檔案加密進而屏蔽外部窺探,提高反編譯難度。并且進一步通過jni本地方法來屏蔽核心方法,在so檔案内解密dex檔案并加載,Sdk暴露的接口全部通過jni來跳轉或者通過反射跳轉到核心dex内實作。其中對so檔案加強可以參考:[對Native層(so檔案)進行加強](http://blog.csdn.net/jiangwei0910410003/article/details/49967375),
           
  • 1
  • 2

對Dex檔案通過各種加密方式然後動态加載方式,可以總結下來有如下方式:

1、直接通過加密dex檔案儲存下來,然後native層解密出檔案并加載,這種被稱為落地式加載,然後被截取到解密後檔案
2、通過圖檔檔案格式隐藏邏輯代碼二進制檔案,然後在native層解析出dex檔案,達到dex檔案隐藏目的
3、采用不落地式加載:解密dex檔案成bytes,直接hook方式利用libdvm.so(低版本的)直接加載位元組碼
4、不僅dex檔案加密,以及加密dex中的指令
5、通過NativeActivity把所有的java層代碼都隐藏起來
           
  • 1
  • 2
  • 3
  • 4
  • 5

so如何實作程式的反調試?

同linux反調試基本原理相同,這裡提供一種方式就是在JNI_Onload中調用ptrace方法,
一個程序隻能被一個程序ptrace,如果你自己調用ptarce,這樣其它程式就無法通過ptrace調試或者 
向您程式程序注入代碼。**重點内容**
           
  • 1
  • 2
  • 3

3. 網絡安全

如果網絡請求不安全,直接被抓包,接口和參數直接被窺探進而被模拟,提高安全的話直接用https,如果條件不允許,那至少得加密傳輸,對參數加密,加密算法必須得so檔案來實作。同時配合服務端做一些防刷,有限性鑒定。同時也要簡單地對抗網絡代理抓包
           
  • 1
  • 2

4. 方法調用棧檢查

對于java調用而言,如果不對調用棧入口檢查,就會出現方法被肆意調用,使用者不受控制的調用幹擾調用流程,如上述直接去掉sdk調用中出現的界面,是以可以直接在某個方法入口處先檢查下此時的調用棧順序是否符合流程的設計,可以檢查下第一個入口,以及後上方的幾個入口是否為設定的流程。

5. 方法入口統一紮口

Java實作方法在sdk,總能通過反射任意調用各個方法,單獨使用某個方法來實作某個功能,是以假如我們經常為了共用功能而經常封裝成單獨方法,這樣就為避開sdk設計的流程而單獨調用提供了機會,這時會有人會說那我把所有的功能用一個方法實作來達到避免流程幹擾,這樣顯示不切實際,那樣的代碼又長又臭,沒有人敢來維護。即使如此,有個工具通過javassit來實作注入代碼進而幹擾代碼執行流程。那到底有沒有好點的辦法來統一紮口呢?個人覺得比較好的方式就是通過Ndk來實作封裝,畢竟jni接口入口可以獨立出來使用,比起java代碼反編難度大,調試難,又不好注入代碼,更難随意調用ndk内部c++實作的相關方法。
 用一個jni入口暴露出來給java層調用,内部封裝整個流程,很好避開大部分破解流程。
           
  • 1
  • 2
  • 3

6. 雲方案

這種方案要是能行的話,覺得是最安全的,絕對避免了核心方法的洩露,這種sdk通過請求調用雲端直接擷取結果,如市場中大多圖像識别sdk都是這樣來做的。

7. 調用鑒權

主要可以分為靜态鑒權和動态鑒權。前者主要是用來檢查固定參數,如appKey和appSecret,以及結合限定應用包名(packageName)和應用名(appName)達非到限定sdk被未經授權而擴散使用。
 動态鑒權就是類似授權令牌一樣由服務端分發token,調用着帶這token來通路接口,這裡面就涉及了多次本服務端和目标服務端多次互動,生成token透傳給使用者,被調用者再次跟服務端互動校驗調用者來源合法性。這種是保護token的生成規則而不在乎是否洩漏使用,即使洩漏,也隻是表面這個合法使用者在使用,而不在乎是模拟的合法使用者,即不會生成出現新的合法調用者。
           
  • 1
  • 2
  • 3

8. 混淆 

1)通過字典來jar混淆 

字元混淆用來對抗反編譯工具,讓字元常量不顯示或着顯示成16進制數組。 

詳細見這邊文章:http://bobao.360.cn/learning/detail/3704.html?spm=a313e.7916648.0.0.11b0b6cqnOKtJ 

字典混淆是指通常混淆字典都是abc…可以通過配置特殊字典,讓反編譯者看得懷疑人生,有常見開源項目示例如下: 

Android開發的安全性方案

開源項目位址: https://github.com/ysrc/AndroidObfuseDictionary 

2)資源res混淆 

對代碼的混淆能夠增加一定的代碼閱讀難度,有時候我們為了防止資源的保護也是可以做混淆的,這個資源混淆原理這裡就不多解釋了,微信團隊已經将這個功能開源,不了解的同學可以轉戰github檢視: 

https://github.com/shwenzhang/AndResGuard 

Android開發的安全性方案

當然資源混淆還有一個很大的好處就是減小apk包的大小,當然這個不是本文讨論的知識點,這裡我們讨論的是混淆資源增加破解查找資源的難度,先來看一下混淆資源之後的結果:

這裡我們可以看到,一個混淆資源的應用,反編譯之後檢視他的string.xml内容,發現他的name全是簡單的混淆字母,那麼這個對于我們之前的那種可以通過name的值,來查找對應的字元串内容來擷取消息,這個将是很蛋疼的一件事,因為你這時候如果全局搜尋一個name值的話,比如這裡的name=’a’,那麼得搜出多少個這樣的name,查找也是很好時間的,其實在沒有混淆之前,一般string中的name都是比較唯一的一種值,查找的話不會有那麼多查找結果,而且查找時間也是很短的。

9.反調試檢測 

摘自《 Android安全防護之旅—Android應用”反調試”操作的幾種方案解析》 

第一、自己附加程序,先占坑,ptrace(PTRACE_TRACEME, 0, 0, 0)! 

第二、簽名校驗不可或缺的一個選擇,本地校驗和服務端校驗雙管齊下! 

第三、借助系統api判斷應用調試狀态和調試屬性,最基礎的防護! 

第四、輪訓檢查android_server調試端口資訊和程序資訊,防護IDA的一種有效方式! 

第五、輪訓檢查自身status中的TracerPid字段值,防止被其他程序附加調試的一種有效方式!

個人思路總結方式: 

1、對于java調用,檢查其調用stack。StackTraceElement來判斷是被繞過執行 

2、結合服務端上傳調用日志,後期延遲判斷是否存在被破解 

3、對調試工具的反調試:如《Android DEX安全攻防戰》

10.更多前沿加密加強技術學習 

加強技術發展與對抗——虛機源碼保護的未來級别方案

技術前沿 | 虛拟機保護技術(VMP)的實踐與體會

Android DEX安全攻防戰 

“暗隐間諜”–利用NDK NativeActivity技術實作Android加強 

Android逆向之旅—Android應用的安全的攻防之戰