开发APP的时候会用到 RunTime.exec() 或者 ProcessBuild().start()执行几行命令行,在需要root权限的时候会抛出如下错误
Cannot run program “su“: error=13, Permission denied
错误提示非常明显,执行该命令权限不足,进入shell查看
红框部分的s代表只有文件所有者的uid通过校验才可以被执行,观察后六位发现只有root和shell用户才有可权限,其他用户没有权限,在应用层使用ProcessBuild 执行一段命令行肯定其他用户,因此没有权限
方法一:
到/system/core/libcutils/fs_config.c 修改名为 android_files 结构体数组
{ 04750, AID_ROOT, AID_SHELL, 0, "system/xbin/su" },
只需将04750 修改成 00755 即可
改后变成:文件拥有者的uid (字母s)标志位没了,其他用户多了个 可读可执行权限,到此修改效果完成。 modified: system/core/libcutils/fs_config.c
方法二:
/system/extras/su/su.c 对当前进程的uid 做一个鉴权,当不是 ROOT 或 SHELL 用户的时候直接抛异常
int main(int argc, char** argv) {
##这里对uid做鉴权
uid_t current_uid = getuid();
if (current_uid != AID_ROOT && current_uid != AID_SHELL) error(1, 0, "not allowed");
/*
* do something
*/
}
我们知道Zygote进程是用来生孩子的,只要在APP进程出生的时候搞事情,满足su.c里面的判断条件就可以了。
进入frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
找到applyUidSecurityPolicy 函数,在末尾添加代码,编译即可。
private static void applyUidSecurityPolicy(Arguments args, Credentials peer)
throws ZygoteSecurityException {
/**
*do somthings
*/
//缺什么权限我们就给什么。
if(args.niceName.equals("自己的包名")) {
args.uid = Process.ROOT_UID;
args.gid = Process.SHELL_UID;
}
}
此方法不会改变敏感文件本来的权限,推荐使用!
-----------------------修改结束-------------
推荐用方法二,影响范围最小
最后附上APP端的调用例子
private fun clearPs() {
var cm2 = "/system/bin/rm -r 文件的路径\n"
val COMMAND_EXIT = "exit\n"
var process = Runtime.getRuntime().exec("su")
val br = BufferedReader(InputStreamReader(process.inputStream), 1024)
var inProcess = InProcessThread(br)
val error = BufferedReader(InputStreamReader(process.errorStream), 1024)
var errorProcessThread = ErrorProcessThread(error)
val os = DataOutputStream(process.outputStream)
os.writeBytes(cm2)
// 最后别忘退出
os.writeBytes(COMMAND_EXIT)
os.flush()
//开2个线程接受子进程的流
inProcess.start()
errorProcessThread.start()
}
//正常的输入流
class InProcessThread(var br: BufferedReader) : Thread() {
override fun run() {
super.run()
try {
val sb = StringBuffer()
var line = ""
while (br.readLine().also {
if (it != null) {
line = it
}
} != null) {
sb.append(line)
}
println("-------sb = ${sb}")
} catch (e: java.lang.Exception) {
Log.e("-----InProcessThread", e?.message ?: "")
} finally {
br.close()
}
}
}