返回介绍

15.3 打开系统调试总开关

发布于 2024-10-10 22:32:19 字数 4490 浏览 0 评论 0 收藏 0

本节将介绍如何在不需要反编译的情况下添加 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文