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命令