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