《逆向专题》使用apktool 和android studio/JEB进行smali 的动态调试

之前介绍了一些做逆向的工具。其中不乏一些反编译和回编译的工具。这篇文章的主题,进行smali 的动态调试,其中关键的一点,就是获得apk的smali代码。当然,这里先排除加壳等情况。默认是可以通过反编译的。

这里我们选中的反编译工具是 apktool。工具在github 有的下载。下载得到的是一个jar。所以要运行要先配java环境。

我们用命令行执行下apktool,可以看到这个命令的使用说明

常用有下面几个用法这里介绍下:

1、反编译 

apktool d  -r <apk所在的目录> -o <输出反编译结果的存放路径>

这里的d 是反编译的意思

-r 是忽略资源文件的意思,可选的。加上之后只反编译dex,也就是只得到smali。所以当我们面临不需要对资源文件进行修改的需求时,就可以加上这个选项,忽略对资源的反编译。

类似的 还有-s  就是忽略源码的意思,只反编译资源文件

-o 是输出的路径,如果没有指定,就会默认输出到当前的目录下。

2、回编译

apktool b  <smali代码所在的目录> -o <输出回编译结果文件名和路径>

这里要注意下,有可能我们的回编译会遇到失败或者比如缺少资源之类的奇怪情况,这是apktool 依赖的android 框架资源版本太低了。这个跟apktool的版本也有关系。一般的,如果我们安装了apktool,我们默认的目录C:\Users\Administrator\apktool\framework  下可以发现有一个1.apk 文件。这个文件就是apktool引用的android 资源文件,如果我们回编译的apk版本高于这个资源的版本,就可能会出现这种失败的现象。比如:当前正在用的是api为20的framework,而需要回编译一个api23 的apk的时候。

3、更新资源文件

遇到这种情况,我们需要做的其实也简单,就是更新下我们的这个资源文件。

那么这个资源怎么获得,有几种方法。1、通过编译对应版本的android 源码获得。2、直接找一个对应api版本的android机,然后下载。这个apk资源一般存放在android中的 /system/framework 这个目录下,有个/system/framework/framework-res.apk,我们可以用adb 的pull 命令将资源下载到pc上,当然这里需要注意下权限,手机需要root等这里不多说。

当我们获得了这样的一个framework-res.apk 之后,可以使用if命令安装到apktool,如:

apktool if framework-res.apk

最后提示安装成功即可。

更新了framework-res.apk 之后,我们可以再来尝试回编译,这时候一般就不会出现问题了。

介绍完apktool 的用法,我们就可以轻易的获得smali代码了,这也是我们调试第一步。

一、获得smali源码,使用apktool 的d 选线反编译apk

二、修改我们反编译后的代码,使apk回编译后的apk进入可调式状态。下面有几个要修改的位置

1、AndroidManifest.xml 的 application 节点 加上  android:debuggable="true" 如:

2、找到入口activity,在smali 中修改onCreate 方法。一般入口activity 在AndroidManifest.xml 中找,有 intent-filter节点,并且有android.intent.action.MAIN 和 android.intent.category.LAUNCHER 声明的就是。如上面截图中的MainActivity。然后找到这个activity对应的smali代码 ,在onCreate处加上

invoke-static {}, Landroid/os/Debug;->waitForDebugger()V

如:

当完成了这句的修改,并在AndroidManifest.xml 的 application 节点 加上  android:debuggable="true"。我们就可以回编译apk了。签名之后装回到手机中,会发现软件进不去,而是到一个空白的界面卡住了。这是因为我们在onCreate中waitForDebugger生效了。app进入到一个等待调试的状态。

这里其实

Landroid/os/Debug;->waitForDebugger()V

最后这一句也可以不加上的,但是不加上的话后面调试会有一点点不一样的地方。那就是要使用调试模式去启动app,而且还要设置一次端口的转发,那这里我们称这种不调用 waitForDebugger 的方法称为方法2.

(显然,如果加上这句话,操作上会比较方便。但是有的时候,尤其是当我们因为各种限制没法回编译的时候,无法成功修改到smali代码的时候,就迫不得已需要使用方法2了)

如果要使用方法2,就不能按照正常的方式双击图标进入apk了。而是要使用命令

adb shell am start -D -n demo.crack.com.crackdemo/demo.crack.com.crackdemo.MainActivity

