- 对本书的赞誉
- 前言
- 基础篇
- 第 1 章 Android 中锁屏密码加密算法分析
- 第 2 章 Android 中 NDK 开发
- 第 3 章 Android 中开发与逆向常用命令总结
- 第 4 章 so 文件格式解析
- 第 5 章 AndroidManifest.xml 文件格式解析
- 第 6 章 resource.arsc 文件格式解析
- 第 7 章 dex 文件格式解析
- 防护篇
- 第 8 章 Android 应用安全防护的基本策略
- 第 9 章 Android 中常用权限分析
- 第 10 章 Android 中的 run-as 命令
- 第 11 章 Android 中的 allowBackup 属性
- 第 12 章 Android 中的签名机制
- 第 13 章 Android 应用加固原理
- 第 14 章 Android 中的 so 加固原理
- 工具篇
- 第 15 章 Android 逆向分析基础
- 第 16 章 反编译神器 apktool 和 Jadx
- 第 17 章 Hook 神器 Xposed
- 第 18 章 脱壳神器 ZjDroid
- 第 19 章 Native 层 Hook 神器 Cydia Substrate
- 操作篇
- 第 20 章 静态方式逆向应用
- 第 21 章 动态调试 smali 源码
- 第 22 章 IDA 工具调试 so 源码
- 第 23 章 逆向加固应用
- 第 24 章 逆向应用经典案例分析
- 第 25 章 Android 中常见漏洞分析
- 第 26 章 文件加密病毒 Wannacry 样本分析
15.3 打开系统调试总开关
本节将介绍如何在不需要反编译的情况下添加 android:debuggable 属性,就可以进行调试。现在已经有很多工具可以做这件事了,先来说说具体的原理吧。
其实 Android 中有一些常用的配置信息都是存放在一个文件中,如下所示,比如设备的系统、版本号、CPU 型号等信息,这个文件位置在:/system/build.prop。
查看文件的内容,可以看到很多设备的信息,而且这些 ro 开头的文件表示这些属性值是只读的,不能进行修改的。
同时 Android 中提供了两个命令来操作这些信息:getprop 和 setprop 命令,如下所示:
查看系统的 sdk 版本号如下所示:
设置系统的 sdk 版本号为 22,可是这里并没有修改成功,原因是因为 ro 开头的属性是不允许后期修改的。如果修改,需要重新编译系统镜像文件 boot.img,但是这里并不是本节介绍的重点。
既然 Android 中的一些系统属性值存放在一个文件中,而且这些值是只读的,当然不仅可以通过 getprop 命令读取,有一个 API 也是可以直接读取的,就是:
其实这个方法是 native 层实现的,具体就不分析了。那么这个文件是存储这些属性值的,是谁来进行解析加载到内存中,能够给每个 App 都能访问到呢?
这个工作就是 init.rc 进程操作的,系统启动时第一步就是解析 init.rc 文件,这个文件是在系统的根目录下,这里会做很多初始化操作,同时会做属性文件的解析工作,所以 Android 属性系统通过系统服务提供系统配置和状态的管理。为了让运行中的所有进程共享系统运行时所需要的各种设置值,系统会开辟一个属性存储区域,并提供访问该内存区域的 API。所有进程都可以访问属性值,但是只有 init 进程可以修改属性值,其他进程若想修改属性值,需要向 init 进程发出请求,最终由 init 进程负责修改属性值。
上面说到的是 system/build.prop 文件。里面主要是系统的配置信息,其实还有一个重要文件在根目录下面:default.prop,如下所示:
这里有一个重要属性 ro.debuggable,关系到系统中每个应用是否能够被调试的关键。在 Android 系统中一个应用能否被调试是这么判断的:当 Dalvik 虚拟机从 Android 应用框架中启动时,系统属性 ro.debuggable 为 1,如果该值被置 1,系统中所有的程序都是可以调试的。如果系统中的 ro.debuggable 为 0,则会判断程序的 AndroidManifest.xml 中 application 标签中的 android:debuggable 元素是否为 true,如果为 true 则开启调试支持。
这相当于 Android 系统中有一个开关,即根目录中 default.prop 文件中的 ro.debuggable 属性值,可用于调试所有设备中的应用。如果把这个属性值设置成 1,设备中所有应用都可以被调试,即使在 AndroidManifest.xml 中没有 android:debuggable=true,还是可以调试的。而这些系统属性的文件 system/build.prop 和 default.prop,都是 init 进程来进行解析的,系统启动的时候就会去解析 init.rc 文件,这个文件中有配置关于系统属性的解析工作信息。然后会把这些系统属性信息解析到内存中,提供给所有 App 进行访问,这块信息也是内存共享的。但是这些 ro 开头的属性信息只能 init 进程进行修改。下面来分析一下修改这个属性值的三种方式。
第一种方式:直接修改 default.prop 文件中的值,然后重启设备。那么现在如果按照上面的目的:就是不需要反编译 apk,添加 android:debuggable 属性的话,直接修改 default.prop 文件,把 ro.debuggable 属性改成 1 即可,但是通过上面的分析,修改完成之后肯定需要重启设备的,因为需要让 init 进程重新解析属性文件,把属性信息加载内存中方可起作用的。但是并没有那么顺利,在实践的过程中,修改了这个属性,结果会发现设备死机了,其实想想也是正常的,如果属性能够通过这些文件来修改的话,那就感觉系统会出现各种问题了,系统是不会允许修改这些文件的。
第二种方式:改写系统文件,重新编译系统镜像文件,然后刷入到设备中。前面已经提到过,这些属性文件是在系统镜像文件 boot.img 系统启动的时候,释放到具体目录中的,也就是说如果能够直接修改 boot.img 中的这个属性即可,那么这个操作是可以进行的。理论上是可以的,但是我没成功操作过。而且这种方式如果成功了,那么这个设备就是永远可以进行各种应用的调试了。
第三种方式:注入 init 进程,修改内存中的属性值。上面分析了,init 进程会解析这个属性文件,然后把这些属性信息解析到内存中,给所有 App 进行访问使用,所以在 init 进程的内存块中是存在这些属性值的,那么这时候就好办了,有一个技术可以做到,就是进程注入技术。可以使用 ptrace 注入到 init 进程,然后修改内存中的这些属性值,只要 init 进程不重启的话,那么这些属性值就会起效。好了,这个方法可以尝试,但是这个方法有一个弊端,就是如果 init 进程挂了重启的话,那么设置就没有任何效果了,必须重新操作了,所以有效期不是很长,但是一般情况下只要保证设备不重启的话,init 进程会一直存在的,而且如果发生了 init 进程挂掉的情况,那么设备肯定会重启的。到时候再重新操作一下即可。
上面的三种方式设置系统中的调试属性总开关,最后一种方式是最靠谱的。而且思路也很简单,但是不用重新去写这个代码逻辑的,因为网上已经有这个工具了,这个工具叫做 mprop,是一个执行文件。用法很简单,首先把可执行文件 mprop 拷贝到设备中的目录下,然后运行命令,如下所示:
这个工具可以修改内存中所有的属性值,包括机型信息。修改完成之后,使用 getprop 命令再查看值,发现修改成功了,但是需要注意的是,修改的是内存的值,而不是文件中的值。所以 default.prop 文件中的内容是没有发生变化:
这时候,可以使用 Eclipse 的 DDMS 来查看可以调试的应用列表,如图 15-1 所示。
图 15-1 Eclipse 中 DDMS 查看应用列表
当然也可以使用 adb jdwp 命令来查看可以调试的进程 id,如下所示:
但是可惜的是,发现还是没有展示设备中所有的应用,其实这里是有一个细节问题,虽然修改了内存值,但是有一个进程需要重启一下,哪个进程呢?就是 adbd 这个进程,这个进程是 adb 的守护进程,就是设备连接信息传输后台进程,所以想看到可以调试的进程信息的话,那么需要重启这个进程,这样连接信息才会更新。
重启这个进程很简单,直接使用命令即可,如下所示:
其实这是两个命令,用分号隔开,首先是干掉进程,然后重启。运行完命令之后,再去看 DDMS 窗口信息,如图 15-2 所示。
图 15-2 Eclipse 中 DDMS 界面展示可调式应用列表
这时候所有的应用进程都是可以调试的了,再使用 dumpsys package 命令查看一个应用的包信息,如下所示:
可以看到,这个应用的 flags 标志中并没有 debuggable 属性值,但是这个应用是可以调试的。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论