Android 5.0 Lollipop 如何像4.2.2一样通过su命令获取root权限
2016-07-10 18:35
603 查看
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权限
3. NanoPi T2 QQ群中网友:孤独的狼
相关文章推荐
- Android 中 DownLoadManager 实现文件下载
- Android滚动原理及实现
- ArcGIS移动客户端离线地图的几种解决方案
- Android100天学习小结
- Android坐标系
- 【Android基础】 Launch Mode
- Fresco图片加载(一)
- Android控件布局属性全解
- 共享元素跳转
- Android之Fragment实战
- Android 笔记之 设置透明度 ActionBar ----ToolBar
- Android平台下使用OpenCV设置ROI
- Android 对canvas的translate()方法的理解
- Android软键盘弹出时把布局顶上去,控件乱套解决方法
- Android两个小Demo之电话拨号器和短信发送器
- Android点击事件的四种实现方式
- android studio 查看程序的 MD5 sha 签名
- <Professional Android 4 Application Development> - Note 02
- Android基本布局总结
- Android Studio环境下基于Robotium的自动化黑盒测试