1. 程式人生 > 實用技巧 >14. 使用IDA進行動態除錯與過反除錯(下)(三)

14. 使用IDA進行動態除錯與過反除錯(下)(三)

《使用IDA進行動態除錯與過反除錯(上)(三)》上篇講了使用IDA對so檔案的動態除錯,與幾種反除錯的檢測

本篇接上篇主要是使用IDA通過動態patch來繞過除錯檢測

仍然使用上篇中的反除錯檢測的apk檔案

IDA動態除錯 .init_array

1. 找到 .ini_array 段裡面的函式 thread_function ,並在其第一條ARM指令上面按F2下斷點

2.在 JNI_OnLoad 函式呼叫的 SearchObjProcess 處下斷點(c程式碼視窗和彙編指令視窗快速轉換按Tab鍵)

3.在動態註冊的函式 checkport()第一條指令下斷點

4. 下面開始動態除錯,但一般當我們使用IDA進行attach的時候,.init_array

JNI_Onload()早已經執行完畢了,根本來不急除錯。這時候我們可以使用jdb這個工具來解決,這個工具是安裝完jdk以後自帶的,可以在jdk的bin目錄下找到。

依舊是先執行 android_server

埠轉發

因為要除錯 .init_array,所以需要在程式剛啟動的時候進行除錯,啟動程式

adb shell am start -D -n demo2.jni.com.myapplication/.MainActivity

此時要除錯的app已經掛起 "Waiting For Debugger"

開啟DDMS,檢視執行的app埠資訊

附加程序

Debugger --> Process Options

Debugger --> Attach to Process

F9執行程式,在IDA等待的時候用jdb將app恢復執行,8618是剛才DDMS上面的那個埠號

jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8618

點選完same後程序會斷在一個點,不要理會,直接F9(如果彈出框都點Yes) 直到程式斷在了我們的斷點處 並將函式第二條ARM指令改成POP讓函式不執行直接出棧,或者把下面呼叫exit對應的HEX改成00 00 00 00都是可以的。

IDA繼續F9讓程式執行起來直到程式斷在我們下的第二個斷點處,ARM指令BL是呼叫函式的意思,所以將其指令對應的HEX改成00 00 00 00,無意義的指令 直接patch掉達到讓其不呼叫的目的

IDA繼續F9,這時會來到我們下的第三處斷點,注意這裡是動態註冊的函式,對於動態註冊的函式我們就不能通過把第二條ARM指令改成POP直接出棧,否則程式會崩潰,那這裡怎麼改呢?這裡可以直接把呼叫exit退出對應的HEX改成00 00 00 00來過掉。

到此這三處反除錯就都過掉了,現在F9執行遇見彈框都點確定,然後程式彈框 恭喜你挑戰成功!

案例AliCrackme分析

這個Crackme案例是之前阿里安全挑戰賽的第二題,先將apk拖入Jadx反編譯分析

解壓apk包,提取裡面的libcrackme.so檔案,使用IDA靜態分析

直接在 Functions window找到 securityCheck() 方法,F5直接反編譯成偽C程式碼,進行程式碼優化

雙擊進入v6內嵌的字串

可以看到字串 "wojiushidaan",輸出發現校驗錯誤,說明程式在執行時肯定對其進行了處理。那麼接下來就對so進行動態除錯。

這裡還是以前的方法,啟動android_server,轉發埠,attach程序

這裡要說一下為什麼動態除錯,attach完程序後,IDA總會停在 libc.so 這個地址

因為android系統中libc是c層中最基本的函式庫,libc中封裝了io、檔案、socket等基本系統呼叫。

所有上層的呼叫都需要經過libc封裝層。所以libc.so是最基本的,所以會斷在這裡,而且我們還需要知道一些常用的系統so,比如linker:

這個linker是用於載入so檔案的模組,所以後面我們在分析如何在.init_array處下斷點

還有一個就是libdvm.so檔案,他包含了DVM中所有的底層載入dex的一些方法,在後面動態除錯需要dump出加密之後的dex檔案,就需要除錯這個so檔案了。

在要除錯的方法的第一行下斷點

這個下斷點的地方動態除錯可以直接通過so檔案對應的相關方法找到,在程式碼第一行下斷點

靜態除錯可以通過 相對地址(native函式) + 基地址(so檔案)得到絕對地址,像這個地方

在開啟一個IDA進行關聯除錯

Ctrl + s 找到so檔案對應的基地址

這樣絕對地址 = B4402000 + 11A8 = B44031A8

使用G鍵直接跳到這個地址,下好斷點,再按F9執行,但是程式並沒有斷下來,反而直接退出了

因此這裡肯定是做了反除錯檢測。

基本原理是IDA是使用android_server在root環境下注入到被除錯的程序中,那麼這裡用到一個技術就是Linux中的ptrace,trace一個正在執行的程序稱為程序附加(attach),使用的是ptrace函式的PTRACE_ATTACH引數,當一個程序成功附加到一個正在執行的程序時,此程序會成為被附加程序的父程序,同時向被附加的程序傳送一個SIGSTOP訊號,讓其停止,這時我們就可以對其進行操縱。當我們完成對tracee的操作後就可以使用ptrace的PTRACE_DETACH引數停止附加。那麼Android中如果一個程序被另外一個程序ptrace了之後,在他的status檔案中有一個欄位:TracerPid 可以標識是被哪個程序trace了,我們可以使用命令檢視我們的被除錯的進行資訊:

status檔案在:/proc/[pid]/status

這裡的程序被 2828 程序 trace了,用ps命令看看2828是哪個程序:

果然是android_server程序,程式在底層做了一個迴圈檢測這個欄位如果不為0,那麼代表自己程序在被人trace,那麼就直接停止退出程式。

如何找到這個反除錯檢測的位置並嘗試繞過?

因為 .init_array 是一個so最先載入的一個段資訊,時機最早,現在一般so解密操作都是在這裡做的;

JNI_OnLoad是so被 System.loadLibrary呼叫的時候執行的,它的時機早於native方法的執行。

那麼知道了這兩個時機,下面我們先來看看是不是在JNI_OnLoad函式中做的策略,所以我們需要先動態除錯JNI_OnLoad函式。

接下來就嘗試斷在 JNI_OnLoad 函式指令處,首先在IDA除錯選項中做如下設定:

要讓程式斷在載入庫檔案時就掛起

但是由於被除錯程式一執行就會執行 static 中的語句,因此需要讓程式停在載入so檔案之前,這裡可以新增 wati For Debugger,或者使用更加簡單的方法,使用debug方式來啟動:

adb shell am start -D -n com.yaotong.crackme/.MainActivity

執行完,裝置是處於一個等待除錯的狀態:

接下來在IDA中進行程序的 attach ,但是此時發現沒有RX許可權的so檔案

說明so並沒有被載入到記憶體中去,因為現在的程式是 Wait For Debugger,也就是還沒有走System.loadLibrary方法,so檔案當然沒有載入到記憶體中,那麼就需要讓程式跑起來。

一定要在IDA除錯選項中(Debugger -> Debugger options)做如下設定:

然後點選IDA的執行按鈕,或者F9

這一步需要開啟DDMS來預設埠轉發(當前正在轉發埠8600的資訊到8700的靜態除錯埠)

或者使用

ps | grep com.yaotong.crackme

然後埠轉發

adb forward tcp:8700 jdwp:14522

然後使用如下命令讓程式跑起來:

jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700

但是出現如下錯誤

出現這種問題大多數是被除錯的程式不可除錯,可以檢視apk的android:debuggable屬性,如何沒有這個屬性預設為 false,所以這裡需要新增這個屬性為 true 再進行回編譯:

打包重新安裝

按照上面的步驟繼續

當jdb執行成功後,程式介面便會結束waiting,同時IDA上成功載入程式後,便會進入到linker模組:

這時候,說明so已經載入進來了,因為這次要除錯的是JnI_OnLoad函式,所以需要獲取JNI_OnLoad函式的絕對地址

雙開IDA,拖入libcrackme.so,靜態分析得到JNI_Onload函式的相對地址

Ctrl + s 找到libcrackme.so的基地址

這樣就可以得到絕對地址 =11A8 + B4401000 = B4402B9C

使用G鍵jump到函式開始執行的位置

在這個地方下斷點,再次點選執行(F9),可以看到程式斷在JNI_OnLoad處的斷點

下面使用F8開始單步除錯了,發現每次到達BLX R7這條指令執行完之後,JNI_OnLoad函式就退出了,這個地方存在問題,可能就是反除錯的地方了。。

我們再次進入除錯,看見BLX跳轉的地方R7暫存器中是 pthread_create 函式,這個函式我們在《使用IDA進行動態除錯與過反除錯(上)(三)》就已經介紹過。

程式的反除錯就在這裡開啟一個執行緒進行輪訓操作,去讀取 /proc/[pid]/status 檔案中的 TrackerPid 欄位值,如果發現不為0,就表示有人在除錯本應用,在JNI_OnLoad中直接退出。

問題找到了,現在問題是怎麼繞過反除錯檢測

可以把 BLX R7 這條指令給nop掉,也就是把這條指令變成空指令(相當於刪除這條指令)這樣apk就不會新建執行緒去執行檢測程式碼了。

雙卡IDA靜態分析libcrackme.so,在JNI_Onload()函式定位到 BLX R7

然後在hex視窗直接把BLX R7這條指令對應的hex改成00 00 00 00.

可以看到修改過後的指令變成 :

儲存修改過後的so檔案

替換原來的so檔案,再次重新編譯簽名安裝,再次按照之前的邏輯給主要的加密函式下斷點,這裡不需要在給JNI_OnLoad函式下斷點了,因為我們已經修改了反除錯功能了,所以這裡我們只需要在securityCheck() 函式處下斷點即可

可以看到順利斷到了securityCheck() 函式開始的地方,說明我們修改反除錯指令成功了。接下來使用 F8 一步步除錯

發現儲存的字串為 "aiyou,bucuoo",輸入這個密碼:

破解成功

參考連結:

  《adb jdb除錯相關》

  《Android IDA So的動態除錯大法》

  《Android逆向之旅---動態方式破解apk進階篇(IDA除錯so原始碼)》

  《IDA除錯Android native(Crackme)》

  《IDA動態除錯so原始碼》