本文將深刻揭示提取Android ROOT權限的完整過程。這一過程與網上的方法有很大的差別。不少網上提取ROOT權限的方式都是使用別人作好的程序,有的甚至點擊一下按鈕就會自動完成全部的工做。這樣作儘管能夠成功提取ROOT權限,但讀者並不能瞭解其中的原理,並且因爲Android設備的千差萬別,可能並非每一種Android設備均可以很容易找到提取ROOT權限的工具。因此最通用的方法就是儘量利用現成的工具來完成提取ROOT權限的工做。那麼現成的工具備什麼呢?其實主要就是Android源代碼以及Linux內核源代碼。也就是說,大多數工做均可以經過這些源代碼來解決。當了解了這一過程的原理後,若是並無找到合適的提取ROOT權限的工具,就能夠經過本文介紹的方法很容易獲取Android設備的ROOT權限。
本文介紹的提取ROOT權限的方法主要針對Nexus 7,對於其餘Android設備也可使用相似的方法。但必須知足以下兩個條件。
Android設備容許進入bootloader模式。有少數的Android設備關閉了bootloader模式,因此沒法刷機。根據筆者的經驗,Google的幾個親兒子(Nexus系列),HTC、三星的Android設備基本都沒問題,其餘廠商的設備就須要具體問題具體分析了。css
能夠找到合適的Recovery。有的Android設備自帶的Recovery因爲功能有限,在刷機上也有一些問題,因此不得不使用第三方的Recovery。一般大廠商生產的Android設備都能找到合適的第三方Recovery。但刷Recovery一般也必須知足第1個條件。android
資深Android
玩家和喜歡玩「酷」的Android
用戶在Android
手機到手後的第一件事就是提取ROOT
權限,由於Android
設備有了ROOT
權限,就徹底在本身的控制之下了,儘管這樣作會帶來必定的安全隱患,但在他們看來,自由比任何東西都重要。
可能不少人是經過從網上下載的工具提取ROOT
權限的。那麼提取ROOT
權限真的很複雜嗎?No
,其實提取ROOT
權限遠沒有編寫Android
應用複雜,只須要一些簡單的步驟就能夠搞定,固然,若是有編程的基礎,那就會更以爲提取ROOT
權限的過程簡直太「酷」了。那麼在本文先看一下提取ROOT
權限的基本步驟。
對於一部沒有ROOT
權限的Android
設備,將文件複製到系統目錄的方法有以下兩個。
一般複製完整的系統目錄結構會使用第1
種方法,例如,複製整個system
文件系統(system.img
)。而要將少許的文件複製到某些文件系統,通常會使用第2
種方法。由於這種方法能夠經過腳本命令複製指定的文件到系統目錄(如/system/xbin
),並且不會影響其餘無關的數據。
讀者可使用官方的Recovery
,也能夠下載第三方的Recovery
。通常第三方的Recovery
會更強大一些。在下一節會詳細介紹如何使用第三方的Recovery
。
提取ROOT
權限的關鍵就是執行su
命令。不過Android
系統帶的su
命令在默認狀況下只能由root
用戶調用,因此使用su
命令以前須要先破解su
命令,也就是修改su
源代碼,將檢測調用權限的代碼去掉,若是有必要,再加入知足本身需求的代碼。也就是所,提取ROOT
權限實際上使用的是已經破解了的su
命令。在後面的內容
會詳細介紹如何修改su
源代碼,並從新生成su
命令文件。
第
3
步
:製做Recovery
刷機文件(update.zip
)
要想將破解後的su
命令放到Android
的系統目錄(如/system/bin
)目錄中,須要製做Recovery
刷機包,也就是一個普通的zip
壓縮文件。一般文件名爲update.zip
。不過不少高級的Recovery
容許選擇其餘的zip
文件。因此通常Recovery
刷機包能夠起任何文件名。
Recovery
刷機包的內部結構有必定的規則,主要的工做就是編寫updater-script
腳本文件,該腳本文件的詳細編寫過程會在後面的內容
節介紹。
到這一步就水到渠成了,直接執行su
命令,當前的Shell
就擁有root
權限了(Shell
標識符由$
變成了#
)。如今能夠在Shell
中瀏覽只有root
權限才能看到的內容,例如,經過ls /data/data
命令查看/data/data
目錄中的文件和目錄列表。
其實第4
步已經成功使當前的Shell
擁有了root
權限,不過還有一點缺陷,就是當進入Android
設備的Shell
時每次都須要執行su
命令才能獲取root
權限,這樣有些麻煩。所以還須要修改配置文件,使得一進入Shell
就能夠馬上擁有root
權限。在後面的內容
會詳細介紹如何修改,以及修改哪些配置文件。
任何一個在Android
設備上成功運行的ROM
都會自帶一個Recovery
,經過Recovery
,能夠將一個zip
格式刷機包中的內容複製到指定的系統目錄。Nexus 7
官方ROM
也帶了一個Recovery
。不過這個Recovery
功能有限,並且zip
文件還須要簽名才能刷機,很麻煩。固然,讀者能夠定製本身的Recovery
,不過定製Recovery
的工做量是很是大的,一般不可能在短期內完成,因此本文暫不作深究,在後續的文章中會專門探討與定製Recovery
相關的問題。既然官方自帶的ROM
不給力,而定製Recovery
又很費勁,那麼最節省時間的方法就是使用第三方的Recovery
。
如今有不少第三方的Recovery,其中比較著名的是Clockwork Recovery。目前大多數流行的Android設備都有對應的Clockwork Recovery。Clockwork Recovery不只功能強大,並且zip格式的刷機包不須要簽名就能夠正常使用。
刷機以前首先應執行下面的命令進入bootloader模式。
大概3到5秒時間,Nexus 7就會自動重啓,並進入bootloader模式。要注意的是,在bootloader模式下adb命令再也不起做用,取而代之的是fastboot命令,要想知道當前PC有多少Android設備處於bootloader模式,可使用下面的命令。固然,若是Android設備處於正常模式下,可使用adb devices顯示當前鏈接到PC的Android設備列表。
進入到bootloader模式後就能夠爲所欲爲地刷機了。在本文只介紹如何刷Recovery,後續的文章會深刻講解如何刷各類鏡像文件。假設下載的Recovery鏡像文件是recovery-clockwork-touch-6.0.2.3-grouper.img。在bootloader模式下刷Recovery鏡像文件的命令以下:
fastboot flash recovery recovery-clockwork-touch-6.0.2.3-grouper.img
![](http://static.javashuo.com/static/loading.gif)
在bootloader
模式下經過音量上下鍵切換到「Recovery mode
」選擇項(在屏幕右上角顯示),而後按電源鍵,大概等5
秒,Nexus 7
就會進入Clockwork Recovery
。若是想從新啓動Nexus 7
,並進入正常的模式,能夠選擇Recovery
的「reboot system now
」菜單項,而後按電源鍵便可。若是讀者刷的是帶觸摸功能的Recovery
,只要點擊「reboot system now
」菜單項便可從新啓動Nexus 7
。若是讀者目前處於正常模式下,而且Nexus 7
已經過USB
線與PC
鏈接,可使用下面的命令進入Recovery
模式。
刷完了Recovery
後,就須要將su
文件放到Android
設備中的/system/bin
或/system/xbin
目錄中,而後直接執行su
命令便可使當前的Shell
得到root
權限(Shell
提示符從$
變成了#
),之前不少不能作的事也能夠作了,例如,普通用戶不能查看/data/data
目錄中的內容,使用su
命令提取root
權限後也可使用ls
命令查看/data/data
目錄的內容了。
讀者能夠從網上下載合適的su
文件,或直接從Android
源代碼中獲取su
文件。若是Android
源代碼尚未編譯,須要按着1.3.2
節的步驟編譯整個Android
源代碼。成功編譯Android
源代碼後,就能夠在以下的目錄找到編譯好的su
文件。
<Android源代碼本目錄>/out/target/product/generic/system/xbin
實際上這個su
命令徹底能夠知足目前的需求,也就是提取Android
設備當前Shell
的root
權限。不過先別忙將su
文件弄到Android
設備上。接下來先看一下su
文件的源代碼,瞭解一下su
文件的運行原理以及爲何能在Android
設備上成功執行。
<Android源代碼根目錄>/system/extras/su
su
是用C
語言編寫的普通可執行文件,主文件是su.c
。讀者能夠打開該文件看一下su
的源代碼。
su.c文件中除了引用的一些頭文件外,就只有一個main函數,代碼以下:
源代碼文件:<Android源代碼根目錄>/system/extras/su/su.c
#define LOG_TAG "su"… …int main(int argc, char **argv){ struct passwd *pw; int uid, gid, myuid; 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 { pw = getpwnam(argv[1]); if(pw == 0) { uid = gid = atoi(argv[1]); } else { uid = pw->pw_uid; gid = pw->pw_gid; } } if(setgid(gid) || setuid(uid)) { fprintf(stderr,"su: permission denied\n"); return 1; } if (argc == 3 ) { if (execlp(argv[2], argv[2], NULL) < 0) { fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[2], strerror(errno)); return -errno; } } else if (argc > 3) { char *exec_args[argc - 1]; memset(exec_args, 0, sizeof(exec_args)); memcpy(exec_args, &argv[2], sizeof(exec_args)); if (execvp(argv[2], exec_args) < 0) { fprintf(stderr, "su: exec failed for %s Error:%s\n", argv[2], strerror(errno)); return -errno; } } execlp("/system/bin/sh", "sh", NULL); fprintf(stderr, "su: exec failed\n"); return 1;}
從su.c文件的代碼能夠看出,su命令支持多個命令行參數。這些命令行參數分爲以下兩類。
第1類:su的第一個參數,該參數指定了要提高權限的用戶ID或用戶名,若是不指定,就是當前的用戶。
第2類:其他的參數。表示提高權限後要馬上執行的命令和該命令的參數。
# su user ls –al /data/data/
經過setgid和setuid函數提高權限,也就是使得任何用戶在執行sh命令時都會擁有與sh命令擁有者一樣的權限。因爲sh命令的擁有者是root用戶,因此天然就將新的Shell提高到了root權限。web
經過execlp函數執行sh命令。因爲前面已經調用了setgid和setuid函數,因此執行sh命令會進入新的Shell,而且該Shell與sh命令文件的全部者(root用戶)擁有一樣的權限。執行exit命令會退出擁有root權限的Shell,並從新回到原來沒有root權限的Shell。再次執行exit命令後,就會退出Android Shell,回到Ubuntu Linux的終端。shell
4. 製做第一個Recovery刷機包(編寫腳本文件)
Recovery使用的刷機包就是zip格式的壓縮文件。根據不一樣的需求,刷機包中包含的文件不一樣,一個完整的刷機包很是複雜,不過本節的目的只是將su文件複製到/system/xbin目錄中,因此暫時用不着那麼複雜的刷機包。關於Recovery刷機包的詳細製做過程將在後面跟的章節深刻探討。本文只作最基本的刷機包。
其實要作一個Recovery刷機包並不困難。製做Recovery刷機包以前一般要考慮使用的是哪一個Recovery。例如,本書主要使用了Clockwork Recovery,因此能夠利用Clockwork Recovery中的一些特性。
本文要製做的刷機包中只有兩個目錄:system和META-INF。其中system就是編譯Android源代碼後,在<Android源代碼根目錄>/out/target/product/generic目錄
中的system目錄,也是進入Android設備的Shell後看到的「/system」目錄,在該目錄下包含了Android的系統文件,其中包括不少命令文件以及系統應用程序
。不過本文製做的Recovery刷機包沒這麼複雜。因爲只須要將su文件複製到/system/xbin目錄,因此在system目錄中只要有一個xbin子目錄,而且在該目錄中放一個在上一節得到的su文件便可。
可能不少讀者會問,將su文件放到/system/xbin目錄中,Recovery中刷機時就會將su文件複製到Android系統的/system/xbin目錄中嗎?答案很簡單,Recovery固然不知道本身要作什麼,具體要完成什麼工做,如何來完成,玄機全在META-INF目錄中。
在META-INF/com/google/android目錄中有一個updater-script腳本文件(純文本文件)和一個update-binary可執行文件。別看這兩個文件一共不到200KB,它們倒是整個Recovery刷機包中最核心的部分。尤爲是update-binary,該文件一般在190KB上下,別看文件尺寸不大,這但是內嵌於Recovery的一種輕量級腳本語言的解析器,而updater-script腳本文件就是使用這種腳本語言寫的。這種腳本語言就是edify。該語言除了定義一些簡單的語句外,還定義了幾十個用於各類操做的函數,例如,複製文件、刪除文件、創建連接等。
Edify語言會在後面的章節介紹,在本文只介紹該語言的幾個經常使用的函數。這些函數的原型、含義及其用法以下:
原型:ui_print(msg1, ..., msgN);
含義:該函數用於在Recovery界面輸出字符串。其中msg一、…、msgN表示N個字符串參數,該函數至少須要指定一個參數。若是指定多個參數,會將這些參數值鏈接起來輸出。
用法:ui_print(" hello world ");
原型:run_program(prog, arg1, .., argN);
含義:該函數用於執行程序,其中prog參數表示要執行的程序文件(要寫完整路徑),arg1、…、argN表示要執行程序的參數。prog參數是必須的,其餘參數都是可選的。
用法:run_program("/sbin/busybox","mount", "/system");
原型:delete(file1, file2, ..., fileN);
含義:該函數用於刪除一個或多個文件。其中file1、file2、…、fileN表示要刪除文件的路徑,至少須要指定一個文件。
用法:delete("/system/xbin/su");
原型:package_extract_dir(package_path, destination_path);
含義:用於提取刷機包中package_path指定目錄的全部文件到destination_path指定的目錄。其中package_path參數表示刷機包中的目錄,destination_path參數表示目標目錄。
用法:package_extract_dir("system", "/system");
原型:set_perm(uid, gid, mode, file1, file2, ..., fileN);
含義:用於設置一個或多個文件的權限。其中uid參數表示用戶ID,gid參數表示用戶組ID。若是想讓文件的用戶和用戶組都是root,uid和gid須要都爲0。mode參數表示設置的權限,這個權限與chmod命令設置的權限徹底同樣,例如,若是將一個文件設爲任何用戶均可以讀寫和執行的權限值是0777。file1、file2、…、fileN表示要設置權限的文件的路徑。
用法:set_perm(0, 0, 0777, "/system/xbin/su");
含義:用於解除文件系統的掛載。其中mount_point參數表示文件系統。
本文要編寫的updater-script文件只會使用上面的函數。該腳本文件主要實現以下基本功能。
以讀寫模式掛載/system。編程
刪除舊的su文件。安全
複製新的su文件。微信
修改su文件的權限。架構
卸載/system。
其中掛載/system調用了busybox命令,該命令並不屬於Android。不過該命令十分強大,常被人稱爲Android的瑞士軍刀
。busybox是一個開源的命令集合,將多達上百個命令集成在了一個大概2MB的文件中。例如,本文要用的mount命令就是其中之一。儘管Android從本質上也屬於Linux系統,但較其餘Linux系統集成的命令是不多的,因此若是想在Android中執行各類操做,一般就須要將busybox文件複製到Android系統的/system/xbin或其餘存儲命令文件的系統目錄。這樣只須要一個busybox命令就能夠搞定一切。若是讀者想知道busybox到底支持多少命令,只須要直接執行busybox命令便可。
讀者能夠在http://www.busybox.net下載busybox最新版本的源代碼,並按着說明使用交叉編譯器編譯busybox便可(在ARM架構的設備上運行必需要使用交叉編譯器),爲了方便讀者,在隨書光盤中帶了一個編譯好的busybox文件,路徑是/tools/busybox。該文件只能在ARM架構的設備上運行,不能在X86 PC上使用。讀者須要將busybox文件上傳到Android設備的/system/xbin目錄中(須要root權限),並執行 chmod 777 /system/xbin/busybox命令修改其權限後便可執行該命令。
如今看一下updater-script文件的代碼。
ui_print("*********************");ui_print("My First Recovery Update");ui_print("*********************"); ui_print("----Mounting /system ----");run_program("/sbin/busybox", "mount","-o", "rw", "/system"); ui_print("----Delete /system/xbin/su ----");delete("/system/xbin/su");ui_print("- Extracting files");package_extract_dir("system", "/system");ui_print("----- Setting permissions");set_perm(0, 0, 0777, "/system/xbin/su");unmount("/system");ui_print("finished");
在updater-script文件中使用run_program函數調用了busybox命令,並經過該命令執行了mount操做,實際上,至關於在Linux終端執行以下的命令。
busybox mount –o rw /system
若是執行mount操做時未指定「-o rw」,默認是隻讀掛載,也就是說/system目錄及其子目錄是隻讀的,爲了將/system目錄變成讀寫模式的,須要再次執行以下的命令。
busybox mount –o rw, remount /system
其中「-o rw, remount」中的rw和remount是mount命令的兩個選項,表示從新將/system目錄mount成可讀寫的。
若是須要修改默認的掛載點對應的路徑,例如,將/system掛載到/my_system目錄(該目錄必須存在),須要使用下面的命令。
busybox mount –o rw /system /my_system
如今updater-script腳本文件已經編寫完了,接下來還須要一個用於解析updater-script腳本文件的update-binary程序。讀者能夠從網上找一個Recovery刷機包,將其中的update-binary文件放到本身的刷機包中,或到<Android源代碼根目錄> /out/target/product/generic/system/bin目錄尋找一個updater文件,將該文件更名爲update-binary便可。其實updater文件也是Android源代碼的某個子程序編譯生成的,在後面深刻探討Recovery時再詳細分析updater的實現原理。
如今Recovery刷機包的全部文件(su、updater-script和update-binary)都搞定了,接下來完成最後一步,就是將system和META-INF目錄用zip格式壓縮(壓縮文件名任意取)。在下一節會介紹如何將這個zip格式文件中的內容刷到Nexus 7上。爲了方便讀者,在隨書光盤上已經帶了這個zip壓縮文件(/recovery/su_update.zip),讀者能夠直接將該文件刷到Android設備上(除了Nexus 7外,其餘使用Clockwork Recovery的Android設備也可使用該刷機包)。
可能有的讀者會發現,updater-script腳本中執行了/sbin目錄中的busybox命令,但成功啓動Android後進入Shell,在/sbin目錄中並無發現busybox命令,這究竟是真麼回事呢?
實際上,busybox命令的確存在,但卻不在system文件系統裏,而是在recovery文件系統中。在Android正常啓動後,實際上掛載的是system文件系統。而進入Recovery模式後,系統會自動掛載recovery文件系統,而掛載system文件系統要在updater-script腳本文件中經過相應的函數來完成(如本文使用了run_program函數調用了busybox命令掛載system文件系統)。system和recovery文件系統都有一個sbin目錄,但目錄中的文件是不同的。實際上,經過Android源代碼編譯生成的Recovery鏡像
是不包含busybox命令的,而Clockwork Recovery的busybox命令是本身添加的,也就是說,其餘的Recovery鏡像並不必定包含busybox命令,因此本文編寫的updater-script腳本文件只適合Clockwork Recovery。若是要想使用其餘的Recovery,或者將busybox命令添加到Recovery鏡像中,或者使用edify腳本語言的mount函數掛載相應的文件系統(如/system、/data等)。在後面的章節會詳細介紹Recovery鏡像文件的生成,以及如何修改現成的Recovery鏡像。
到如今爲止,一切準備工做都已經完成了,如今只剩下最後一步,就是提取Nexus 7的root權限。不過此次提取root權限徹底是DIY方式的,這也顯得更有意義,由於做爲程序員來講,瞭解其中的過程比結果更重要。
如今須要用USB線鏈接Nexus 7和PC,而後將上一節生成的zip文件上傳到Nexus 7的SD卡中。若是不想上傳也沒問題。一般在Recovery模式下選擇sideloader上傳方式,而不是事先上傳到Nexus 7上,由於這樣Nexus 7不須要在正常模式和Recovery模式之間來回切換,這也更適合須要頻繁調試和刷機的程序員。
如今進入Nexus 7的Recovery模式(正常模式下執行adb reboot recovery命令),若是讀者已經將zip壓縮文件(這裏假設爲update.zip)上傳到Nexus 7的SD卡中,選擇「install zip from sdcard」(第2個菜單項),而後繼續選擇zip文件便可刷機。若是未將zip文件上傳,選擇「install zip from sideload」菜單項,而後Recovery模式會處於等待狀態。如今adb的sideload上傳模式能夠工做了。在Linux終端輸入adb sideload update.zip命令,便可成功刷機。在刷機的過程當中會看到updater-script腳本文件中使用ui_print函數輸出的字符串。updater-script腳本文件中的命令執行完後,就會回到Recovery主界面。而後選擇「reboot system now」(第1個菜單項)重啓Nexus 7。
當Nexus 7進入正常模式後,進入Shell,這時尚未執行su命令,因此當前Shell仍然沒有root權限,如今執行su命令,會看到Shell提示符從「$」變爲「#」,這說明當前Shell已經擁有了root權限。如今作一些之前作不了的事,例如,使用ls /data/data命令查看系統的data目錄,如今能夠成功列出該目錄中全部的子目錄(都是系統應用或普通應用創建的私有目錄)。
6. 上傳Android應用到/system/app目錄
儘管提取root權限的目的不少,有的是爲了調用Linux的命令,有的是爲了直接訪問系統的數據。不過本章提取root權限的目的主要是爲了將系統應用的APK文件上傳到/system/app目錄中,以即可以在真機的環境下測試系統應用。
如今進入Android設備的Shell,並執行su命令提取root權限,而後看看/system/app目錄是否可寫。有的Android設備在掛載system文件系統時,/system及其子目錄是隻讀的,若是是這種狀況,執行以下的命令便可將/system目錄及其子目錄變成可讀寫的。
mount –o rw,remount /system
如今退出Android設備的Shell,從新回到Linux終端。而後找一個APK文件。但有一個問題,當執行adb shell命令進入Android設備的Shell時,一開始並無root權限,須要執行su命令才能提權,因此就不能直接使用adb push命令將APK文件上傳到/system/app目錄中(由於沒有root權限,該目錄是隻讀的)。解決的方法也很簡單,就是首先使用adb push命令將APK文件上傳到Android設備的SD卡上,而後在執行adb shell的同時執行su命令提權。例如,下面的命令能夠在Linux終端下刪除Android設備中/system/app目錄中的Test.apk文件。
adb shell su -c "mount -o remount,rw /system | rm -f /system/app/Test.apk "
下面的命令將SD卡根目錄中的Test.apk文件複製到Android設備的/system/app目錄中。
adb su -c "mount -o remount,rw /system | cp /sdcard/Test.apk /system/app/Test.apk "
爲了方便,讀者能夠編寫一個帶參數的Shell腳本文件,將adb push和adb shell命令在一塊兒使用。
- EOF -
關注「極客起源」公衆號,加星標,不錯過精彩技術乾貨
![](http://static.javashuo.com/static/loading.gif)