給大家介紹一下反調試匯總的原理及實現(xiàn)方式,以及各種反調試的擴展
反調試匯總:
針對于一些大型apk 反調試不一定是讓你不能調試 -> 讓你得到一個錯誤的結果
逆向某一個算法 傳參 中間會根據(jù)一些數(shù)據(jù)運算 如果檢測到反調試 計算錯誤
1.IDA調試端口檢測
監(jiān)測android_server文件端口信息 默認的23946(5D8A)
更改端口 31927 -> 過掉此反調試
2.調試器進程名檢測
監(jiān)測android_server gdbserver gdb等進程
通過ps命令來監(jiān)測有沒有相應的進程信息 android_server as
更改android_server文件名 -> 過掉反調試
3.父進程名檢測
app應用的進程都是由zygote fork 而來 也包括系統(tǒng)應用
vs遠程調試 用可執(zhí)行文件加載so:父進程名為gdbserver
4.自身進程名檢測
多用于單獨調用so 包括 apk來調用so 可執(zhí)行文件調用so
apk來調用so -> 包名與原apk的包名一致
LoadLibrary()函數(shù)加載so文件 僅有這種情況 除非它是自定義linker加載so文件(360殼)
5.apk線程數(shù)量檢測
比如說:我們寫了一個demo apk 來調用so文件(要調試的apk比較大 環(huán)境比較復雜 調試的時候容易跑蹦)
demo apk線程數(shù)量一般 不是很多计维,相較于原apk
找到檢測點 nop掉
6.apk進程fd文件檢測
類似于apk線程數(shù)量檢測
/proc/pid/fd/文件個數(shù)差異
檢測apk是否以debug模式啟動 即使進行ida調試了 程序的大部分功能依然沒有運行 所以fd文件較正常偏少
找到檢測點 nop掉
7.安卓系統(tǒng)自帶調試檢測函數(shù)
android.os.Debug.isDebuggerConnected()? 當程序被調試時 返回值為 true
根據(jù)全局變量 DebuggerActive來判斷
特征: 在java層 搜索 isDebuggerConnected 函數(shù)名
動態(tài)調試時在libart.so 中 _ZN3art3Dbg15gDebuggerActiveE函數(shù)下斷 讓其函數(shù)值為 0 或者直接在內存窗口
修改全局變量
8.ptrace檢測
IDA gdb 都要附加
一個app只能被附加一次
在自己app中開一個線程 然后附加本應用 如果附加失敗 證明應用被調試
先于別的附加 自己附加自己 那么本應用就不能被附加 從而避免被調試
可以在ptrace函數(shù)做手腳 hook函數(shù) ida動態(tài)調試時打斷點做處理 或者直接干掉反調試
以debug模式啟動
分界線 理論上以上調試都是直接跑蹦 一下有特殊情況
9.函數(shù)hash值檢測
為什么ida中打了斷點 程序會斷在此位置龄章? 軟件斷點 不唯一 int 3 調試異常 bkpt斷點指令
根據(jù)這個原理 來檢測一段指令的hash值時候發(fā)生變化 變化了就說明存在軟件斷點
沒有創(chuàng)建線程 掃了一下 -> 會在調試點直接崩潰
創(chuàng)建線程 循環(huán)比較函數(shù)hash值是否相等 若不等 則kill
可以從 創(chuàng)建線程api出發(fā) 同時吃谣,此調試點肯定在指令被檢測之前運行 之后是不可能的
可以試試 ctrl +f7 即 回溯
10.斷點指令檢測
和上面其實并沒有本質區(qū)別
11.系統(tǒng)源碼修改檢測
tracePid檢測 _ZN3art3Dbg15gDebuggerActiveE函數(shù)
查看 /proc/pid/status 目錄下的 tracePid 是否為0 若為0 則未被調試 若不為0 則被調試
解決辦法:可以修改系統(tǒng)源碼實現(xiàn) tracePid 恒為0 不論是否被調試
動態(tài)調試的反調試檢測點
程序直接掛掉 直接可以nop掉或者fopen函數(shù)下斷 打開/proc/pid/status目錄時 修改內存中 tracePid的值
可以自己附加自己 查看tracePid是否為0 若為0 則修改了系統(tǒng)源碼 kill進程 若不為0 則為修改
12.單步調試陷阱
可以模擬IDA打下斷點,即修改相應指令的二進制 將其改為bkpt指令 需要修改內存也屬性 mprotect()
自己注冊斷點處理函數(shù) 做什么事做裙?
把斷點處指令 恢復成正常的指令 等一些列工作
如果IDA動態(tài)調試走到此斷點處 IDA會正常的處理此斷定指令 但是我們的信號處理函數(shù)已經將此指令處理完畢
IDA做了重復性的工作 -> 程序崩潰
崩潰特點:立即崩潰 程序一般不會被kill 會指令走不動 f8 f9 一直彈信號
借助于IDA調試缺陷來設置的反調試
反調試設置的地方可能不在這個指令崩潰的附近 反調試點不太好找
內聯(lián)匯編 __asm__{}; 有可能在內聯(lián)匯編中做此反調試 反調試設置的地方在其周圍
13.基于信號的檢測
signal() raise() 發(fā)送信號
利用IDA先截獲信號特性的檢測
IDA總是先于我們的應用程序截獲信號
signal(SIGTRAP, myhandler); SIGTRAP:調試信號 myhandler:信號處理函數(shù)(自己實現(xiàn)的)
信號處理函數(shù) 可以設置一個全局變量
終止進程方式可以kill進程 或者 sleep()
先給程序設置signal 并實現(xiàn)信號處理函數(shù)
在關鍵函數(shù)里或者開一個線程 隔時 發(fā)送信號 即 raise()
若信號未收到 則程序被調試
信號 消息機制 被捕獲就會消失 一次性
14.利用IDA解析缺陷反調試
BLX BX 跳轉指令 可切換指令集
X帶指令切換 L帶鏈接
IDA解析 是Thumb指令還是Arm指令時可能出錯 遞歸下降算法來反匯編指令
這種情況多發(fā)生于靜態(tài)分析 動態(tài)調試指令執(zhí)行基本不會出現(xiàn)
__asm __volatile{"","memory"} asm 前綴 從這里開始指令為匯編指令
volatile 會面的匯編指令不要給我優(yōu)化 按我的執(zhí)行
讓IDA 指令識別錯誤 即Arm Thumb指令 錯誤識別類型 -> 導致程序無法正常運行
nop掉
15.時間反調試
gettimeofday() time() 常用
通過獲取兩個時間 來計算出時間間隔 從而確定時候被反調試
如果我們進行調試時 不f8單步 或者不停留 那么這種反調試是無用的
關鍵算法 或者程序比較靠前的地方
在gettimeofday函數(shù)下斷 最近的兩次調用 將其返回值改成一樣的
直接找到反調試設置的地方 然后給nop
time()函數(shù) time_t結構體 clock()函數(shù) clock_t結構體 gettimeofday()函數(shù)
timeval結構 timezone結構 clock_gettime()函數(shù) timespec結構 getrusage()函數(shù) rusage結構
16. Inotify事件監(jiān)控dump
防dump文件
Inotify系列api來監(jiān)控mem或pagemap的打開或訪問事件 自己設置要監(jiān)測的文件
當然岗憋,除此之外 還有別的反調試 比較多的就是這個環(huán)境問題