安卓代码跟踪方式学习笔记_第1页
安卓代码跟踪方式学习笔记_第2页
安卓代码跟踪方式学习笔记_第3页
安卓代码跟踪方式学习笔记_第4页
安卓代码跟踪方式学习笔记_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

安卓代码跟踪方式学习笔记分享一下学习过程中的心得,主要献给和我一样起步晚又对安卓产生浓烈兴趣的童鞋们!一、代码跟踪的介绍&使用工具代码跟踪常用于调试程序中,跟踪并了解程序的执行轨迹和执行逻辑。这样来说,对Java这样的高级语言来说,我们容易理解也容易调试。但是像一些低级语言,例如ASM、Smali来说难度就很大了,因为反汇编这样的语言,我们需要一次性记住很多乱七八糟的关键词才能成功,因而代码跟踪的技术就诞生了,并且在一些大程序中的运用更为广泛,同时也是现在逆向一些大而复杂的Android-app极为重要的一种手段。相信很多人都玩过PC端,对OD的动态调试也应该特别熟悉。OD很强大,其中的F2(断点),F8(单步走)使得调试程序事半功倍,我相信用过得没有说不好的吧。而Android-app与PCsoftware的性质是不同的。在Android-app里是把Apk文件Dump成字节码,分析,修改,再重新编译。有一个很大的不同点就是Android-app但是正是由于开源,使得Dump出来的字节码是“死"的,这是Java的一个特性。幸运的是,Apktool很好的解决了这个问题,它的出现使得Android-app的调试得到了转机,受益的是大家。既然不能进行完全的调试,想到的办法是用系统的log函数来呈现程序运行到关键时候的关键信息来达到相应的效果。比如说,你想知道程序运行到某个时候某个变量里装的是什么,就可以用log的方式显示。获取Android程序的log信息一共有几种方式。最好的选择当时是用DDMS,因为它和AndroidSDK是一伙的!它可以显示很多系统的log信息以及一些其他的乱七八糟的信息。同时,可以设置过滤器来进行标签过滤、log等级(error,warning,info,debug,verbose)过滤、进程过滤,也能结束进程。相当强大。如图:二、跟踪方法Logging大法因为Apps没有控制台所以它们只能通过Android的API中的log函数来进行输出。关于android/util/Log的介绍如下:LogextendsObject一共有5个方法:Log.v()Log.d()Log.i()Log.w()andLog.e(),它们分别对应:intASSERTPriorityconstantfortheprintlnDEBUGPriorityconstantfortheprintlnmethod;useLERRORPriorityconstantfortheprintlnmethod;useLINFOPriorityconstantfortheprintlnmethod;useLVERBOSEPriorityconstantfortheprintlnmethod;useLWARNPriorityconstantfortheprintlnmethod;useLog.wLog.d一般来说是用的最多的。(本来log.v是最多的,但是log.v并不参加编译)写一个测试类来分析Java代码如下:代码:publicclassLog{publicLog(){}publicstaticvoidLog(Stringmsg){Log(msg,"Log");}publicstaticvoidLog(ObjectXX){Log("Log",XX.toString());}publicstaticvoidLog(ObjectXX,Stringtag){Log(tag,XX.toString());}publicstaticvoidLog(Stringtag,Stringmsg){Log.d(tag,msg);}publicstaticvoidToastLog(Contextcontx,Stringmsg,intduration){Toast.makeText(contx,msg,duration).show();}反汇编成Smali代码如下:代码:#directmethods.methodpublicconstruetor<init>()V.logue.line8invoke-direct{pO},Ljava/lang/Object;-><init>()Vreturn-void.endmethod.methodpublicstaticLog(Ljava/lang/Object;)V.registers3.parameter""XX".prologue.line17const-stringvO,"Log"invoke-virtual{pO},Ljava/lang/Object;->toString()Ljava/lang/String;move-result-objectvlinvoke-static{vO,vl},Lcom/Ericky/Log;->Log(Ljava/lang/String;Ljava/lang/String;)V.line18return-void.endmethod.methodpublicstaticLog(Ljava/lang/Object;Ljava/lang/String;)V.registers3.parameter""XX"".parameter""tag".prologue.line22invoke-virtual{pO},Ljava/lang/Object;->toString()Ljava/lang/String;move-result-objectv0invoke-static{pl,v0},Lcom/Ericky/Log;->Log(Ljava/lang/String;Ljava/lang/String;)V.line23return-void.endmethod.methodpublicstaticLog(Ljava/lang/String;)V.registers2.〃〃.parameterlogue.line12const-stringv0,"Log"invoke-static{v0,p0},Lcom/Ericky/Log;->Log(Ljava/lang/String;Ljava/lang/String;)V.line13return-void.endmethod.methodpublicstaticLog(Ljava/lang/String;Ljava/lang/String;)V.registers2.parameter"tag".〃〃.parameterlogue.line28invoke-static{p0,p1},Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I.line29return-void.endmethod.methodpublicstaticToastLog(Landroid/content/Context;Ljava/lang/String;)V.registers3.parameter""contx"".〃〃.parameterlogue.line33const/4v0,0x5invoke—static{pO,pl,v0},Lcom/Ericky/Log;—>ToastLog(Landroid/content/Context;Ljava/lang/String;I)V.line34return—void.endmethod.methodpublicstaticToastLog(Landroid/content/Context;Ljava/lang/String;I)V.registers4.parameter""contx"".〃〃.parametermsg.parameter""duration"".prologue.line40invoke—virtual{p0},Landroid/content/Context;->getApplicationContext()Landroid/content/Context;.line41invoke—static{p0,pl,p2},Landroid/widget/Toast;—>makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;move—result—objectvOinvoke—virtual{vO},Landroid/widget/Toast;->show()V.line42return—void.endmethod取出第一个方法:代码:.methodpublicstaticLog(Ljava/lang/Object;)V.registers3.parameter""XX"".prologue.line17const-stringv0,"Log"invoke-virtual{pO},Ljava/lang/Object;->toString()Ljava/lang/String;move-result-objectvlinvoke-static{v0,v1},Lcom/Ericky/Log;->Log(Ljava/lang/String;Ljava/lang/String;)V.line18return-void.endmethod在这个方法里的第一个参数就是标签,在DDMS中是可以过滤的。因此,可以利用这个特点插入我们要加的信息,从而轻松的定位到关键的地方。在实际操作的过程中,可以打开androidAPI的文档,对着看。通常的做法是用Log.d,还要用到toString()这个API,同时需要2个变量,一个变量存放你的标签以及另一个存放你的对象。值得注意的是,即使你根本不用这个2个变量,也需要将.locals和.registers的数量增加。修改完了之后记得检查好代码,至少我们自己能读懂它。还有一点需要我们注意,当你改完之后最好在根目录下运行,否则记得还要改class的路径。不然的话有可能出现ClassDefNotFound错误,程序强制退出。下面是修改的代码:const-stringvO,"Erickytag"const-stringv1,"importantlogmessage"invoke-static{vO,v1},Lcom/Ericky/Log;->Log(Ljava/lang/String;Ljava/lang/String;)V这是一个简单的例子,但是有的时候我们是需要显示更多的字符串,那我们应该怎么办呢?需要用到一个StringBuilder类。StringBuilder类的用法在我之前的一篇文章中已经有用到了,很容易理解。http:///showthread.php?t=194955栈跟踪法有时候破解的时候,我们会找一些关键的注册字符串,例如“Register,failed,limit、pro”等等,但是很多程序其实在刚启动的时候就检测完了用户的合法性,所以可能造成定位不准确。一些混淆过的程序一般都是这样的。这时候我们就可以用栈跟踪法了,可以查看堆栈,能看到它所调用的方法,查看堆栈代码:invoke-static{},Ljava/lang/Thread;->dumpStack()V它的标签为:System.err实际效果:代码:java.lang.Throwable:stackdumpatjava.lang.Thread.dumpStack(Thread.java:612)atcom.lohan.testbed.SomeClass.superFun(SomeClass.java:113)atcom.lohan.testbed.Main.onCreate(Main.java:48)atandroid.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)atandroid.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)atandroid.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)atandroid.app.ActivityThread.access$2300(ActivityThread.java:125)atandroid.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)atandroid.os.Handler.dispatchMessage(Handler.java:99)atandroid.os.Looper.loop(Looper.java:123)atandroid.app.ActivityThread.main(ActivityThread.java:4627)atjava.lang.reflect.Method.invokeNative(NativeMethod)atjava.lang.reflect.Method.invoke(Method.java:521)ernal.os.Zygotelnit$MethodAndArgsCaller.run(Zygotelnit.java:868)ernal.os.Zygotelnit.main(Zygotelnit.java:626)atdalvik.system.NativeStart.main(NativeMethod)从第三行可以知道dumpStack实际上是在SomeClass类中的superFun()函数里。然后superFun()函数又是在onCreate()函数里。以此类推。不过值得一提的是,如果app被混淆了,并且debugging信息被删除了或者是被重命名了,会出现“Unknownsource",但是还是可以判断的。线程和处理器很多时候app用了大量线程之间的通信导致了栈跟踪法变得不是那么有效了,这个时候如果你还是打印出堆栈的信息的话,只会追溯到最后的那个线程的消息处理器,而原始的那个线程就被隐藏了。当然可以通过手工来追溯,方法是根据代码中的一些函数类似于sendMessage()等等。这里有个更简单的方式:代码://在handleMessage()中的smali代码invoke-static{vO},Lsample/thread/messaging/ThreadMessaging;->access$0(Lsample/thread/messaging/ThreadMessaging;)Landroid/os/Handler;move-result-objectv2invoke-virtual{v2},Landroid/os/Handler;->obtainMessage()Landroid/os/Message;move-result-objectvl//假设v2是你的处理器invoke-virtual{v2},Landroid/os/Handler;->getLooper()Landroid/os/Looper;move-result-objectv2invoke-virtual{v2},Landroid/os/Looper;->getThread()Ljava/lang/Thread;move-result-objectv2invoke-virtual{v2},Ljava/lang/Thread;->getName()Ljava/lang/String;move-result-objectv2但是2个线程如果同时在运行,这个方法就不好使了,原因就留给大家去思考了。“遗留下的宝藏”这个方法虽然说跟运气脱不了干系,但在实际的运用中还是比较广泛的。因为程序员是人,是人就会有疏忽。在编写程序的时候,程序员会用很多的log来调试他自己写的程序是否正确,因此就给逆向人员留下了一笔宝贵的财富。当然,很有可能有一个Boolean类型调试变量来控制是否输出log信息,类似下面:代码:publicclassMyClass{privateContextmyContext;privatebooleanDebugMode;publicMyClass(Contextc){myContext二c;DebugMode=false;}publicvoidsomeMethod(){SharedPreferencessettings=PreferenceManager.getDefaultSharedPreferences(myConte

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论