其实说白了就是AndroidStudio动态调试Smali,一直在用的方法,挺有效的逆向分析方法。把apk反编译成Smali然后倒入AndroidStudio中,然后通过jdwp调试相关进程。
基本技能
- 会使用AndroidStudio的debug的功能,不会的看这里
- 能够理解简单的Smali语法看这里
- 能够使用apktool反编译apk,并且重新打包,不会的看这里
工具
- AndroidStudio 最好是最新版本,我用的是2.3 最近好像3.0的正式版出来了
- smaliidea-x.x.x.zip这个是AndroidStudio的插件,从这个链接的列表中下载那个,最新版本的zip文件插件的官网
- apktool 反编译apk->Smali 并且重新打包修改后的Smali到apk
- jadx 用了查看Smali对应的java代码,增加可读性
插件安装:上面那个zip包下载完成后,打开AndroidStudio选择
Android Studio -> Preferences -> Plugins -> Install plugin from disk -> 选择 smalidea.x.x.x.zip 插件 ->重启 -> 插件就安装好了。
动态调试Smali文件
1. 调试的前提条件 使app可调试
开发过Android的都知道,要想调试一个apk的前提是这个apk是可调式,一般我们发版的时候,会发release版。(在一开始的时候,我们开发Android是没有gradle的,那时候发release版不像现在在gradle配置好就行了,是直接操作AndroidManifest.xml
文件中
标签的 属性 android:debuggable="true"
)因为在一般的手机上,release版本的应用是不可以被调试的,相对来说起到了保护app的作用。
上面说了是在一般的手机上,从上面来看,可以在AndroidManifest文件中设置debuggable开关,那么这个开关是被谁来验证的呢?答案是系统,Android系统会通过debuggable 验证一个app是不是可以调试。可以不可以关掉系统的验证?答案是可以的。不过很麻烦,据说有两种方式可以修改,一种是重新刷入boot.img 修改方法,另一种是通过xpost修改。
而我们平常用的最多的就是,修改AndroidManifest.xml 中的android:debuggable="true"
,然后重新打包apk。
逆向工程不是普通的反编译,一般来说逆向都是带有目的的。我们拿最近我用到的WPS 的Android版(WPSOffice_206.apk)来测试,在这里不讨论逆向的目的。我们来处理这个apk,使它可以被被debug。
- 首先 通过
apktool d WPSOffice_206.apk
来反编译 - 然后 在生成的目录中找到
AndroidManifest.xml
,用AS或者文本编辑器打开修改里面的
标签,如果有debuggable属性,修改为true,如果没有,给
标签添加android:debuggable="true"
- 最后
apktool b WPSOffice_206
这时候会在./WPSOffice_206/dist
目录下生成重新打包好的apk。(注意这个地方会出现重新打包的错误,文章最后给出解决方法)然后要给这个apk签名。文章开始给出的相应的文章。 - 然后我们把这个自签名后的apk安装到手机就可以了
2. 导入Smail源码到AndroidStudio中
打开as后,通过File-->Open ...
选择我们刚才反编译处理的那个目录,WPSOffice_206,然后等待as建立完索引。
注意左侧选择Project视图,如下所示:
然后右键工程主目录:Mark Directory As -> Sources Root
然后设置sdk,最后和测试手机的系统版本一致:项目目录-->右键-->Open ModuleSettings:
3. Android Studio 的配置
接下来配置:Run/Debug Configurations
里面的配置文件:
打开后我们点击上面的+符合,然后选择Remote,添加一个远程调试如下图:
然后配置远程调试的端口和一些其他信息,如下图:
注意,上面的Name可以随便写,因为每一个Remote配置都对应手机app上的一个进程,每一个手机app可能有多个进程,所有名字上我们做下区分。另一个需要配置的地方是Port,这个port也可以随便写,只要当前电脑上没有是用这个端口就好,如果要同时调试手机上的某个app的多个进程,这个每次配置Remote的时候,port不能一样。我们这里是用默认的5005。
4. 打通AndroidStudio和可调试apk之间的通道
手机上已经安装了我们前面重新打包的可调试的wps的apk。运行它
4.1 查看wps的所有的进程信息
然后命令行运行adb shell ps | grep cn.wps.moffice_eng
4.2 判断你要debug的那个页面(Activity)在哪个进程里面
首先打开这个页面,然后命令行运行:
adb shell dumpsys activity | grep mFocusedActivity
这会得到当前显示的Activity的名字,然后去AndroidManifest.xml
中去查看这个Activity的信息,里面会有进程信息。
4.3 端口映射
adb forward tcp:5005 jdwp:29685
设置端口转发,这条命令的含义可以认为是在本地5005端口与手机29685进程之间建立一条通道,当开始调试时,AS连接本地的5005端口,通过这条通道控制程序的运行。这个5005是前面(图3.2)中配置的端口,这个29685是wps在手机上运行的一个进程的进程id。(图4.1)中获取的。
关于 adb (包括adbd,adb-Client adb-Server )中的端口映射的可以看这篇文章http://www.cnblogs.com/gordon0918/p/5570811.html,端口映射可以省略,在ddms中选中要调试的进程,ddms会附加一个8700端口。
4.4 下断点
这个随便下,和平常一样,只要下到你想要程序暂停的地方就好,我们把断点下到wps的首页,通过adb shell dumpsys activity | grep mFocusedActivity
这个命令可知道首页叫cn.wps.moffice.main.local.HomeRootActivity
。
注:这里把断点下到了首页的onResume方法中是为了测试用,因为onResume方法会被调用很多次,当我们按home键,然后在打开wps的时候这个方法就会被调用。不说了,如果连onResume的调用时机都不知道还搞什么逆向。
4.5 启动debug
首先选择要调试的配置,然后点击那个调试按钮。如果左下角出现下图说明启动成功:
试试打开个别的应用,然后再切回wps,这时候程序会停在断点处。
5 举个例子
举个例子:以WPS的创建ppt为例,我们来把断点打到创建ppt上,然后调试这个ppt的创建流程。
我们打开WPS后,右下角有个很大的红色加号,点击这个后会有创建选项,我们选中创建PPT,然后选择新建空白文档。会看到如下图所示
这个时候我们运行adb shell dumpsys activity | grep mFocusedActivity
会得到
mFocusedActivity: ActivityRecord{50a4e0a u0 cn.wps.moffice_eng/cn.wps.moffice.presentation.multiactivity.Presentation1 t306}
还是截图来看吧:
现在拿到这个Activity的名字了,我们再来看这个Activity在哪个进程里面,这就需要通过AndroidManifest.xml了。
看到android:process
的值了没,就是这个Activity所在的进程。然后我们拿大这个进程号就可以调试了。
命令行运行adb shell ps | grep cn.wps.moffice_eng
如下图:
然后配置debug config
设置端口转发:
adb forward tcp:5006 jdwp:31333
然后运行debug:
运行成功视图:
这是后在点击创建一个ppt,然后程序就会在断点处暂停如下图:
剩下的调试面板的使用和普通的Android调试一样,前面给出的文章已经有啦。通过这个调试面板可以跟踪变量,查看调用堆栈,类之间的跳转。等等非常有用。
最后一个bug处理
在修改完 wps的 AndroidManifest.xml 然后执行apktool b WPSOffice_206
的时候。apktool会抛出下面的错误:
可以看到打了一大堆乱七八糟的log,其实都没用,只看第一行就行,说在 AndroidManifest.xml 的第61行有个不能被识别的资源标识符'resizeableActivity',打开AndroidManifest.xml 然后全局搜下这个字符串:
这玩意不知道有啥用,把这个属性删了就行,好像是为了简单组织重打包的一个混淆操作。