1. 设备环境
已经 root 的Android手机
2. 步骤
- 下载 busybox 二进制文件 Android一般为arm架构的
- 重命名下载的文件为 busybox
- adb push 到手机,比如
adb push ~/Download/busybox /sdcard
- 把busybox 复制到xbin下,首先
adb shell
然后cp /sdcard/busybox /system/xbin/
(如果报错,看下面的错误处理) - 修改busybox的执行权限
cd /system/xbin/
然后chmod a+x busybox
sync
同步一下- 然后验证一下
busybox vi
3. 错误处理
在执行 cp /sdcard/busybox /system/xbin/
的过程出错了,提示:only ready system
,当前目录是只读的,不能写入文件,然后搜索到重新挂载命令mount -o remount -t yaffs2 /dev/block/android_system /system/
运行结果如下:
HWEVA:/ # mount -o remount -t yaffs2 /dev/block/android_system /system/mount: '/system/' not in /proc/mounts1|HWEVA:/ #复制代码
报错:'/system/' not in /proc/mounts
最后找到了一个新的挂载命令mount -o rw,remount -t auto /system
:
1|HWEVA:/ # mount -o rw,remount -t auto /systemHWEVA:/ #复制代码
3.1 无法mount 的原因
没有搜到为啥上面那个命令不能用了,但是有个工具app很好用,Re文件管理器
google play 可以下载
下载后jadx-gui 打开,然后全局搜索,mount
,最有可能的是以下两个方法(当然你也可以认为都有可能~~~):
然后通过AndroidStudio的Smali插件,动态调试一下。把这两个方法都打上断点,然后在界面上点击,挂载为可读写
观察代码执行顺序,发现走了第二个地方。
ok,去研究第二个地方的代码是如何执行shell的。
//类名 com.speedsoftware.rootexplorer.ch//这个参数,是mount 命令,可能是原始的mount也可能是busybox的 public final String b(String str) { String str2; if (VERSION.SDK_INT <= 22) { //Android 5.1 及其以下版本 //这个a()方法返回的是当前的挂载状态,以此来选择本次操作是挂载为可读写还是挂载为只读 str2 = a() ? "rw" : "ro"; //断点调试发现,当目录选择为 /system 的时候 //this.c = /dev/block/mmcblk0p43 //this.d = /system //所以这里完整的命令为 //mount -o rw,remount /dev/block/mmcblk0p43 /system return String.format(str + " -o %s,remount %s %s", new Object[]{str2, this.c, this.d}); } str2 = a() ? "rw" : "ro"; //mount -o rw,remount /system return String.format(str + " -o %s,remount %s", new Object[]{str2, this.d}); }复制代码
现在,根据不同的手机执行上面的命令行就行了,不过要记住,手机必须root,命令必须在超级用户下执行。其实上面的方法只是生成了要执行的shell的命令字符串,真正的执行,在调用这个方法的下一步。具体查找过程省略:
//类名 com.speedsoftware.rootexplorer.aq//大概的调用伪代码如下this.n = "/system/bin/sh"; this.j = Runtime.getRuntime().exec(this.n);this.e = this.j.getOutputStream();this.e.write( b("busybox mount"))this.e.flush()复制代码
最后看下这个方法是在哪里调用的,也就是b方法的参数传入的到底是哈?
//类名 com.speedsoftware.rootexplorer.ig /* Access modifiers changed, original: protected|final */ public final boolean a(ch chVar) { boolean a = be ? a("mount_for_root_explorer.sh", chVar, false) : false; //就是这里不同脚本的mount命令... return (a || !(a("toolbox mount", chVar, false) || a("toolbox mount", chVar, true) || a("busybox mount", chVar, false) || a("busybox mount", chVar, true) || a("mount", chVar, false))) ? a : true; }复制代码