Android app反調試與代碼保護的一些基本方案

現創建了一個Android開發水友圈,圈內會不定時更新一些Android中高級的進階資料,歡迎大家帶著技術問題來討論,共同成長進步!(包含資深UI工程師,Android底層開發工程師,Android架構師,原生性能優化及混合優化,flutter專精);希望有技術的大佬加入,水圈內解決的問題越多獲得的權利越大!

有興趣的可以私信我加圈,圈內有部分Android進階資料領,免費的。私信我“資料”即可入圈。

本文介紹Android app代碼(java + ndk)的反調試的方法和保護代碼增加逆向難度的一些基本方法。

Android自問世以來得以迅速發展,各大手機廠商紛紛投入成本開發、設計開發自己的Android系統,從2016年開始,Android已經超越ios成為全球最有影響力的操作系統。針對於Android app的逆向方法和逆向工具很多,所以反調試對於Android的代碼保護扮演著很重要的角色。本文從四個方面介紹一下Android反調試的一些方法。

ps:反調試並不能完全阻止逆向行為,只是在長期的攻防戰中給破解人員不斷的增加逆向難度。

Java:

(1)Proguard

藉助Android studio的proguard工具,對Java代碼分別進行壓縮(Shrink)、優化(Optimize)、混淆(Obfuscate)、檢查(Veirfy)。

壓縮(Shrink):去掉代碼中無用的類、函數方法和字段。

優化(Optimize):對Android的可執行文件dex進行優化,去掉無用指令。

混淆(Obfuscate):用毫無意義的字段對代碼的類名、函數名、變量名重命名,比如用a, b, c這種。

檢查(Veirfy):對混淆後的代碼進行檢查。

經過Proguard後,代碼程序依然可以重新組織和處理,處理後的程序邏輯與之前完全一致,而混淆後的代碼即便反編譯後依然很難閱讀。同時,在混淆過程中對於一些不影響正常運行的信息將永久丟失,這些信息的丟失使得程序更加難以理解。

同時,Proguard還可以控制對某個類混淆,以及對某個類的某些函數方法混淆。

下圖是一張混淆前和混淆後的對比圖:

混淆前:

Android app反調試與代碼保護的一些基本方案

混淆後:

Android app反調試與代碼保護的一些基本方案

(2)isDebuggerConnected

Android Debug類提供isDebuggerConnected函數,函數原型如下:

Android app反調試與代碼保護的一些基本方案

在VMDebug類裡的isDebuggerConnected的具體實現在ndk程序裡。

Android app反調試與代碼保護的一些基本方案

這裡暫且不跟進該函數,總之,isDebuggerConnected函數用於檢測此刻是否有調試器掛載到程序上,如果返回值為true則表示此刻被調試中。用法很簡單,如下:

Android app反調試與代碼保護的一些基本方案

(3)android:debuggable屬性

在Android的AndroidManifest.xml清單文件的application節點下加入android:debuggable="false"屬性,使程序不能被調試。在Java程序代碼裡也可檢測該屬性的值,如下:

Android app反調試與代碼保護的一些基本方案

NDK:

(1)ptrace函數

Linux內核的ptrace函數原型:

Android app反調試與代碼保護的一些基本方案

ptrace可以允許A進程控制B進程,並且A進程可以檢查和修改B進程的內存和寄存器。但是一個進程只能被一個進程調試,所以根據這個特點,可以讓進程自己ptrace自己,傳入的request設置為PTRACE_TRACEME,程序被自己附加調試後,其他的調試操作就會失敗了。

(2)文件節點檢測

一旦程序處於被調試狀態,Linux會向進程的節點寫入數據,比如/proc//status內容中的TracePid會寫入調試進程的pid,如果TracePid的值不為0,就表明進程處於被調試狀態了。

此外,通用的檢測邏輯還有檢測調試的端口號,Linux的文件節點/proc/net/tcp會記錄著正在運行的進程的本地的端口號,調試工具IDA的默認的調試端口是23946,通過讀取/proc/net/tcp內容,檢測是否有23946,如果找到了就表明進程處於被調試狀態了。

(3)Inotify

Linux的Inotify用於檢測文件系統變化。它可以檢測單個文件,也可以檢測整個目錄。

逆向最常做的一件事就是dump 內存,使用dd命令(或者如果使用gdb的話為gcore命令),dump掉/proc/

/mem或/proc//mpas或/proc//pagemap的內容。

這裡,就可以使用Inotify API對上述三個文件監控,如果有發現打開、讀寫操作,極大概率就是進程正在被破解。

(4)so文件hash值檢測

so文件在被JNI_Onload加載後,so文件的函數的指令是固定的,若被調試器掛載,下了斷點後指令會發生改變(斷點地址會被改寫為bkpt指令),計算內存中加載的so的hash值,進行校驗檢測函數是否被修改或被下斷點即可判斷出是否被調試狀態。

(5)時間差檢測

一個取巧的方法,正常情況下,一段程序在兩條代碼之間的時間差是很短的,而對於調試程序來說,單步調試中的程序兩條代碼之間的時間差會比較大,檢測兩條代碼之間的時間差,可以大概率判斷程序是否被調試。

Resource資源文件:

Android資源文件經常被惡意篡改,植入各種廣告,插件,嚴重影響了Android app生態平衡。

APK簽名檢測

Android SDK中有apk 簽名檢測的方法,Framework的PackageManager類提供了getPackageInfo()函數,函數原型:

Android app反調試與代碼保護的一些基本方案

第二個參數傳入GET_SIGNATURES時,返回對象的signature字段就是簽名信息,計算其hash值,前後對比hash值。實際可用的兩種方案:

(1)在本地Java代碼裡進行校驗,不一致則強退應用;

(2)把簽名信息發到服務器後臺,服務器後臺記錄著正確的簽名信息,比對後不一致則返回一個錯誤給錯誤。

上述即為對於Android app的反調試,代碼保護的一些基本策略。


分享到:


相關文章: