Android 5.0 Lollipop 如何像4.2.2一樣通過su命令獲取root權限

4.2.2(Jelly Bean)上root的方法比較簡單,調用su命令就可以獲取到root權限並執行一些命令。但是在Android 4.3+到5.0,Google爲這種root方法設置了層層障礙: 
1. su命令源碼中添加了uid檢驗,只允許shell/root用戶進行調用  
2. Zygote源碼中添加了添加DropCapabilitiesBoundingSet屏蔽APP了setuid的功能 
3. adb源碼中添加了添加should_drop_privileges屏蔽adb了setuid的功能(對於userdebug/eng版本該函數未被調用) 
4. 開啓了SELinux安全模塊,1,2條都滿足情況下也會被中斷su。

具體解決方法:

針對前三項的解決方法是按照以下diff文件進行修改代碼並重新編譯Android系統:

su命令源碼中添加了uid檢驗,只允許shell/root用戶進行調用 
Zygote源碼中添加了添加DropCapabilitiesBoundingSet屏蔽APP了setuid的功能
adb源碼中添加了添加should_drop_privileges屏蔽adb了setuid的功能(對於userdebug/eng版本該函數未被調用)
以上三項需要改動代碼並重新編譯Android系統。 
1,2,3代碼修改的diff文件:

project frameworks/base/
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 1bb28c3..3e69750 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -185,6 +185,7 @@ static const char ZYGOTE_NICE_NAME[] = "zygote";

 int main(int argc, char* const argv[])
 {
+/*
     if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
         // Older kernels don't understand PR_SET_NO_NEW_PRIVS and return
         // EINVAL. Don't die on such kernels.
@@ -193,6 +194,7 @@ int main(int argc, char* const argv[])
             return 12;
         }
     }
+*/

     AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
     // Process command line arguments
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 4f5e08b..8b136bd 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -208,6 +208,7 @@ static void EnableKeepCapabilities(JNIEnv* env) {
 }

 static void DropCapabilitiesBoundingSet(JNIEnv* env) {
+/*
   for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
     int rc = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
     if (rc == -1) {
@@ -220,6 +221,7 @@ static void DropCapabilitiesBoundingSet(JNIEnv* env) {
       }
     }
   }
+*/
 }

 static void SetCapabilities(JNIEnv* env, int64_t permitted, int64_t effective) {

project system/core/
diff --git a/adb/adb.c b/adb/adb.c
index 10a1e0d..2cd4f97 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -1261,6 +1261,7 @@ static void drop_capabilities_bounding_set_if_needed() {
 }

 static int should_drop_privileges() {
+    return 0;
 #ifndef ALLOW_ADBD_ROOT
     return 1;
 #else /* ALLOW_ADBD_ROOT */
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 2f528b9..1223b45 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -244,7 +244,7 @@ static const struct fs_path_config android_files[] = {

     /* the following five files are INTENTIONALLY set-uid, but they
      * are NOT included on user builds. */
-    { 04750, AID_ROOT,      AID_SHELL,     0, "system/xbin/su" },
+    { 06755, AID_ROOT,      AID_SHELL,     0, "system/xbin/su" },
     { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/librank" },
     { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procrank" },
     { 06755, AID_ROOT,      AID_ROOT,      0, "system/xbin/procmem" },
@@ -255,6 +255,7 @@ static const struct fs_path_config android_files[] = {

     { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/uncrypt" },
     { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/install-recovery.sh" },
+    { 06755, AID_ROOT,      AID_ROOT,      0, "system/bin/su" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/valgrind/*" },

project system/extras/
diff --git a/su/su.c b/su/su.c
index 8365379..826acfc 100644
--- a/su/su.c
+++ b/su/su.c
@@ -107,11 +107,12 @@ int main(int argc, char **argv)

     /* Until we have something better, only root and the shell can use su. */
     myuid = getuid();
+    /*
     if (myuid != AID_ROOT && myuid != AID_SHELL) {
         fprintf(stderr,"su: uid %d not allowed to su\n", myuid);
         return 1;
     }
-
+    */
     if(argc < 2) {
         uid = gid = 0;
     } else {

設置SELinux權限爲Permissive

我是儘量把事情簡單化,這次這裏討論的是SELinux,其實現原理會比較複雜,我這裏只是簡單記錄在Android 5.0 + Linux 3.4如何將SELinux降級,這麼做的原因是實現:APP可以調用su命令最終實現運行一些命令。

SELinux常用狀態有兩個Permissive 和 Enforcing,後者會使APP無法調用su命令,前者可以。 
1. 查詢當前SELinux狀態:

adb shell getenforce

運行該命令後,會輸出當前系統的SELinux權限Permissive 和 Enforcing。 
2. 在eng/userdebug版本 將SELinux 模式調整到Permissive mode

臨時方案:運行如下命令(無需重啓系統,即刻見效)
adb shell setenforce 0

長久方案:在啓動參數中添加
androidboot.selinux=permissive

ROOT不成功問題解決方法

root不成功主要是因爲沒有改全這些項,有其中一項沒有改好都會造成root不成功。這裏把每項沒有改好會造成的問題列出來以供參考。

安裝運行 HelloRoot App,這是一個協助查看是否能獲取root權限的小工具。

查看HelloRoot的Application user id

root@nanopi2:/ # ps | grep com.example.helloroot
u0_a50    1283  121   1233532 40640 ffffffff b6e791c4 S com.example.helloroot
root@nanopi2:/ #

其中u0_a50就是HelloRoot的Application user id了,這個id在下面步驟中會用到;

切換到u0_a50用戶下並運行su命令
root@nanopi2:/ # su u0_a50
root@nanopi2:/ $ id
uid=10050(u0_a50) gid=10050(u0_a50) groups=1003(graphics),1004(input),1007(log),1011(adb),1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats) context=u:r:su:s0
# 以u0_a50身份運行su命令,正常情況下會再切到root權限下
root@nanopi2:/ $ su
root@nanopi2:/ #

不正常的話會出現如下錯誤:
su: can't execute: Permission denied
這個屬於u0_a50對su無可執行權限,說明include/private/android_filesystem_config.h中需要改的內容沒有改或者是沒有改成功。
su: uid 10050 not allowed to su
這個屬於su不允許su和shell以外的用戶(比如u0_a50)調用,說明su.c中需要改的內容沒有改或者是沒有改成功。
點擊CheckRoot按鈕,判斷App是否可以root,如果Log信息如下:

System.err: java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null
System.err:     at java.lang.ProcessManager.exec(ProcessManager.java:211)
System.err:     at java.lang.Runtime.exec(Runtime.java:173)
System.err:     at java.lang.Runtime.exec(Runtime.java:246)
System.err:     at java.lang.Runtime.exec(Runtime.java:189)
System.err:     at cn.trinea.android.common.util.ShellUtils.execCommand(ShellUtils.java:135)
System.err:     at cn.trinea.android.common.util.ShellUtils.execCommand(ShellUtils.java:93)
System.err:     at cn.trinea.android.common.util.ShellUtils.checkRootPermission(ShellUtils.java:44)
System.err:     at com.example.helloroot.MainActivity.onCreate(MainActivity.java:25)
System.err:     at android.app.Activity.performCreate(Activity.java:5990)
System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
System.err:     at android.app.ActivityThread.access$800(ActivityThread.java:151)
System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
System.err:     at android.os.Looper.loop(Looper.java:135)
System.err:     at android.app.ActivityThread.main(ActivityThread.java:5254)
System.err:     at java.lang.reflect.Method.invoke(Native Method)
System.err:     at java.lang.reflect.Method.invoke(Method.java:372)
System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
System.err: Caused by: java.io.IOException: Permission denied
System.err:     at java.lang.ProcessManager.exec(Native Method)
System.err:     at java.lang.ProcessManager.exec(ProcessManager.java:209)
System.err:     ... 20 more
System.err: java.io.IOException: Error running exec(). Command: [su] Working Directory: null Environment: null
System.err:     at java.lang.ProcessManager.exec(ProcessManager.java:211)
System.err:     at java.lang.Runtime.exec(Runtime.java:173)
System.err:     at java.lang.Runtime.exec(Runtime.java:246)
System.err:     at java.lang.Runtime.exec(Runtime.java:189)
System.err:     at cn.trinea.android.common.util.ShellUtils.execCommand(ShellUtils.java:135)
System.err:     at cn.trinea.android.common.util.ShellUtils.execCommand(ShellUtils.java:56)
System.err:     at com.example.helloroot.MainActivity.onCreate(MainActivity.java:26)
System.err:     at android.app.Activity.performCreate(Activity.java:5990)
System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
System.err:     at android.app.ActivityThread.access$800(ActivityThread.java:151)
System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
System.err:     at android.os.Looper.loop(Looper.java:135)
System.err:     at android.app.ActivityThread.main(ActivityThread.java:5254)
System.err:     at java.lang.reflect.Method.invoke(Native Method)
System.err:     at java.lang.reflect.Method.invoke(Method.java:372)
System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
System.err: Caused by: java.io.IOException: Permission denied
System.err:     at java.lang.ProcessManager.exec(Native Method)
System.err:     at      ... 19 more

A. 出現這個問題是由於沒有將SELinux關閉,需要按照以下方法查看

# 通過查看SELinux狀態
root@nanopi2:/ # getenforce
Enforcing

需要按照「設置SELinux權限爲Permissive」進行設置。 
B. 無法setuid的限制修改 
core/jni/com_android_internal_os_Zygote.cpp和cmds/app_process/app_main.cpp修改。

參考文檔: 
1. How to set SELinux to 0 or permissive mode in android 4.4.4 and above? by user1147688 
2. user版本如何打開root權限 
 

https://blog.csdn.net/kangear/article/details/51872653

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章