这里的格式是<包名>/<启动Activity名称>

成功运行之后,apk 也会进入一个等待调试的状态。这时候我们打开monitor看看。能发现目标包名已经处于等待调试状态了

记下Online的值 以及后面的8600/8700,记好之后记得要关掉monitor。因为monitor会占用掉我们的8700端口。导致后面端口转发的失败。

接下来我们 adb forward 命令实现转发,这里是

adb forward tcp:8700 jdwp:5620    

这个命令的意思是将pc端的8600端口接收到的数据转发到手机中pid 5620 的进程中。JDWP(java debug wire protocol)是dalvik VM的一个线程,可以建立在adb或者tcp基础上,与DDMS或debugger进行通信。

接下来两种方法的流程就合并了。我们其实也可以看做方法2 手动进入等待调试模式和 设置tcp通讯其实正是waitForDebugger的作用。

三、使用apktool的 b选项回编译我们的apk,可能失败需要更新资源文件,用if命令。

四、对apk进行签名,并重新安装。

签名可以使用很多集成工具的一键签名功能。也可以使用java 自带的sdk 中 jarsigner.exe进行签名。安装的时候要注意,先卸载机子中原来的apk,否则会因为签名的不同而安装失败。

安装之后,点开app,发现app会处于一片空白的状态下挂起。那么恭喜你,前面的4个步骤都已经成功了。接下来是准备导入我们的smali源码,并且开启调试。

上面就是对于我们尽心smali调试需要做的准备工作。下面要完成的事情就是进入到调试中。

这里调试smali 代码可以用真机也可以用一些模拟器。不过有的模拟器会比较不稳定,会出现一些奇怪的问题。所以涉及到调试工作,最好还是使用真机进行。

下面简单介绍下真机调试的环境配置

1、或者真机的root权限,完全root,不完全root 都可以

2、进入开发者模式,开启usb调试

3、apk满足下面两个条件中任意一个

a)  AndroidMainifest.xml  中的Application 标签包含 android:debuggalbe="true" 

b) /default.prop中的ro.debuggable的值为1

但是a方案越来越不好弄了。因为修改xml需要脱壳,反编译回回编译这些过程,即使回编译完成了还要重新签名,这会触发到签名校验,然后需要绕过各种验证过程,才能完成这个修改,所以这个方法其实越来越不好用了。

b方案 就是需要改default.prop中的ro.debuggable的值为1。这里有两种做法:

(a)改文件

(b)改内存

像这种系统文件,一般改文件都是只读的。首先是没有权限,另外即使改了这个文件的值,内存中的值也没改,需要重启。但是一旦重启,可能这个被修改的文件又恢复了,还是不行。(这个不同的机子可能会有所不同,简单测试下就知道了),当然,如果有人说我刷机改这个文件。那当我没说(不过刷机是有风险的,能接受变砖那就无所谓了)。。

然后另一个方法就是改内存了。

当我们拿到一个手机的时候,一般的 ro.debuggalbe 的值都是0。 这代表不使用调试.

init进程会解析这个default.prop文件,然后把这些属性信息解析到内存中,给所有app进行访问使用,所以在init进程的内存块中是存在这些属性值的,那么这时候我们可以利用进程注入技术,我们可以使用ptrace注入到init进程,然后修改内存中的这些属性值,只要init进程不重启的话,那么这些属性值就会起效。

解决方法:

第一步:拷贝mprop 到/data/目录下

第二步:./mprop ro.debuggable 1  (当然前提赋予mprop 可执行权限)

第三步:getprop ro.debuggable(查看此时ro.debuggable在内存中的值是否修改成功)

第四步:stop  start(重启adbd进程,adb 其实包括3部分,adb server ,adb client 和 adbd 进程。注意如果这里手机重启的话这边改动的值是会变回来的)

成功修改  ro.debuggable =1 之后,这里我们使用 getprop可以查看ro.debuggable 值得状态, 现在手机中的所有应用都支持debug了。

完成了我们的真机调试设置,接下来就是进入到调试了。

这里我们分别介绍两种调试工具的使用,

1、使用android studio

2、使用JEB

######################

先来看看使用android studio 是怎么调试smali的,不过android studio本身并不支持smali 代码的识别。不信的人可以试试现在就导入smali代码,会发现smali代码中的关键字不会被高亮显示,而且也无法设置对应的断点。所以我们需要安装smailIdea插件才行。插件在这下载

