p = Runtime.getRuntime().exec("su"); linux
因此,1159 PID的sh会启动su,这里须要注意的是,su进程的Real UID是10073,由于继承自parent,可是,其EUID却提高为了ROOT,这就是因为SUID被设置的缘由。 因为su进程的EUID是ROOT,因此致使了su能够作不少高权限的事情。 android
su会经过: sql
sprintf(sysCmd, "am start -a android.intent.action.MAIN -n com.koushikdutta.superuser/com.koushikdutta.superuser.SuperuserRequestActivity --ei uid %d --ei pid %d > /dev/null", g_puid, ppid);
if (system(sysCmd))
return executionFailure("am."); shell
启动SuperUser Request Activity来询问用户是否受权当前应用,若是否的话,则su将return 结束, 不然su会继续运行。 app
获得用户许可后(经过sqlite和SuperUser Request Activity交流用户许可),su会将本身的Real UID也设置为ROOT: ui
if(setgid(0) || setuid(0))
return permissionDenied(); spa
因为su的EUID是ROOT,因此su有权限执行以上代码,执行完后su进程的Real UID,effective UID都变成了ROOT。 这里为何要同时提高Real UID的权限,后面会说明。 .net
而后,su会启动一个额外的sh来运行用户的指令: 命令行
char *exec_args[argc + 1];
exec_args[argc] = NULL;
exec_args[0] = "sh";
int i;
for (i = 1; i < argc; i++)
{
exec_args[i] = argv[i]; orm
}
execv("/system/bin/sh", exec_args);
return executionFailure("sh");
这里很是关键的代码是execv! 这里没有使用fork,而是直接使用execv,这将致使不会建立新的进程运行sh image,而是直接在当前su的进程空间load并执行sh image。 因此,return executionFailure("sh"); 正常状况下是永远不会被执行的,执行完execv后,就开始直接sh的代码了。
这里能够看到,因为复用su当前进程来运行sh,使得sh运行的进程的EUID,Real UID都是ROOT,那么,任何操做均可以执行了。 若是不提高Real UID为Root的话,那么只要sh运行中经过启动外部程序的方式来完成操做的话,就会出现权限问题,由于新启动的进程只会继承父进程的Real UID,而不是EUID,那么新起的进程的Real UID=EUID= parent RealUID != ROOT,那么某些操做可能有问题。 因此,su把本身的Real UID也提高为ROOT后,则无论启动后的任何代后的子进程执行操做,都是以ROOT的权限运行。
RootExplorer经过获得sh流后,就能够经过该流执行任何shell指令了:
经过ps也能够明显看到su变成了sh,以下,
app_73 1143 103 301620 39944 ffffffff 400194c4 S com.speedsoftware.rootexp
lorer
app_73 1159 1143 764 376 c003e454 4001cf94 S /system/bin/sh
root 1161 1159 772 388 c012e760 4007c578 S sh
这里的PID=1161的进程实际上是su(能够经过打log验证),当执行execv("/system/bin/sh", exec_args);后,进程名就变成了sh。固然进程EUID不变,仍然是ROOT。
经过cat 进程的proc信息,咱们也能够看到其实RootExplorer自身的UID或者权限根本没有被提高(这是和linux上执行su不同的地方),
root@android :/proc/1143 # cat status
cat status
Name: re.rootexplorer
State: S (sleeping)
Tgid: 1143
Pid: 1143
PPid: 103
TracerPid: 0
Uid: 10073(Real) 10073(Effecttive) 10073(saved) 10073
Gid: 10073 10073 10073 10073
而su演变成的sh,倒是具备全部的ROOT UID:
root@android :/proc/1161 # cat status
cat status
Name: sh
State: S (sleeping)
Tgid: 1161
Pid: 1161
PPid: 1159
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
总结: Android中App受权获取Root权限,其实不是App自身的权限提高了,而是经过具备ROOT权限的sh流来执行shell命令