Android应用逆向——最好用的两个无源码调试器

  要逆向分析并修改一个Android应用,首先是对APK进行解包和打包,这一部分网上资料铺天盖地,不再赘述了。值得一提的一点就是,如果apktool无法解包或打包的话,可以尝试国人在apktool基础上开发的ShakaApktool,另外也可以使用 AndroidKiller这个工具,当然 AndroidKiller内部是使用ShakaApktool来进行解包打包。

  关于如何解包和打包、反编译为JAVA代码、修改smali代码的资料很多,按部就班做起来也比较简单。dex2jar、JD-GUI获得了反编译的JAVA代码,但如何分析这些代码,找到关键之处进行修改,才是重中之重,也是难点所在。我最近需要分析的一个APK反编译后纯JAVA代码的体积居然达到了100多MB,如何从这100多MB的代码中找到关键之处并修改,实在是一个很头疼的事情。

查阅书籍和网上资料,分析代码的方法大概有这么几种:

1.使用Android SDK中的LogCat工具查看APP运行时的日志。

要在LogCat中看到APP输出的日志,需要具备以下两个条件中的任意一个。

  ①你所用的手机的Android系统的根目录下的/default.prop文件中的ro.debuggable值为1,如果这个值为1,你可以在DDMS中看到手机上的所有进程,并可以调试它们或查看它们输出的日志。但一般的手机都不会打开这个调试开关,当然也许你会说直接修改这个/default.prop文件不就行了。不行,因为修改了要重启才会生效,但是一重启,/default.prop就会恢复原始状态,因为/default.prop是保存在boot.img的ramdisk中,它每次重启都会重新从rom中加载,所以要达到目就必须修改boot.img中的ramdisk并重新刷到手机中。具体步骤可以网上搜一下,由于太麻烦就留给喜欢折腾的人去折腾了。当然也可以把手机刷上小米的MIUI开发版ROM,它的/default.prop文件中的ro.debuggable默认为1,可以方便的调试程序。

  ②你要分析的这个Android应用的APK中的AndroidManifest.xml中有一句android:debuggable=true。但几乎所有发布出来的应用都不会把这个调试开关打开。当然你可以用apktool解包,修改AndroidManifest.xml,重新打包。但是有的应用做了特殊处理,无法用apktool解包或打包,或者是做了防打包处理,打包后一运行就闪退或不允许你登录账号。对于这种情况,在解决防打包问题之前,可以先不对它重打包。而是使用Android模拟器,大部分PC上的Android模拟器都默认根目录下的/default.prop文件中的ro.debuggable值为1,可以调试安装在上面的所有应用。用于开发的最佳模拟器当属Genymotion,其次是Android SDK自带的模拟器,但有时候你要分析的应用可能无法在这两个模拟器上运行,原因你懂的,有些应用的开发者不希望你在模拟器上运行它们的应用,做了简单处理,这个时候可以尝试一下BlueStacks之类的模拟器,这些模拟器模拟得更像真实的手机,应用不易察觉。

  好了,现在可以在LogCat中看到你想分析的应用输出的日志了,但问题来了,很多应用都不会直接用android.util.Log输出它的所有日志。输到什么地方,鬼也不知道,也许是某个文件,也许是发到它的服务器。但在反编译出的代码中找到日志的输出代码并不难。找到以后通过修改它的smali代码或用Xposed来Hook相关的日志输出函数,并将日志重定向到android.util.Log,接下来就可以在LogCat中看到它的全部日志了。这样一来可以看到不少有用的信息。

2.使用TraceView查看调用了哪些方法。

  TraceView是Android SDK中的一个性能分析工具,正如其名,它是性能分析工具,不是逆向分析工具,所以用起来是很不如意的。你可以在DDMS中开始性能分析,然后到Android应用中点一下,然后在DDMS中停止性能分析。就可以看到这段时间内所有的方法调用和耗时,但你看到的是铺天盖地的系统函数,看不出调用顺序也看不出调用堆栈,还得在铺天盖地的系统函数中找到应用自身代码的函数,简直奔溃。你也可以把android.os.Debug.startMethodTracing()和android.os.Debug.stopMethodTracing()这两行代码对应的smali代码插入到你想分析的某个函数的调用前和调用后,然后再来查看生成的性能分析文件。不过效果仍然令人沮丧。当然你可以用dmtracedump和graphviz来根据性能分析文件生成代码的调用关系视图。不过依然收效甚微,里面充斥着大量的系统函数,十分难看。这方面可以参考《Android安全技术解密与防范》或在网上查找资料。

2.抓包。
  很多Android应用(游戏、单机应用除外)都是通过HTTP协议与服务器通信,如果能抓到数据包,无疑对逆向分析很有帮助。不过很多应用与服务器的通信都是HTTPS通信,用 wireshark和tcpdump之类的工具无法抓到明文。不过根据网上资料显示,使用Fiddler可以抓到HTTPS的包,试了一下,果然如此,不过只是少部分,我想要的关键性数据没有抓到。
抓包大法中效果最好的大法当属Hook大法,使用Xposed并编写Hook模块,Hook目标应用使用的HTTP Client库的API,可以抓到所有明文数据。不过需要先查看该应用的代码,了解它是用的是什么HTTP Client库,用了该库的哪些API,然后再编写Hook模块。需要下些功夫,花不少时间,但效果是很好的。