https://bitbucket.org/JesusFreke/smali/downloads/

目前最新的是smalidea-0.05.zip。我们先下载下来。下载后需要在android studio中安装

五(AS)、android studio安装 smalidea 插件,并且导入smali 反编译代码。

点击File->Settings->plugins->instal plugins from disk,选择下载的zip包就行,不要解压。安装完成后,AS提示重启生效,重启即可

等待插件安装完成并且重启,我们就可以导入smali代码了。

点击import project

然后出现

不用管这个一路next,最后finished

最后工程被导入进来了

用project 视图查看,不然看不清。

导入之后我们发现smali 代码已经高亮显示了,而且还可以加上断点

六(AS)、android studio开始调试smali

打开 Device Monitor 面板。monitor 是一个sdk工具,用于查看手机的当前状态。程序的位置在\sdk\tools\monitor.bat

我们可以直接在这边运行,也可以在android studio 中输入monitor 运行(当然前提是android 的sdk/tool已经加到了环境变量中)

点开monitor面板可以看到调试姐的信息,这时候使用usb连接真机,或者使用模拟器,点开我们装上的apk, 使其处于一片空白的等待调试状态。

monitor 的 device列表有出现一个等待调试的项目,如

这里的 18137是进程iid号(后面可以用于日志的过滤等),8600和8700 是调试的端口号。

接下来开始设置我们的远程调试,点开调试设置选项,添加一个remote 类型的调试

这里端口号随便设置成8600或者8700

最后点击 debug

就可以进入调试模式,而app上的界面也出来画面了。

我们可以单击 android studio 上的代码行数旁边空白处,添加断点。然后运行app 触发断点。如下:

我们还可以在变量查看器中添加我们感兴趣的寄存器,查看器会显示出当前寄存器的值

调试的方法跟android 开发调试的流程大同小异,这里就不介绍了。

接下来看使用JEB如何调试:

五(JEB)、JEB中调试SMALI

相对于在android studio中进行smali的调试,JEB就显得格外简单了。因为它不需要安装什么插件,也不需要先将apk反编译回smali代码导入,非常简单粗暴的将开启debug 的apk拖入到JEB中,就能自动进行反编译

然后就会得到这样的一个反编译的信息,双击一下bytecode,会跳出apk的代码结构,如下

找到我们关心的类,点击进去就能转到相应的smali代码

我们可以右击选择decompile 然后跳转到对应的java层代码

操作都挺简单的。接下来我们下断点。

鼠标放在某一行smali代码上,然后按下ctrl+B 就可以添加一个断点。再重复一次可以取消断点。

设置完成断点之后我们点击debug 这个按钮开始进入调试。和前面一样的,要先启动我们的app,使之进入一个空白的状态,这就是在等待进入调试了。

然后出现选择如图所示,点击选择设备进程,带D的就是该apk的进程,如下所示,然后这里注意下包名,要与当前的一致

点击attach,就可以进入调试(这里要注意一点,如果你开启了ddms,在这一步之前需要关闭,否则会attach失败的)

attach 成功后会看到程序已经卡在断点处了。

单步执行什么的可以点击上面的工具栏,也可以将鼠标停留在图标上,可以看到对应的快捷键,用快捷键调试也是可以的。

接下来,我们查看VM/Breakpoints这个窗口,就能看到变量的值了,但是这里有个小问题,可以看到v3这个地方应该是个字符串,但是显示的却是数字:

所以这个时候我们需要自己动手改一下啦,将int改为string,就能够正常显示啦!

这里跟android studio 相比起来有个不好的地方。就是寄存器的值类型我需要设置一下,不然就默认是int,这有点不直观。

还有的就是android studio可以自己添加需要观察的变量,这里好像不能添加。有时候我想要观察某些变量,但是这里没有的话就挺抓狂了。有时候会遇到,估计是我这边破解版本的bug。除了这些之外,好像其他也没啥好说的了。毕竟前提只是拖动了一个apk进来,相比 android studio 简直不要太简单

以上就是使用 apktool + android studio/JEB 调试 smali 的全部内容。调试有利于我们弄清一些app 的执行流程,也能帮助我们更好的理解smali语法,是逆向过程中重要的一环。

发布了24 篇原创文章 · 获赞 10 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/lin___/article/details/103217571