????????對提供的 CrackmeTest.apk 進行逆向分析,程序含有反調試機制(加殼),通過靜態補丁反反調試(去殼),再動態調試獲取其中密碼。
目錄
環境
基礎
實驗內容
靜態分析
動態分析
反反調試
再動態調試
補充
環境
環境:Windows11,java環境。
工具:IDA_Pro_v7.0 , AndroidKiller_V1.2 , 雷神模擬器,adb工具。
基礎
????????殼目的:反調試、反靜態分析、反篡改、許可證管理。
????????殼種類:壓縮殼、加密殼(防止逆向)
????????當一個Android應用加載一個原生庫System.loadLibrary("crackme")時,Java層調用 System.loadLibrary,然后加載libcrackme.so動態鏈接,Android Native庫加載執行的三個級別如下:
系統級:-> libdl.so ->linker
外殼級:.init ->.init_array -> JNI_OnLoad
應用級:Java_com_xxx函數(SecurityCheck)
? ? ?可在以上位置設置加殼,實驗樣本是加在JNI_OnLoad的簡單保護殼(“弱殼”),外殼級,對JNI_OnLoad下斷點。
? ? ?若 JNI_OnLoad 被加殼,應在以下位置設斷點:
-
.init 、.init_array
-
系統級.so中的初始化函數(例如在libc.so的fopen、strcmp,或者鏈接器的__dl_init函數)
? ? ? ? ?殼保護機制:在?libcrackme.so?的?JNI_OnLoad函數中,通過ptrace進行自我跟蹤檢測。如果發現TracerPid不為0(即程序正在被調試),就立即終止進程。
?????????Android APK 文件結構:
AndroidManifest.xml:應用“身份證”和“權限申請單”
resources.arsc:資源索引表,將所有資源ID映射到具體內容
res:資源目錄,存放具體資源文件
?res/values/strings.xml:保存所有文本字符串
res/values/public.xml:固定資源ID的映射關系
Classes.dex:應用代碼邏輯,由Java編譯成
Lib/ 原生庫目錄:存放.so文件,C/C++編譯的本地庫
實驗內容
靜態分析
-
初始在模擬器中運行程序,隨意輸入密碼顯示驗證碼校驗失敗。
-
使用 AndroidKiller 反編譯 APK,查看AndroidMainfest.xml中的activity類,找到入口Activity(MainActivity),以及在res-values-strings.xml和public.xml搜索成功提示等,未找到字段。
-
使用 jadx-gui 分析 Java 代碼,查看MainActtivity和ResultActivity的java代碼,確定密碼校驗的關鍵函數securityCheck。
-
用IDA靜態分析libcrackme.so文件定位到securityCheck函數,對其分析可知apppwd即加密后off_628C(初始"aWojiushidaan"),與inputpwd即用戶輸入的密碼比較,相等則校驗成功。
- 確定securityCheck偏移地址:0x000011A8,JNI_OnLoad偏移地址00001B9C。
動態分析
-
adb連接模擬器后將android_server上傳后運行失敗,換成android_x86_server后運行成功,開始監聽,并將23946端口轉發。
- ????????模擬器開啟root權限,開啟adb遠程調試權限,在IDA中附加進程com.mytest0.crackme開始遠程調試。
- 搜segement找libcrackme.so發現無可執行的.so文件,modules搜索crackme得到的入口地址:0B244000
-
入口地址加上securityCheck的偏移地址000011A8得到絕對地址: F0B2451A8,搜索絕對地址添加斷點調試。
-
發現屏幕顯示FFFFFFFF,程序有反調試機制,查看ptrace確認TracerPid非零。
反反調試
-
調試模式啟動程序,重新打開IDA調試掛載的程序。
-
libcrackme.so的基地址0B244000+JNI_OnLoad偏移地址00001B9C得到絕對地址0B245B9C,跳轉到這里添加斷點逐步調試。
-
發現到對應相對地址00001C58處退出,BLX R7這個調用最終會執行ptrace檢測,如果發現被調試就退出,靜態調試修改libcrackme.so對應十六進制文件,修改該指令為空指令。
-
將修改后的.so文件替換原來的.so文件,用AndroidKiller重新編譯打包,再次上傳,重新調試。
再動態調試
????????再次掛載程序,IDA附加進程,基地址0B245000(動態鏈接,每次都會變),加上securityCheck函數偏移地址000011A8得到絕對地址0B2451A8添加斷點調試,隨意輸入密碼放入寄存器,一直F8執行,直到0B2451A8處發現R1中存放輸入的密碼,與R3中真正的密碼比較,查看內存中R3寄存器處的對應值得到真實的密碼aiyou,bucuoo。
補充
靜態脫殼(適用于簡單壓縮殼),有些壓縮殼的算法是公開的,可以直接用專門的脫殼工具(如UPX -d)進行解壓,恢復出原始文件,但對加密殼完全無效。
動態脫殼是最主流的方法
- 加載程序(殼開始執行)
- 執行殼的解密代碼(繞過反調試)
- 等待解密完成(定位原始程序的真正入口OEP)
- 抓取內存鏡像(Dump Memory)
- 修復文件(內存鏡像重建輸入表/節區)
- 得到脫殼后的原生程序