3.调试。
  无源码调试Android应用的方法和工具有很多。在把网上资料都翻遍,几乎所有调试方法都试过来之后,总结出两种相对较好用的调试方法。

Android应用逆向——最好用的两个无源码调试器_第1张图片

①IDA Pro
  优点:调试时smali代码单步走走得很准,一步是一步,不会乱走,断点命中也很准。
  缺点:局部变量、寄存器内容显示效果太差,总所周知,很多发布出来的应用代码都做过处理,不会留下局部变量的变量名,调试时除了this,其它变量全部是寄存器v0 v1 v2等,在这种情况下你用IDA Pro调试,除了this,一个变量的值都看不到。效果如上图,除了this,所有的寄存器都是Bad type。也就是说你用IDA Pro来调试,基本上只能看看执行流程,看不到任何数据,这是什么鬼!
不过别急,在仔细阅读IDA pro的官方文档后发现,寄存器内容并非不能显示,而是它不知道里面是什么类型,需要你手动告诉它!你得打开Watch View窗口,每单步走一步,就要先看看Locals里有多少个寄存器,它们的序号是什么,然后到Watch View中添加它们并告诉它这是什么类型。那你又怎么知道是什么类型?你可以在JD-GUI里看它反编译的JAVA代码,然后再告诉IDA Pro。由于寄存器随时在变,你在调试过程中每走一步就需要看一下JAVA代码,然后告诉IDA Pro一下寄存器的类型,才能看到变量的值。可想而知,调试起来有多么辛苦,而且这个调试器还不稳定,随时都会卡死、奔溃,你需要有足够的耐心来折腾它。

IDA pro官方文档:
https://www.hex-rays.com/products/ida/support/idadoc/1669.shtml
https://www.hex-rays.com/products/ida/support/tutorials/debugging_dalvik.pdf


Android应用逆向——最好用的两个无源码调试器_第2张图片

②smalidea
  简直是神器!它是去年(2015年)下半年才面世的,如果很早之前就有这款神器,那么如今其它无源码Android调试工具应该早就被抛弃了。它是开发smali/baksmali的团队开发出来的一款IntelliJ IDEA/Android Studio插件,可以让你在你喜爱的Android Studio或IntelliJ IDEA中直接调试smali代码!虽然目前它的版本为V0.03,但已经很好用了。最为关键的一点是只要你在Watches中添加了寄存器监视,单步调试每走一步,它都会自动识别类型并显示内容。当我看到这个效果时,立马神清气爽,跑出去买了一瓶冰雪碧,摩拳擦掌准备大搞一番的时候,问题来了。
每次调试,必须先手动运行APP,然后在IDEA里附加到进程调试,如果我想调试APP启动时的代码,就不好搞了。不过查阅资料,才知道可以用adb来启动一个应用并让它等待调试器。只需在原本用于启动应用的命令 adb shell am start再加上一个参数-D即可。最后使用python写了一段脚本,先用adb shell am start -D 启动APP,然后用adb shell ps获得所有进程id,从中检索出目标APP的进程id,最后用"adb forward tcp:8700 jdwp: 进程id" 映射到8700端口。这样一来我在IntelliJ IDEA上只需固定设置调试端口为8700端口,每次我要调试APP时只需运行一下脚本,然后就可以在IntelliJ IDEA点击开始调试了,非常方便和畅快。
  不过这都是小问题,最大的问题是使用smalidea进行调试时,单步走走得不是很准,有时候对不上行,有时候乱跳,有的赋值语句一次性全跳过了,有时候明明只走到函数中间的一半,并没有什么跳转语句,但是点击下一步时,函数就结束了,好了,这次调试器没有奔溃,我奔溃了。不知道是我调试的代码做过混淆处理还是怎么说,总之开心愉快的心情一下子就跌入了谷底。
  后来使用 smalidea调试自己写的APP,发现如果不进行任何混淆处理的话,用smalidea来调试完全是爽到爆炸,差不多和有源码调试一样爽快,没有那么多莫名其妙的问题,所有局部变量都自动识别、清晰可见。

smalidea下载地址和使用说明:https://github.com/JesusFreke/smali/wiki/smalidea
adb资料:https://developer.android.com/studio/command-line/adb.html

  其它调试方法,比如AndBug由于觉得更不好用,就没有深入了解了。最后结合IDA pro单步走位准的优点和 smalidea变量显示准的优点,最终我选择两个一起用!先用IDA pro看走位,看代码执行流程,到了疑似关键的地方就用smalidea直接下断点断在那里看变量值。当然你最好准备两台电脑,一台用IDA pro,一台用smalidea。调试的时候IDA pro这边先探路,探明了道路,直接到smalidea这边下断点,查看道路(变量)细节。

  如果你觉得这样调试还是不爽,请看下一篇文章,在下一篇文章中,我们将使用一个巧妙的办法,舒舒服服的躺在床上把APP的执行流程尽收眼底。

       《Android应用逆向——分析反编译代码之大神器》


本文由CharlesSimonyi发表于CSDN博客:http://blog.csdn.net/charlessimonyi/article/details/51989096转载请注明出处

你可能感兴趣的:(【Android】,Android逆向工程)