Android IDA So的動態除錯大法
今天已是國慶的第五天,白天去武館訓練過後,晚上回來品一杯西湖龍井,更一篇部落格,一來幫助需要之人,二來加深自己的理解。
下面就說關於在IDA中Android so的動態除錯的問題以及在so的三個層次下斷點的操作。
問題篇:
1.動態除錯的作用以及與我們常說的脫殼區別之處?
2.IDA的下斷點除錯的原理?
3.有無反除錯的步驟區別?以及原理?
4.反除錯與反附加的區別?
5.IDA動態除錯so時有哪三個層次?以及如何下斷點?
注意:so的動態除錯與脫殼在步驟上有很多的相似之處,關於脫殼在後面會詳細介紹加殼以及脫殼的發展歷程。
解答原理篇:
第一個問題:
曰:動態除錯作用有二:
其一:dump記憶體,即:找準時機dump出解密後的正確檔案;
其二:檢視每一步狀態,進一步分析出正確的邏輯;
脫殼只是我們在除錯系統級別的.so檔案後,找準時機dump出正確而真實的.so檔案,而動態除錯只不過是手動脫殼的一種表現方式。
第二個問題:
曰:(由於師哥說面試時喜歡問,此處列出來)
下斷點原理:
由於下斷點有硬體斷點和軟體斷點,我們在這裡只說IDA中的軟體斷點原理:
X86系列處理器提供了一條專門用來支援除錯的指令,即INT 3,這條指令的目的就是使CPU中斷(break)到偵錯程式,以供除錯者對執行現場進行各種分析。
當我們在IDA中對程式碼的某一行設定斷點時,即:F2,偵錯程式會先把這裡的本來指令的第一個位元組儲存起來,然後寫入一條INT 3指令,因為INT 3指令的機器碼為11001100b(0xCC)當執行到這的時候CPU會捕獲一條異常,轉去處理異常,CPU會保留上上下文環境,然後中斷到偵錯程式,大多數偵錯程式的做法是在被除錯程式中斷到偵錯程式時,會先將所有斷點位置被替換為INT 3的指令恢復成原來的指令,然後再把控制權交給使用者。這樣我們就可以愉快的開始除錯了。如下圖所示也是寫偵錯程式的原理圖:
第三個問題:
曰:先說無反除錯:
1.adb push d:\android_server(IDA的dbgsrv目錄下) /data/local/tmp/android_server(這個目錄其實可以隨便放,有的反除錯會檢測這)
2.adb shell
3.su(一定要有root許可權)
4.cd /data/local/tmp
5.chmod 777 android_server(執行許可權要給)
6.再開一個cmd
adb forward tcp:23946 tcp:23946(埠轉發,除錯手機上的某個程序要有協議支援通訊)
7.開啟待除錯的應用程式,就可以愉快的除錯了
再來說有反除錯:
曰
這時候我們就要改變除錯戰略了
在上文的基礎上:
1.啟動android_server;
2.埠轉發adb forward tcp:23946 tcp:23946;
3.adb shell am start -D -n 包名/類名;
(說明:以啟動模式啟動,是停在載入so檔案之前,報名在AndroidMainfest檔案中可以找到)
4.開啟IDA,附加上對應的程序之後,設定IDA中的load so的時機,在debug options中設定一下,後面會有實戰部分;
5.adb forward tcp:8700 jdwp:程序號;(jdwp是後面jdb偵錯程式的協議,轉換到待除錯的指定的應用程式);
6.jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=8700(jdb進行附加);
7.可以愉快的下斷點,開始除錯了;
第四個問題:
曰:反除錯就是阻止你進行動態除錯所採用的一種手段,在下一篇中會進行具體的講解反除錯的手段,以及解決反除錯的辦法。
反附加,在這塊重要的是說jdb的反附加,很多情況下jdb會附加不上,就是會出現“無法附加到目標的VM”這樣的問題那是因為在每個應用程式下,有這個android:debuggable="true"才能除錯,因為篇幅問題,照樣會在下一篇中會針對反附加尋找目前所有解決辦法。
第五個問題:
曰:我們知道在so的載入時候有個這個過程:
.init->->.init array->->JNI_Onload->->java_com_XXX;
還有我們在脫殼的過程中會在一些系統級的.so中下斷點比如:fopen,fget,dvmdexfileopen,等等
而.init以及.init_array一般會作為殼的入口地方,那我們索性叫它外殼級的.so檔案
這裡歸納為三類:
應用級別的:java_com_XXX;
外殼級別的:JNI_Onload,.init,.init_array;
系統級別的:fopen,fget,dvmdexfileopen;
對於在應用級別的和系統級別的就不說了比較簡單容易理解,這裡也是在實現篇中會重點說的,看到上面的.so的載入執行過程我們知道如果說反除錯放在外殼級別的.so檔案的話我們就會遇程式在應用級核心函式一下斷點就退出的尷尬,事實上多數的反除錯會放在這,那麼過反除錯就必須要在這些地方下斷點,那麼我們就重點的說如何在.init_array和JNI_Onload處理下斷點。
實現篇:
這裡我們會拿阿里有一年的比賽樣本,會放在附件中。
在JNI_Onload處下斷點方法一:(雙開定位)
1.啟動android_server;
2.埠轉發以及除錯模式啟動:如圖所示:
3.開啟IDA,設定
4.附加上對應的程序進去之後如圖:
5.這一步很重要在Debugger option下面選擇這三個選項(讓在load so的每個介面處停下來)
6.jdwp協議埠轉發
7.jdb附加
8.F9執行,忽略提示框;這時候執行到linker處,如圖:
9.這時候找JNI_Onload的絕對地址:
基地址+相對地址;
基地址為:ctrl+s顯示為:
相對地址,用IDA靜態分析libcrack.so可得到相對地止:
絕對地址為:4151E000+1B9C=4151FB9C
按下“G”鍵輸入4151FB9C
如圖所示:按下F2下好斷點,再按F9執行到斷點處就可以愉快的除錯了
在JNI_Onload處下斷點方法二:(簡單好用)
1.首先把要分析的libcrackme.so檔案拉進IDA裡面在要下斷點的JNI_Onload處下好斷點如圖所示:
2.啟動android_server與上面一樣;
3.埠轉發以及除錯模式啟動:如圖所示
4.先設定一下Debugger 如圖所示
5.IDA進行附加程序回到之前靜態分析libcrackme.so的IDA介面單擊Debugger -> Process options 配置除錯資訊,這裡只需配置hostname為localhost,其餘的保持預設設定即可
6.單擊Debugger -> Attach to process進行附加程序
7.jdwp轉發(當然開啟DDMS就不需要這一步了)jdb附加
8.F9執行一路取消就OK,得到如圖所示:
是不是很簡單??
在.iniy_array處下斷點(與上面方法二雷同)
得到的結果是:
OK,搞定
在JNI_Onload處下斷點方法三:(適合於脫殼的時候)
1.可以根據看原始碼,對應不同版本的系統原始碼就會發現一點,如下在vm/Native.cpp路徑下:
2.我們逆向去看,首先把系統中的libdvm.so a db pull出來,拉到IDA中去分析;
找到JNI_Onload處進行分析:F5可以看到,首先V20進行“JNI_Onload”符號查詢,同時在V23有對V20的呼叫,
回到ARM指令處可以看到如下:
0x50008就是偏移處,這個時候我們就開始下斷:
載入上要除錯的APK以後,找到libdvm.so的基址,然後加上50008,下斷點。如果看不到彙編,那就P一下,下斷點,這個比較適合於脫殼的時候。