【转】Android开发中,手把手教你root Android系统

因为从事的是智能家居相关行业,用的系统也是android系统,在某些场景下可能需要拿到系统的root权限。下面就手把手教大家去拿到app的root权限adb的root权限,比如一般手机在出厂的时候,开关机动画都是固定的,但是如果有一个需求就是需要你动态的去切换开关机的动画的时候,可能就需要你拿到root权限,然后对system/media(手机目录,开关机动画不一定全部在这里)的开关机动画进行操作等,这些都是需要拿到root权限才能进行的

当然在android系统的root权限中也是有区别的,会在下面指出区别在哪:
您要确认您是想开启adbd 的root 权限,还是让app 也可以拿到root 权限。他们之间是有很大区别的,其功能导向也肯定不一样,举个例子:如果你的系统adb root了,并不代表你的apk可以对系统目录进行操作,同样也是apk如果拿到root权限,也不一定代表可以拿到所有对系统的操作权限;

注意严重声明: 任何在最终user版本上打开root权限的手法都会给用户带来安全风险, 请仔细评估您的需求是否真实需要.
MTK(有可能是联发科) 强烈反对此类做法, 由此带来的安全风险,以及造成的损失, MTK 不承担任何的责任。
注意:MTK是强烈反对对user版本进行root的,因为会带来严重的安全性问题。

什么是adb的权限:
USB adb 权限是指,当adb 连接手机时,手机中的守护进程adbd 的权限为root 权限,从而它的子
进程也具有root 权限,通常如果adb shell 看到是:
这里写图片描述

在上面可以看到:在输入adb shell之后,直接拿到的就是root的权限

什么是apk的root权限
一个apk想要拿到系统的root权限可没那么容易,知道linux的都知道,linux系统下如果想拿到系统的权限就必须要使用sudo命令,同样,在android系统中,如果你想你的apk可以拿到系统的权限,就必须要su,那么这个su就要在编译的时候编译到system/bin文件夹或者system/xbin下面,而且su文件使用权限也必须要对普通的用户进行开放

这里写图片描述
从上图可以看出,集成了su命令的系统,在进去shell的时候,其adb是没有root权限的,依旧是,但是在执行su,命令之后,其后面的

就已经转变成#,说明已经拿到root的权限了,但是本篇博客重点讲的就是如何去进行adb的root和apk的root

如何永久性开启adb的root的权限

adb 的root 权限是在system/core/adb/adb.c (Linux中文件,刷机文件)中控制。主要根据ro.secure 以及 ro.debuggable
等system property 来控制。
默认即档ro.secure 为0 时,即开启root 权限,为1时再根据ro.debuggable 等选项来确认是否可
以用开启root 权限。为此如果要永久性开启adb 的root 权限,有两种修改的方式:
1. 修改system property ro.secure, 让ro.secure=0。
2. 修改adb.c 中开启root 权限的判断逻辑。
* 在L 版本上adb 会受到SELinux 的影响, 所以需要调整SELinux policy 设置.
下面详细说明这两种修改方式:
第一种方法. 修改system property ro.secure, 让ro.secure=0。

(1)修改alps/build/core/main.mk(?暂时找不到此文件

ifneq (,$(user_variant))
    #Target is secure in user builds.
ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=1
将ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=1
改成 ADDITIONAL_DEFAULT_PROPERTIES +=ro.secure=0 即可。

(2)在android JB 版本(4.1) 以后,google 从编译上直接去除了adbd 的user 版本root 权限, 为
此您要修改system/core/adb/Android.mk(Linux中文件) 中的编译选项ALLOW_ADBD_ROOT, 如果没有打开这个选项
,那么adb.c 中将不会根据ro.secure 去选择root 还是shell 权限,直接返回shell 权限。因此您
必须需要Android.mk 中的第126行:

将ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
 修改成ifneq (,$(filter userdebug user eng,$(TARGET_BUILD_VARIANT)))

(3)在android L (5.0) 以后, google 默认开启SELinux enforce mode, 需要在user build 上将su label 默认build 进SEPolicy.
放开SELinux 的限制. 更新alps/external/sepolicy/Android.mk(?暂时找不到) 116 行, 将su label 默认编译进入sepolicy.

sepolicy_policy.conf := $(intermediates)/policy.conf
$(sepolicy_policy.conf): PRIVATE_MLS_SENS := $(MLS_SENS)
$(sepolicy_policy.conf): PRIVATE_MLS_CATS := $(MLS_CATS)
$(sepolicy_policy.conf) : $(call build_policy, $(sepolicy_build_files))
@mkdir -p $(dir $@)
$(hide) m4 -D mls_num_sens=$(PRIVATE_MLS_SENS) -D mls_num_cats=$(PRIVATE_MLS_CATS) \
-D target_build_variant=$(TARGET_BUILD_VARIANT) \<---在这里
-D force_permissive_to_unconfined=$(FORCE_PERMISSIVE_TO_UNCONFINED) \
-s $^ > $@
$(hide) sed '/dontaudit/d' $@ > [email protected]
将-D target_build_variant=$(TARGET_BUILD_VARIANT) 改成 -D target_build_variant=eng

即第一种方法在android L(5.0) 以后你需要改(1),(2),(3).
注:目前我们项目的系统是5.0以上的,所以我只试过(1),(2)(3)三种方法

第二种方法. 修改adb.c 中开启root 权限的判断逻辑。这里针对4.1 以后版本 和4.1以前版本有所区别。
(1).如果是JB 4.1 以后版本,直接修改函数should_drop_privileges() 函数, 清空这个函数,直
接返回 0 即可。返回0 即开启root 权限。

(2).如果是JB 4.1 以前版本,直接修改函数adb_main 函数,在

/* don't listen on a port (default 5037) if running in secure mode */
/* don't run as root if we are running in secure mode */
if (secure) {
struct __user_cap_header_struct header;
struct __user_cap_data_struct cap;
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
exit(1);
}

在这段代码前加一行:

    secure = 0; //mtk71029 add for root forever.
    /* don't listen on a port (default 5037) if running in secure mode */
    /* don't run as root if we are running in secure mode */
    if (secure) {
    struct __user_cap_header_struct header;
    struct __user_cap_data_struct cap;
    if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) {
    exit(1);
    }

(3)在android L (5.0) 以后, google 默认开启SELinux enforce mode, 需要在user build 上将su label 默认build 进SEPolicy.
放开SELinux 的限制. 更新alps/external/sepolicy/Android.mk 116 行, 将su label 默认编译进入sepolicy.

(和第一种方法的3步骤一致)

    sepolicy_policy.conf := $(intermediates)/policy.conf
    $(sepolicy_policy.conf): PRIVATE_MLS_SENS := $(MLS_SENS)
    $(sepolicy_policy.conf): PRIVATE_MLS_CATS := $(MLS_CATS)
    $(sepolicy_policy.conf) : $(call build_policy, $(sepolicy_build_files))
    @mkdir -p $(dir $@)
    $(hide) m4 -D mls_num_sens=$(PRIVATE_MLS_SENS) -D mls_num_cats=$(PRIVATE_MLS_CATS) \
    -D target_build_variant=$(TARGET_BUILD_VARIANT) \
    -D force_permissive_to_unconfined=$(FORCE_PERMISSIVE_TO_UNCONFINED) \
    -s $^ > $@
    $(hide) sed '/dontaudit/d' $@ > [email protected]
    将-D target_build_variant=$(TARGET_BUILD_VARIANT) 改成 -D target_build_variant=eng

即第二种方法在android L(5.0) 以后你需要改(1),(3).
当修改完成后,只需要重新build bootimage,然后download 即可,然后到setting 中开启debug选项,adb 连接后,会显示 #, 即root 成功。

如何去开启apk的root权限(su命令内置和克服SELINUX)

通过内置第三方SuperSU来进行apk的root(PS:作者由于项目时间比较忙,并没有尝试过这样的root方法)

该方式可以绕过zygote 和 adbd 对Root Capabilities BoundSet 的限制. MTK 目前仅测试KK 以及以前的版本, L 版
本后因为SuperSU 还在持续更新中, 请客户查看它官网的说明.
1:下载SuperSU(SuperSu介绍:http://pcedu.pconline.com.cn/1019/10198925.html
SuperSU下载(GooglePlay,我因为暂时不用网站打开,但下载页面一直没打开):

http://forum.xda-developers.com/showthread.php?t=1538053,https://forum.xda-developers.com/apps/supersu/stable-2016-09-01supersu-v2-78-release-t3452703
2:内置Superuser.apk 到 system/app

将su 复制并改名成: daemonsu
内置su 到 system/xbin
内置daemonsu 到 system/xbin
内置chattr 到 system/xbin
内置chattr.pie 到 /system/xbin

3. 内置install-recovery.sh 到system/etc

更新alps/system/core/inlcude/private/android_filesystem_config.h
在android_files 数组的最开始新增.
{ 00755, AID_ROOT, AID_ROOT, 0, "system/etc/install-recovery.sh" },

第二种方法就是内置Google default su命令

1:放开Google default su 只准shell/root 用户使用的限制

system/extras/su/su.c 中删除下面3行代码
if (myuid != AID_ROOT && myuid != AID_SHELL) {
fprintf(stderr,"su: uid %d not allowed to su\n", myuid);
return 1;
}

2:首先将此编译出的su 内置到system/bin, 然后修改su 的内置权限,启用sbit 位.

1、修改 alps\system\extras\su\Android.mk
LOCAL_MODULE_TAGS := debug 改为 LOCAL_MODULE_TAGS := optional
注:将su设置在编译的时候不仅仅是在debug状态下才编译的
2、修改 alps\build\target\product\core.mk
增加    PRODUCT_PACKAGES += \ su \
注:在编译的时候,编译su项目

3、如果是KK(非KK2)版本。需要强行解除 zygote 和adbd 对Root Capabilities BoundSet 的限制。
   修改 alps\kernel\security\commoncap.c
   增加
    static long cap_prctl_drop(struct cred *new, unsigned long cap) {
    //add start
    if(!strncmp(current->comm, "zygote", 16)){
            return -EINVAL; .
    }
    if(!strncmp(current->comm, "adbd", 16)){
         return -EINVAL;
    }
    //add end
    if (!capable(CAP_SETPCAP))
        return -EPERM;
    if (!cap_valid(cap))
        return -EINVAL;
    cap_lower(new->cap_bset, cap);
        return 0;
    }

4、然后修改su 的内置权限
更新alps/system/core/inlcude/private/android_filesystem_config.h
在android_files 数组中,将原来su的权限修改成:
{ 06755, AID_ROOT,  AID_ROOT,      0, "system/xbin/su" },
注:这个时候编译出来的是可以获取root权限的,并且其编译成功后的目录是在system/xbin目录下的

3:如果在L 版本操作, 请按下面的流程:(目前作者操作的版本是L版本以后的)

更新alps/frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
将 DropCapabilitiesBoundingSet(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) {
      if (errno == EINVAL) {
        ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify "
        "your kernel is compiled with file capabilities support");
      } else {
        ALOGE("prctl(PR_CAPBSET_DROP) failed");
        RuntimeAbort(env);
      }
    }
  }*/
}

