動態調試Android程序


最近好幾天來一直在看動態調試。首先是這一篇(http://www.52pojie.cn/forum.php?mod=viewthread&tid=293648)里面介紹了多種IDA動態調試的情形,比如調試JNICALL,調試JNI_Onload等等。步驟大概都是這樣:

執行android_server
端口轉發 adb forward tcp:23946 tcp:23946
調試模式啟動程序 adb shell am start -D -n 包名/類名
IDA附加
靜態找到目標函數對應所在模塊的偏移地址
Ctrl+S找到對應模塊的基地址,兩個地址相加得到最終地址
G跳轉至地址,然后下斷
F9運行
執行jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700
斷下,進行調試。

但我一直不太懂,接下來說的「進行調試」是干什么。

后來又看了http://1.xbalien.sinaapp.com/?p=342這篇,assest目錄下存在兩個jar包,分析說可能是dex加密保存在了這里。執行真正代碼的時候會進行解密那就可以直接dump出明文dex了。(修復結構反調試在這題並不考慮)

文中介紹了兩種初級dump的方法,第一種是gcoredump。第二種是通過在dvmDexFileOpenPartial斷點dump。

 

關於dvmDexFileOpenPartial:

int dvmDexFileOpenPartial(const void* addr, int len, DvmDex** ppDvmDex);

第一個參數就是dex內存起始地址,第二個參數就是dex大小。所以在這個函數下斷點可以直接dump出明文dex。


我腦補一下原理,大概就是說它解密完了之后在內存里打開這個明文dex,然后我們要拿到它的這兩個參數,就可以保存成解密后的dex了!(還是不太明白它的適用性

 

用這種方法調試的步驟跟前面列出的步驟基本一致,過程中遇到很多問題,首當其沖是輸入jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700的時候,提示「致命錯誤,無法附加到指定VM」。我看到很多人都沒有用到這個jdb指令,也不知道這個指令到底什么時候用。后來看到一些文章他們沒用這個命令,而且不用算地址。比如:http://blog.sina.com.cn/s/blog_92b6d74d0102uyds.html#cmt_3043762

我提問:

請問你是怎么在G中填寫dvmDexFileOpenPartial就跳轉到dvmDexFileOpenPartial函數的?是不是應該先在libdvm.so中找到dvmDexFileOpenPartial函數的偏移地址,再用偏移地址加上調試程序的libdvm.so的基址,再用G跳轉,下斷嗎?

人家說他用的是正版IDA6.6。我用的是IDA6.5。

 

操作jni_onload是成功了,但我仍不知道下面該怎么調試。因為jni_onload里面保存了一些信息所以也去dump出來?可那個不是dex吧。

為什么無法附加指定VM,我還是覺得自己的地址算錯了,因為在調試Jni_Onload的時候,jdb就成功attach了,這里卻不行。但是,我分別用了2.3(Ray),4.0.4(Ray),4.2.2(Nexus 4)和4.4.4(L36h)的不同的libdvm.so測試,皆不行。回想調試Jni_Onload的時候,跟這個的區別是1.開了Eclipse,2.先F9+JDB 再下的斷點。等會兒再試試。

 

剛才試了一下,這次我像調試jni_onload一樣,步驟是F9 ——JDB命令(成功attach后程序中斷)——G到目標地址下斷點——再按一次F9觸發斷點,斷在了下的那個斷點的地方。這時候之前下斷點的地方呈現出libdvm.so中那個方法調用的地方一樣的匯編代碼,為什么之前同樣的地址什么都沒有呢。但是,這時候對應R0的地址是0,顯然是錯誤的。

而帖子中的順序是:下斷點,F9,JDB(附加后程序會中斷)。

還有個疑點,出現了這個:

destination可以指定就算了,source竟然也可以指定。。醉了。暫時不弄了。感覺好蠢,糾結於各個IDA各個版本和android各個版本的細微差別之間,試圖將所有的耦合全部嘗試一遍,卻仍然拿不到想要的東西。百度上沒有任何相關的資料。

 

好的,我假裝自己已經定位到那個dex的起始位置了,下面開始dump:

{
    auto fp, dex_addr, end_addr;
    fp = fopen("F:\\dump.dex", "wb");
    end_addr = r0 + r1;
    for ( dex_addr = r0; dex_addr < end_addr; dex_addr ++ )
        fputc(Byte(dex_addr), fp);
}

下面用smailview看dex。對於:http://1.xbalien.sinaapp.com/?p=342這道題,后面要學一下webview。

 

 

 

 

 

---------------------------------------

 

adb  forward  tcp:<本地機器的端口號>  tcp:<模擬器或是真機的端口號>

例:adb [-d|-e|-s <serialNumber>] forward tcp:6100 tcp:7100 表示把本機的6100端口號與模擬器的7100端口建立起相關,

當模擬器或真機向自己的7100端口發送了數據,那們我們可以在本機的6100端口讀取其發送的內容,這是一個很關鍵的命令,

以后我們使用jdb調式apk之前,就要用它先把目標進程和本地端口建立起關聯。

 

jdb是一個支持java代碼級調試的工具,它是由java jdk提供的,存在於xxx\Java\jdk1.6.0_21\bin之下

通過attach方式進行調試

adb jdwp顯示所有可供調試的用戶進程
adb forward tcp:xxx jdwp:<pid>
jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=xxx

 

調試模式啟動intent,手機上顯示waiting for the debugger to attach,這時候attach的時候ida顯示:

protocol version is 14 expected 17。

我是這樣做的,把android_server重新push到手機里,權限改成777,運行。

這時候用64bit的IDA打開提示類似address 4 epected 4

我是這樣做的,用32bitIDA打開。可以attach了。

 

 

----------一些摘自書上的內容----------

DDMS  

DDMS(Dalvik Debug Monitor Server)就是動態調試的一個工具(不知Android L之后會不會改名--!)。DDMS提供文件瀏覽、Logcat、Method Profiling等功能。

 

定位關鍵代碼

1.代碼注入法

用Apktool反編譯得到smali,查找onClick(),比如要找程序注冊碼,仔細閱讀之后發現比對注冊碼與用戶輸入的函數

invoke-virtual {v1, v0},Ljava/lang/String;->equalsIgnoreCase(Ljava/lang/String;)Z

move=result v3

if-eqz v3, :cond_2

那么加入Log.v()來輸出v0寄存器:

const-string v3, "SN"

invoke-static {v3, v0},Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I

然后用Apktool打包、簽名,

用"adb logcat -s SN:v"輸出SN。

  

2.棧追蹤法

代碼注入配合Logcat好用但是需要閱讀大量反匯編代碼來找「輸出點」。

棧追蹤法也屬於注入的范疇。

比如要找一個Toast是啥時候被調用的,不用閱讀太多反匯編代碼,而是定位到Toast,然后在這一段之后加入

new Exception("print trace").printStackTrace();

對應smali在書上就不寫了。

然后打包簽名運行,

在CMD輸入"adb logcat -s System.err:V *:W"

會以堆棧的方式,先輸出java.lang.Exception print trace

然后輸出從程序啟動到printStackTrace()執行期間所有被調用過的方法。

 

3.Method Profiling 4.AndBug 5.IDA Pro..

 

 

 另外參考:http://www.blogbus.com/riusksk-logs/271566148.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM