天天看点

android开发中,手把手教你root 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 看到是:

android开发中,手把手教你root Android系统

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

什么是apk的root权限

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

android开发中,手把手教你root Android系统

从上图可以看出,集成了su命令的系统,在进去shell的时候,其adb是没有root权限的,依旧是 ,但是在执行su,命令之后,其后面的 就已经转变成#,说明已经拿到root的权限了,但是本篇博客重点讲的就是如何去进行adb的root和apk的root

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

adb 的root 权限是在system/core/adb/adb.c 中控制。主要根据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 中的编译选项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.

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://forum.xda-developers.com/showthread.php?t=1538053

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

当然这些内容其实在FAQ中其实都是有讲解和解决的,只是这个文档相对来说是比较大,就没有传上去了,在这里有需要的可以关注下 私信发一下

欢迎访问我的博客