4:更新alps/frameworks/base/cmds/app_process/app_main.cpp 的main 函数, 注释掉main函数开始的下面这段代码

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.
    if (errno != EINVAL) {
        LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
        return 12;
    }
}

5:如果是L 版本, 需要手动关闭SELinux

更新bootable/bootloader/lk/platform/mt6xxx/rules.mk
# choose one of following value -> 1: disabled/ 2: permissive /3: enforcing
SELINUX_STATUS := 3
调整这个SELINUX_STATUS这个的值为 2

6:修改system/core/init/Android.mk 新增

ifeq ($(strip $(TARGET_BUILD_VARIANT)),user)
LOCAL_CFLAGS += -DALLOW_DISABLE_SELINUX=1
endif

 

笔者也是在网上参考了很多过来的人经验,再结合自己在实际修改权限的过程中遇到的某些问题做的一些总结,可能有时候我们做手机并不需要去更改的系统想相关的权限,而我们的用户可能对手机root也并不是那么敏感。但是作为一个开发者,并不意味着我们不会遇到某些场景下,需要打开root的这样的需求。当然,如果打开了root之后,最直接的结果可能就是会导致安全性会稍稍降低,但是也可以采用其他的方式来避免。

参考的相关博客:
http://blog.csdn.net/muyang_ren/article/details/49507393
http://blog.csdn.net/kangear/article/details/51872653

转载链接:https://blog.csdn.net/qq_29924041/article/details/59106635

你可能感兴趣的:(Android系统权限)