安卓代码跟踪方式学习笔记
生活随笔
收集整理的這篇文章主要介紹了
安卓代码跟踪方式学习笔记
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
一、代碼跟蹤的介紹&使用工具
代碼跟蹤常用于調(diào)試程序中,跟蹤并了解程序的執(zhí)行軌跡和執(zhí)行邏輯。這樣來說,對Java這樣的高級語言來說,我們?nèi)菀桌斫庖踩菀渍{(diào)試。但是像一些低級語言,例如ASM、Smali來說難度就很大了,因?yàn)榉磪R編這樣的語言,我們需要一次性記住很多亂七八糟的關(guān)鍵詞才能成功,因而代碼跟蹤的技術(shù)就誕生了,并且在一些大程序中的運(yùn)用更為廣泛,同時也是現(xiàn)在逆向一些大而復(fù)雜的Android?-app極為重要的一種手段。
相信很多人都玩過PC端,對OD的動態(tài)調(diào)試也應(yīng)該特別熟悉。OD很強(qiáng)大,其中的F2(斷點(diǎn)),F8(單步走)使得調(diào)試程序事半功倍,我相信用過得沒有說不好的吧。而Android-app與PC?software的性質(zhì)是不同的。在Android-app里是把Apk文件Dump成字節(jié)碼,分析,修改,再重新編譯。有一個很大的不同點(diǎn)就是Android-app但是正是由于開源,使得Dump出來的字節(jié)碼是“死”的,這是Java的一個特性。幸運(yùn)的是,Apktool很好的解決了這個問題,它的出現(xiàn)使得Android-app的調(diào)試得到了轉(zhuǎn)機(jī),受益的是大家。
既然不能進(jìn)行完全的調(diào)試,想到的辦法是用系統(tǒng)的log函數(shù)來呈現(xiàn)程序運(yùn)行到關(guān)鍵時候的關(guān)鍵信息來達(dá)到相應(yīng)的效果。比如說,你想知道程序運(yùn)行到某個時候某個變量里裝的是什么,就可以用log的方式顯示。
獲取Android程序的log信息一共有幾種方式。最好的選擇當(dāng)時是用DDMS,因?yàn)樗虯ndroid?SDK是一伙的!它可以顯示很多系統(tǒng)的log信息以及一些其他的亂七八糟的信息。同時,可以設(shè)置過濾器來進(jìn)行標(biāo)簽過濾、log等級(error,warning,info,debug,verbose)過濾、進(jìn)程過濾,也能結(jié)束進(jìn)程。相當(dāng)強(qiáng)大。如圖:
二、跟蹤方法
1.Logging大法
因?yàn)锳pps沒有控制臺所以它們只能通過Android?的API中的log函數(shù)來進(jìn)行輸出。
關(guān)于android/util/Log的介紹如下:
Log?extends?Object
一共有5個方法:Log.v()?Log.d()?Log.i()?Log.w()?and?Log.e(),它們分別對應(yīng):
int??ASSERT??Priority?constant?for?the?println?method.
int??DEBUG??Priority?constant?for?the?println?method;?use?Log.d.
int??ERROR??Priority?constant?for?the?println?method;?use?Log.e.
int??INFO??Priority?constant?for?the?println?method;?use?Log.i.
int??VERBOSE??Priority?constant?for?the?println?method;?use?Log.v.
int??WARN??Priority?constant?for?the?println?method;?use?Log.w
Log.d一般來說是用的最多的。(本來log.v是最多的,但是log.v并不參加編譯)
寫一個測試類來分析Java代碼如下:
代碼: public?class?Log?{public?Log()?{}public?static?void?Log(String?msg){Log(msg,?"Log");}public?static?void?Log(Object?XX){Log("Log",?XX.toString());}public?static?void?Log(Object?XX,?String?tag){Log(tag,?XX.toString());}public?static?void?Log(String?tag,?String?msg){Log.d(tag,?msg);}public?static?void?ToastLog(Context?contx,?String?msg,?int?duration){Toast.makeText(contx,?msg,?duration).show();} } 反匯編成Smali代碼如下:
代碼: #?direct?methods .method?public?constructor?<init>()V.registers?1.prologue.line?8invoke-direct?{p0},?Ljava/lang/Object;-><init>()Vreturn-void .end?method.method?public?static?Log(Ljava/lang/Object;)V.registers?3.parameter?"XX".prologue.line?17const-string?v0,?"Log"invoke-virtual?{p0},?Ljava/lang/Object;->toString()Ljava/lang/String;move-result-object?v1invoke-static?{v0,?v1},?Lcom/Ericky/Log;->Log(Ljava/lang/String;Ljava/lang/String;)V.line?18return-void .end?method.method?public?static?Log(Ljava/lang/Object;Ljava/lang/String;)V.registers?3.parameter?"XX".parameter?"tag".prologue.line?22invoke-virtual?{p0},?Ljava/lang/Object;->toString()Ljava/lang/String;move-result-object?v0invoke-static?{p1,?v0},?Lcom/Ericky/Log;->Log(Ljava/lang/String;Ljava/lang/String;)V.line?23return-void .end?method.method?public?static?Log(Ljava/lang/String;)V.registers?2.parameter?"msg".prologue.line?12const-string?v0,?"Log"invoke-static?{v0,?p0},?Lcom/Ericky/Log;->Log(Ljava/lang/String;Ljava/lang/String;)V.line?13return-void .end?method.method?public?static?Log(Ljava/lang/String;Ljava/lang/String;)V.registers?2.parameter?"tag".parameter?"msg".prologue.line?28invoke-static?{p0,?p1},?Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I.line?29return-void .end?method.method?public?static?ToastLog(Landroid/content/Context;Ljava/lang/String;)V.registers?3.parameter?"contx".parameter?"msg".prologue.line?33const/4?v0,?0x5invoke-static?{p0,?p1,?v0},?Lcom/Ericky/Log;->ToastLog(Landroid/content/Context;Ljava/lang/String;I)V.line?34return-void .end?method.method?public?static?ToastLog(Landroid/content/Context;Ljava/lang/String;I)V.registers?4.parameter?"contx".parameter?"msg".parameter?"duration".prologue.line?40invoke-virtual?{p0},?Landroid/content/Context;->getApplicationContext()Landroid/content/Context;.line?41invoke-static?{p0,?p1,?p2},?Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;move-result-object?v0invoke-virtual?{v0},?Landroid/widget/Toast;->show()V.line?42return-void .end?method 取出第一個方法:
代碼: .method?public?static?Log(Ljava/lang/Object;)V.registers?3 .parameter?"XX".prologue.line?17const-string?v0,?"Log"invoke-virtual?{p0},?Ljava/lang/Object;->toString()Ljava/lang/String;move-result-object?v1invoke-static?{v0,?v1},?Lcom/Ericky/Log;->Log(Ljava/lang/String;Ljava/lang/String;)V.line?18return-void .end?method 在這個方法里的第一個參數(shù)就是標(biāo)簽,在DDMS中是可以過濾的。因此,可以利用這個特點(diǎn)插入我們要加的信息,從而輕松的定位到關(guān)鍵的地方。在實(shí)際操作的過程中,可以打開android?API的文檔,對著看。通常的做法是用Log.d,還要用到toString()這個API,同時需要2個變量,一個變量存放你的標(biāo)簽以及另一個存放你的對象。值得注意的是,即使你根本不用這個2個變量,也需要將.locals和.registers的數(shù)量增加。修改完了之后記得檢查好代碼,至少我們自己能讀懂它。
還有一點(diǎn)需要我們注意,當(dāng)你改完之后最好在根目錄下運(yùn)行,否則記得還要改class的路徑。不然的話有可能出現(xiàn)ClassDefNotFound錯誤,程序強(qiáng)制退出。下面是修改的代碼:
const-string?v0,?"Ericky?tag"
const-string?v1,?"important?log?message"
invoke-static?{v0,?v1},?Lcom/Ericky/Log;->Log(Ljava/lang/String;Ljava/lang/String;)V
這是一個簡單的例子,但是有的時候我們是需要顯示更多的字符串,那我們應(yīng)該怎么辦呢?需要用到一個StringBuilder類。StringBuilder類的用法在我之前的一篇文章中已經(jīng)有用到了,很容易理解。 http://bbs.pediy.com/showthread.php?t=194955
2.棧跟蹤法
有時候破解的時候,我們會找一些關(guān)鍵的注冊字符串,例如“Register、failed、limit、pro”等等,但是很多程序其實(shí)在剛啟動的時候就檢測完了用戶的合法性,所以可能造成定位不準(zhǔn)確。一些混淆過的程序一般都是這樣的。這時候我們就可以用棧跟蹤法了,可以查看堆棧,能看到它所調(diào)用的方法,查看堆棧代碼:
invoke-static?{},?Ljava/lang/Thread;->dumpStack()V
它的標(biāo)簽為:System.err??實(shí)際效果:
代碼: java.lang.Throwable:?stack?dumpat?java.lang.Thread.dumpStack(Thread.java:612)at?com.lohan.testbed.SomeClass.superFun(SomeClass.java:113)at?com.lohan.testbed.Main.onCreate(Main.java:48)at?android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)at?android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)at?android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)at?android.app.ActivityThread.access$2300(ActivityThread.java:125)at?android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)at?android.os.Handler.dispatchMessage(Handler.java:99)at?android.os.Looper.loop(Looper.java:123)at?android.app.ActivityThread.main(ActivityThread.java:4627)at?java.lang.reflect.Method.invokeNative(Native?Method)at?java.lang.reflect.Method.invoke(Method.java:521)at?com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)at?com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)at?dalvik.system.NativeStart.main(Native?Method) 從第三行可以知道dumpStack實(shí)際上是在SomeClass類中的superFun()函數(shù)里。然后superFun()函數(shù)又是在onCreate()函數(shù)里。以此類推。不過值得一提的是,如果app被混淆了,并且debugging?信息被刪除了或者是被重命名了,會出現(xiàn)“Unknown?source”,但是還是可以判斷的。
3.線程和處理器
很多時候app用了大量線程之間的通信導(dǎo)致了棧跟蹤法變得不是那么有效了,這個時候如果你還是打印出堆棧的信息的話,只會追溯到最后的那個線程的消息處理器,而原始的那個線程就被隱藏了。當(dāng)然可以通過手工來追溯,方法是根據(jù)代碼中的一些函數(shù)類似于sendMessage()等等。這里有個更簡單的方式:
代碼: //?在handleMessage()?中的smali代碼 invoke-static?{v0},?Lsample/thread/messaging/ThreadMessaging;->access$0(Lsample/thread/messaging/ThreadMessaging;)Landroid/os/Handler; move-result-object?v2 invoke-virtual?{v2},?Landroid/os/Handler;->obtainMessage()Landroid/os/Message; move-result-object?v1 //假設(shè)v2是你的處理器 invoke-virtual?{v2},?Landroid/os/Handler;->getLooper()Landroid/os/Looper; move-result-object?v2 invoke-virtual?{v2},?Landroid/os/Looper;->getThread()Ljava/lang/Thread; move-result-object?v2 invoke-virtual?{v2},?Ljava/lang/Thread;->getName()Ljava/lang/String; move-result-object?v2 但是2個線程如果同時在運(yùn)行,這個方法就不好使了,原因就留給大家去思考了。
4.“遺留下的寶藏”
這個方法雖然說跟運(yùn)氣脫不了干系,但在實(shí)際的運(yùn)用中還是比較廣泛的。因?yàn)槌绦騿T是人,是人就會有疏忽。在編寫程序的時候,程序員會用很多的log來調(diào)試他自己寫的程序是否正確,因此就給逆向人員留下了一筆寶貴的財富。當(dāng)然,很有可能有一個Boolean類型調(diào)試變量來控制是否輸出log信息,類似下面:
代碼: public?class?MyClass?{private?Context?myContext;private?boolean?DebugMode;public?MyClass(Context?c){myContext?=?c;DebugMode?=?false;}public?void?someMethod(){SharedPreferences?settings?=?PreferenceManager.getDefaultSharedPreferences(myContext);if?(?DebugMode?)Log.d("someMethod",?"running?someMethod?now!");SharedPreferences.Editor?editor?=?settings.edit();try?{editor.putString("mobileID",?getMobileID());}catch?(Exception?e)?{e.printStackTrace();}????editor.commit();} } 那我們只需要找到DebugMode的位置,把它置成“1”即可。
5.SmaliDebugging(APKtools)
如果log信息都被程序員刪除了,那怎么辦?此時此刻,我們不得不拿出神器Apktools來調(diào)試一段一段的smali語句了,根據(jù)官方介紹,還可以單步走。是不是很誘人呢?具體可以看:http://code.google.com/p/android-apktool/wiki/SmaliDebugging
6.JDB神器
這是一個很強(qiáng)大的工具,應(yīng)該是類似GNU或者GDB調(diào)試器。打開DDMS獲取端口,然后連接調(diào)試器。
在Linux下的命令:
jdb?-attach?localhost:8616
在Windows下的命令:
jdb?-connect?com.sun.jdi.SocketAttach:hostname=localhost,port=8616
出現(xiàn)這樣的文字說明成功了:
代碼: Set?uncaught?java.lang.Throwable Set?deferred?uncaught?java.lang.Throwable Initializing?jdb?... 三、總結(jié)
當(dāng)然還有更多更好的方法,希望大牛們繼續(xù)補(bǔ)充。學(xué)習(xí)Android已經(jīng)1個多星期了,菜鳥一枚。很多地方難免有疏漏之處或者錯誤,歡迎各位童鞋指正,也歡迎多多交流,共同學(xué)習(xí)進(jìn)步。
By?Ericky
代碼跟蹤常用于調(diào)試程序中,跟蹤并了解程序的執(zhí)行軌跡和執(zhí)行邏輯。這樣來說,對Java這樣的高級語言來說,我們?nèi)菀桌斫庖踩菀渍{(diào)試。但是像一些低級語言,例如ASM、Smali來說難度就很大了,因?yàn)榉磪R編這樣的語言,我們需要一次性記住很多亂七八糟的關(guān)鍵詞才能成功,因而代碼跟蹤的技術(shù)就誕生了,并且在一些大程序中的運(yùn)用更為廣泛,同時也是現(xiàn)在逆向一些大而復(fù)雜的Android?-app極為重要的一種手段。
相信很多人都玩過PC端,對OD的動態(tài)調(diào)試也應(yīng)該特別熟悉。OD很強(qiáng)大,其中的F2(斷點(diǎn)),F8(單步走)使得調(diào)試程序事半功倍,我相信用過得沒有說不好的吧。而Android-app與PC?software的性質(zhì)是不同的。在Android-app里是把Apk文件Dump成字節(jié)碼,分析,修改,再重新編譯。有一個很大的不同點(diǎn)就是Android-app但是正是由于開源,使得Dump出來的字節(jié)碼是“死”的,這是Java的一個特性。幸運(yùn)的是,Apktool很好的解決了這個問題,它的出現(xiàn)使得Android-app的調(diào)試得到了轉(zhuǎn)機(jī),受益的是大家。
既然不能進(jìn)行完全的調(diào)試,想到的辦法是用系統(tǒng)的log函數(shù)來呈現(xiàn)程序運(yùn)行到關(guān)鍵時候的關(guān)鍵信息來達(dá)到相應(yīng)的效果。比如說,你想知道程序運(yùn)行到某個時候某個變量里裝的是什么,就可以用log的方式顯示。
獲取Android程序的log信息一共有幾種方式。最好的選擇當(dāng)時是用DDMS,因?yàn)樗虯ndroid?SDK是一伙的!它可以顯示很多系統(tǒng)的log信息以及一些其他的亂七八糟的信息。同時,可以設(shè)置過濾器來進(jìn)行標(biāo)簽過濾、log等級(error,warning,info,debug,verbose)過濾、進(jìn)程過濾,也能結(jié)束進(jìn)程。相當(dāng)強(qiáng)大。如圖:
二、跟蹤方法
1.Logging大法
因?yàn)锳pps沒有控制臺所以它們只能通過Android?的API中的log函數(shù)來進(jìn)行輸出。
關(guān)于android/util/Log的介紹如下:
Log?extends?Object
一共有5個方法:Log.v()?Log.d()?Log.i()?Log.w()?and?Log.e(),它們分別對應(yīng):
int??ASSERT??Priority?constant?for?the?println?method.
int??DEBUG??Priority?constant?for?the?println?method;?use?Log.d.
int??ERROR??Priority?constant?for?the?println?method;?use?Log.e.
int??INFO??Priority?constant?for?the?println?method;?use?Log.i.
int??VERBOSE??Priority?constant?for?the?println?method;?use?Log.v.
int??WARN??Priority?constant?for?the?println?method;?use?Log.w
Log.d一般來說是用的最多的。(本來log.v是最多的,但是log.v并不參加編譯)
寫一個測試類來分析Java代碼如下:
代碼: public?class?Log?{public?Log()?{}public?static?void?Log(String?msg){Log(msg,?"Log");}public?static?void?Log(Object?XX){Log("Log",?XX.toString());}public?static?void?Log(Object?XX,?String?tag){Log(tag,?XX.toString());}public?static?void?Log(String?tag,?String?msg){Log.d(tag,?msg);}public?static?void?ToastLog(Context?contx,?String?msg,?int?duration){Toast.makeText(contx,?msg,?duration).show();} } 反匯編成Smali代碼如下:
代碼: #?direct?methods .method?public?constructor?<init>()V.registers?1.prologue.line?8invoke-direct?{p0},?Ljava/lang/Object;-><init>()Vreturn-void .end?method.method?public?static?Log(Ljava/lang/Object;)V.registers?3.parameter?"XX".prologue.line?17const-string?v0,?"Log"invoke-virtual?{p0},?Ljava/lang/Object;->toString()Ljava/lang/String;move-result-object?v1invoke-static?{v0,?v1},?Lcom/Ericky/Log;->Log(Ljava/lang/String;Ljava/lang/String;)V.line?18return-void .end?method.method?public?static?Log(Ljava/lang/Object;Ljava/lang/String;)V.registers?3.parameter?"XX".parameter?"tag".prologue.line?22invoke-virtual?{p0},?Ljava/lang/Object;->toString()Ljava/lang/String;move-result-object?v0invoke-static?{p1,?v0},?Lcom/Ericky/Log;->Log(Ljava/lang/String;Ljava/lang/String;)V.line?23return-void .end?method.method?public?static?Log(Ljava/lang/String;)V.registers?2.parameter?"msg".prologue.line?12const-string?v0,?"Log"invoke-static?{v0,?p0},?Lcom/Ericky/Log;->Log(Ljava/lang/String;Ljava/lang/String;)V.line?13return-void .end?method.method?public?static?Log(Ljava/lang/String;Ljava/lang/String;)V.registers?2.parameter?"tag".parameter?"msg".prologue.line?28invoke-static?{p0,?p1},?Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I.line?29return-void .end?method.method?public?static?ToastLog(Landroid/content/Context;Ljava/lang/String;)V.registers?3.parameter?"contx".parameter?"msg".prologue.line?33const/4?v0,?0x5invoke-static?{p0,?p1,?v0},?Lcom/Ericky/Log;->ToastLog(Landroid/content/Context;Ljava/lang/String;I)V.line?34return-void .end?method.method?public?static?ToastLog(Landroid/content/Context;Ljava/lang/String;I)V.registers?4.parameter?"contx".parameter?"msg".parameter?"duration".prologue.line?40invoke-virtual?{p0},?Landroid/content/Context;->getApplicationContext()Landroid/content/Context;.line?41invoke-static?{p0,?p1,?p2},?Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;move-result-object?v0invoke-virtual?{v0},?Landroid/widget/Toast;->show()V.line?42return-void .end?method 取出第一個方法:
代碼: .method?public?static?Log(Ljava/lang/Object;)V.registers?3 .parameter?"XX".prologue.line?17const-string?v0,?"Log"invoke-virtual?{p0},?Ljava/lang/Object;->toString()Ljava/lang/String;move-result-object?v1invoke-static?{v0,?v1},?Lcom/Ericky/Log;->Log(Ljava/lang/String;Ljava/lang/String;)V.line?18return-void .end?method 在這個方法里的第一個參數(shù)就是標(biāo)簽,在DDMS中是可以過濾的。因此,可以利用這個特點(diǎn)插入我們要加的信息,從而輕松的定位到關(guān)鍵的地方。在實(shí)際操作的過程中,可以打開android?API的文檔,對著看。通常的做法是用Log.d,還要用到toString()這個API,同時需要2個變量,一個變量存放你的標(biāo)簽以及另一個存放你的對象。值得注意的是,即使你根本不用這個2個變量,也需要將.locals和.registers的數(shù)量增加。修改完了之后記得檢查好代碼,至少我們自己能讀懂它。
還有一點(diǎn)需要我們注意,當(dāng)你改完之后最好在根目錄下運(yùn)行,否則記得還要改class的路徑。不然的話有可能出現(xiàn)ClassDefNotFound錯誤,程序強(qiáng)制退出。下面是修改的代碼:
const-string?v0,?"Ericky?tag"
const-string?v1,?"important?log?message"
invoke-static?{v0,?v1},?Lcom/Ericky/Log;->Log(Ljava/lang/String;Ljava/lang/String;)V
這是一個簡單的例子,但是有的時候我們是需要顯示更多的字符串,那我們應(yīng)該怎么辦呢?需要用到一個StringBuilder類。StringBuilder類的用法在我之前的一篇文章中已經(jīng)有用到了,很容易理解。 http://bbs.pediy.com/showthread.php?t=194955
2.棧跟蹤法
有時候破解的時候,我們會找一些關(guān)鍵的注冊字符串,例如“Register、failed、limit、pro”等等,但是很多程序其實(shí)在剛啟動的時候就檢測完了用戶的合法性,所以可能造成定位不準(zhǔn)確。一些混淆過的程序一般都是這樣的。這時候我們就可以用棧跟蹤法了,可以查看堆棧,能看到它所調(diào)用的方法,查看堆棧代碼:
invoke-static?{},?Ljava/lang/Thread;->dumpStack()V
它的標(biāo)簽為:System.err??實(shí)際效果:
代碼: java.lang.Throwable:?stack?dumpat?java.lang.Thread.dumpStack(Thread.java:612)at?com.lohan.testbed.SomeClass.superFun(SomeClass.java:113)at?com.lohan.testbed.Main.onCreate(Main.java:48)at?android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)at?android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)at?android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)at?android.app.ActivityThread.access$2300(ActivityThread.java:125)at?android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)at?android.os.Handler.dispatchMessage(Handler.java:99)at?android.os.Looper.loop(Looper.java:123)at?android.app.ActivityThread.main(ActivityThread.java:4627)at?java.lang.reflect.Method.invokeNative(Native?Method)at?java.lang.reflect.Method.invoke(Method.java:521)at?com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)at?com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)at?dalvik.system.NativeStart.main(Native?Method) 從第三行可以知道dumpStack實(shí)際上是在SomeClass類中的superFun()函數(shù)里。然后superFun()函數(shù)又是在onCreate()函數(shù)里。以此類推。不過值得一提的是,如果app被混淆了,并且debugging?信息被刪除了或者是被重命名了,會出現(xiàn)“Unknown?source”,但是還是可以判斷的。
3.線程和處理器
很多時候app用了大量線程之間的通信導(dǎo)致了棧跟蹤法變得不是那么有效了,這個時候如果你還是打印出堆棧的信息的話,只會追溯到最后的那個線程的消息處理器,而原始的那個線程就被隱藏了。當(dāng)然可以通過手工來追溯,方法是根據(jù)代碼中的一些函數(shù)類似于sendMessage()等等。這里有個更簡單的方式:
代碼: //?在handleMessage()?中的smali代碼 invoke-static?{v0},?Lsample/thread/messaging/ThreadMessaging;->access$0(Lsample/thread/messaging/ThreadMessaging;)Landroid/os/Handler; move-result-object?v2 invoke-virtual?{v2},?Landroid/os/Handler;->obtainMessage()Landroid/os/Message; move-result-object?v1 //假設(shè)v2是你的處理器 invoke-virtual?{v2},?Landroid/os/Handler;->getLooper()Landroid/os/Looper; move-result-object?v2 invoke-virtual?{v2},?Landroid/os/Looper;->getThread()Ljava/lang/Thread; move-result-object?v2 invoke-virtual?{v2},?Ljava/lang/Thread;->getName()Ljava/lang/String; move-result-object?v2 但是2個線程如果同時在運(yùn)行,這個方法就不好使了,原因就留給大家去思考了。
4.“遺留下的寶藏”
這個方法雖然說跟運(yùn)氣脫不了干系,但在實(shí)際的運(yùn)用中還是比較廣泛的。因?yàn)槌绦騿T是人,是人就會有疏忽。在編寫程序的時候,程序員會用很多的log來調(diào)試他自己寫的程序是否正確,因此就給逆向人員留下了一筆寶貴的財富。當(dāng)然,很有可能有一個Boolean類型調(diào)試變量來控制是否輸出log信息,類似下面:
代碼: public?class?MyClass?{private?Context?myContext;private?boolean?DebugMode;public?MyClass(Context?c){myContext?=?c;DebugMode?=?false;}public?void?someMethod(){SharedPreferences?settings?=?PreferenceManager.getDefaultSharedPreferences(myContext);if?(?DebugMode?)Log.d("someMethod",?"running?someMethod?now!");SharedPreferences.Editor?editor?=?settings.edit();try?{editor.putString("mobileID",?getMobileID());}catch?(Exception?e)?{e.printStackTrace();}????editor.commit();} } 那我們只需要找到DebugMode的位置,把它置成“1”即可。
5.SmaliDebugging(APKtools)
如果log信息都被程序員刪除了,那怎么辦?此時此刻,我們不得不拿出神器Apktools來調(diào)試一段一段的smali語句了,根據(jù)官方介紹,還可以單步走。是不是很誘人呢?具體可以看:http://code.google.com/p/android-apktool/wiki/SmaliDebugging
6.JDB神器
這是一個很強(qiáng)大的工具,應(yīng)該是類似GNU或者GDB調(diào)試器。打開DDMS獲取端口,然后連接調(diào)試器。
在Linux下的命令:
jdb?-attach?localhost:8616
在Windows下的命令:
jdb?-connect?com.sun.jdi.SocketAttach:hostname=localhost,port=8616
出現(xiàn)這樣的文字說明成功了:
代碼: Set?uncaught?java.lang.Throwable Set?deferred?uncaught?java.lang.Throwable Initializing?jdb?... 三、總結(jié)
當(dāng)然還有更多更好的方法,希望大牛們繼續(xù)補(bǔ)充。學(xué)習(xí)Android已經(jīng)1個多星期了,菜鳥一枚。很多地方難免有疏漏之處或者錯誤,歡迎各位童鞋指正,也歡迎多多交流,共同學(xué)習(xí)進(jìn)步。
By?Ericky
2014.12.4
原文地址: http://www.kanxue.com/bbs/showthread.php?t=195202
總結(jié)
以上是生活随笔為你收集整理的安卓代码跟踪方式学习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android 安全专项-Xposed
- 下一篇: 也来看看Android的ART运行时