天天看點

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中其實都是有講解和解決的,隻是這個文檔相對來說是比較大,就沒有傳上去了,在這裡有需要的可以關注下 私信發一下

歡迎通路我的部落格