Android Root原理

玩兒過Linux的應(yīng)該都明白Root代表了什么,獲取Root權(quán)限你就能控制系統(tǒng)的一切势誊,甚至還可以執(zhí)行rm -rf /呜达,反正我沒試過,不如你試試粟耻?

那么一般情況下如何切換到Root用戶呢查近,在大多數(shù)的Linux發(fā)行版中眉踱,在終端輸入su就可以進入Root用戶,當(dāng)然如果Root用戶有密碼霜威,你必須輸入密碼才能切換過去谈喳。

Android系統(tǒng)本質(zhì)上還是屬于Linux,它有著Linux和內(nèi)核和文件系統(tǒng)戈泼,它同樣可以輸入su來切換到Root用戶婿禽,但為了安全起見,Google一開始就規(guī)定Android系統(tǒng)只有兩個用戶能獲取Root權(quán)限大猛,一個是Root用戶本身谈宛,另一個是Shell用戶。Shell用戶是通過ADB(Android Debug Bridge)登錄的胎署,但如果你其他的App想獲取Root權(quán)限,就沒辦法通過Shell用戶(這里倒是沒試過在Shell用戶里窑滞,用am命令啟動App是否能獲取Root權(quán)限琼牧,沒辦法測試,我的設(shè)備已經(jīng)Root了)哀卫。

所以如果我們想讓我們登錄手機的用戶啟動的App巨坊,來獲取到Root權(quán)限,我們就要修改su(SuperUser)文件此改。

Root所需條件

Android手機(最好是Nexus系列) × 1

修改后的su文件 × 1

強大的Recovery × 1

提取Root權(quán)限步驟

刷入一個合適的Recovery

修改su命令

Recovery刷機文件

執(zhí)行su命令提取Root權(quán)限

讓ROM本身擁有Root權(quán)限

刷入一個強大的Recovery

對于一個沒有Root權(quán)限的手機趾撵,如果想修改/替換手機系統(tǒng)內(nèi)部文件,有兩種辦法

通過Bootloader模式復(fù)制整個文件系統(tǒng)(也就是我們常說的刷機)

在Recovery模式下通過Recovery升級包的方式將文件復(fù)制到指定的目錄中

很明顯一般我們理解的獲取Root權(quán)限 != 重新刷機共啃,所以我們選擇第二種方式占调,但Android手機默認(rèn)的Recovery不夠強大,我們需要尋找一個好用的Recovery來替換它移剪。

下載Recovery

目前比較流行的強大的Recovery有:

ClockWorkMod(CWM)

Team Win Recovery Project(TWRP)

先去找下有沒有自己的設(shè)備究珊,如果沒有,只能到國內(nèi)的各大手機論壇纵苛,找下自己的手機版塊剿涮,看有沒有民間大神把這些強大的Recovery移植到你的手機上,這里另外提一個攻人,國內(nèi)低端手機用的比較多的MTK芯片的機子取试,可以到移動叔叔論壇,移動叔叔自產(chǎn)的Recovery也不錯怀吻,推薦下國產(chǎn)~

刷入Recovery

下載好Recovery之后瞬浓,我們就可以想辦法用它來替換我們手機里的原裝Recovery。

Option1:通過fastboot命令刷入Recovery

先將手機切換到Bootloader模式烙博,用USB連接手機到電腦瑟蜈,并且確認(rèn)它已經(jīng)處于待調(diào)試的狀態(tài)烟逊,比如輸入adb devices,顯示出你的設(shè)備铺根,并且狀態(tài)是device宪躯,輸入命令

adb reboot bootloader

等待手機重啟到bootloader模式,大概在你準(zhǔn)備看的時候位迂,它已經(jīng)準(zhǔn)備好了访雪。

這里需要提醒的是,bootloader模式下的操作非常危險掂林,bootloader程序是手機在裝載系統(tǒng)時運行的程序臣缀,同時它也承擔(dān)著通過軟件方式自我更新系統(tǒng)的任務(wù),比較類似我們常見的BIOS泻帮,但BIOS好在一般是固件程序精置。總之锣杂,弄壞了bootloader脂倦,要么換主板,要么讓廠家通過JTAG之類的硬件的方式重新刷入bootloader元莫,簡而言之赖阻,就是廢了。不過也沒有那么可怕踱蠢,只要不執(zhí)行fastboot命令中有關(guān)bootloader的命令火欧,一般也不會有事兒。

用fastboot命令茎截,刷入你已經(jīng)準(zhǔn)備好的recovery

fastboot flash recovery [你的recovery路徑]

隨后就等待Recovery刷入完成吧苇侵!

Option2:Recovery下通過命令直接刷入(需要Root)

這種方法適合已經(jīng)Root過,但想更換Recovery的朋友稼虎,這里也順便說下衅檀,就一個命令,在 adb shell 下或者手機本地終端su進入Root用戶后使用

dd if=/sdcard/recovery.img of=/dev/recovery

下面還是來解釋下這個命令吧霎俩,dd是Linux自帶的一個復(fù)制文件的命令哀军,并在復(fù)制的同時可以進行指定的轉(zhuǎn)換,if后跟的是源路徑打却,of后跟的是目標(biāo)路徑杉适,這個命令即是把/sdcard/目錄下的recovery.img文件復(fù)制到 /dev/recovery .

到這里,相信Recovery這里沒啥疑問啦柳击。

制作Recovery升級包

有了強大的Recovery之后猿推,我們就需要制作一個Recovery的升級包,來直接替換掉系統(tǒng)自帶的su文件,這里Recovery升級包主要是靠一個腳本語言——updater-script蹬叭,來實現(xiàn)替換系統(tǒng)文件的自動化操作藕咏。

updater-script

updater-script目前的格式是Edify語言,它幾乎每一條語句都是一個函數(shù)秽五,我們主要看看Edify語言的語法格式孽查。

Edify語法

我們主要看看這次制作升級包所用到的函數(shù),更詳細語法有興趣的可以查看tody_guo的專欄 - Android updater-scripts(Edify Script)各函數(shù)詳細說明

1. ui_print

原型:uiprint(msg1, …, msgN);

功能:該函數(shù)用于在Recovery界面輸出字符串坦喘, 其中msg1 - msgN表示N個字符串參數(shù)盲再,它至少要指定一個參數(shù),如果指定多個瓣铣,會將這些參數(shù)值連接起來輸出答朋。

用法:ui_print(“ hello world “);

2. run_program

原型:run_program(prog, arg1, …, argN);

功能:該函數(shù)用于執(zhí)行程序,其中prog參數(shù)表示要執(zhí)行的程序文件(完整路徑)棠笑, arg1 - argN 表示要執(zhí)行程序的參數(shù)發(fā)梦碗。prog參數(shù)是必須的,其他參數(shù)可選

用法:run_program(“/sbin/busybox”, “mount”, “/system”);

3. delete

原型:delete(file1, file2, …, fileN);

功能:該函數(shù)用于刪除一個或多個文件蓖救。其中file叉弦、file2、…藻糖、fileN表示要刪除文件的路徑,至少需要指定一個文件库车。

用法:delete(“/system/xbin/su”);

4. package_extract_dir

原型:package_extract_dir(package_path, destination_path);

功能:用于提取刷機包中package_path指定目錄的所有文件到destination_path指定的目錄巨柒。其中package_path參數(shù)表示刷機包中的目錄,destination_path參數(shù)表示目標(biāo)目錄柠衍。

用法:package_extract_dir(“system”, “/system”);

5. set_perm

原型:set_perm(uid, gid, mode, file1, file2, …, fileN);

功能:用于設(shè)置一個或多個文件的權(quán)限洋满。其中uid參數(shù)表示用戶ID,gid參數(shù)表示用戶組ID珍坊。如果想讓文件的用戶和用戶組都是Root牺勾,uid和gid需要為0。mode參數(shù)表示設(shè)置的權(quán)限阵漏。與chmod命令相似驻民。

用法:set_perm(0, 0, 0777, “/system/xbin/su”);

6. mount

原型:mount(fs_type, partition_type, location, mount_point);

功能:掛載分區(qū)

用法:mount(“ext4”, “EMMC”, “/dev/block/platform/s3c-sdhci.0/by-name/system”, “/system”);

7. unmount

原型:unmount(mount_point);

功能:用于解除文件系統(tǒng)的掛載。其中mount_point參數(shù)表示文件系統(tǒng)履怯。

用法:unmount(“/system”);

編寫腳本文件

了解了基本的語法后回还,就可以來編寫個簡單的替換系統(tǒng)文件的腳本了,我們主要進行的操作如下

以讀寫模式掛載/system

刪除舊的su文件

復(fù)制新的su文件

修改su文件的權(quán)限

卸載/system

根據(jù)以上步驟叹洲,這里直接給上腳本

ui_print("----------------------");

ui_print("Recovery Upgrade Package");

ui_print("----------------------");

ui_print("--- Mounting /system ---");

#以讀寫模式掛載/system

run_program("/sbin/busybox", "mount", "-o", "rw", "/system");

ui_print(--- Delete /system/xbin/su ---);

#刪除舊的su文件

delete("/system/xbin/su");

ui_pirnt("--- Extracting system to /system ---");

#將刷機包中的system目錄的所有文件復(fù)制到/system目錄中的相應(yīng)位置

package_extract_dir("system", "/system");

#給su命令添加可執(zhí)行權(quán)限

set_perm(0, 0, 0777, "/system/xbin/su");

#卸載/system

unmount(/system);

ui_print("--- finished ---");

升級包制作

制作Recovery升級包需要兩個目錄

META-INF/com/google/android

system/xbin

前者用來放我們制作的updater-script文件柠硕,在META-INF/com/google/android目錄下還有一個update-binary的文件,它是用來解析我們制作的updater-script文件运提,把su放在system/xbin目錄下蝗柔。

目錄中的其他東西闻葵,可以找一個現(xiàn)成任意的Recovery升級包,把內(nèi)容復(fù)制過來就行了

最后癣丧,把這兩個目錄壓縮成.zip文件槽畔, 升級包就制作完成了。

替換su文件

有了升級包之后坎缭,我們要做的就是在Recovery里面安裝這個升級包竟痰,通過adb shell進入recovery模式

adb reboot recovery

在Recovery模式下,我們可以直接用 adb 操作這個升級包掏呼,比如先push到sdcard里面坏快,然后在Recovery里面手動的選擇在sdcard里面找到并安裝這個升級包,另外我們也可以通過一個adb命令直接push并安裝這個升級包

adb sideload update.zip

它會首先將updata.zip下載到手機中憎夷,并且執(zhí)行安裝莽鸿,這里的updata.zip是升級包的路徑,而非單單名字拾给。

使用su命令提取Root權(quán)限

su文件替換完之后祥得,我們就可以通過各種方法獲取到Root權(quán)限

在終端中執(zhí)行su命令提取Root權(quán)限

無論在pc上的adb shell命令還是手機的本地終端,正如我們開篇所說的蒋得,直接輸入su级及,即可獲取Root權(quán)限。

在App中使用Root權(quán)限

Runtime.getRuntime().exec("su");

OutputStream os = process.getOutputStream();

os.write("ls /system/app".getBytes());

os.flush();

os.close();

這段代碼還沒有進行嘗試额衙,之后會寫個刪除系統(tǒng)自帶軟件的程序來驗證下饮焦。

su命令源代碼解析

Android源代碼上su.c文件

/**

** Copyright 2008, The Android Open Source Project

** Licensed under the Apache License, Version 2.0 (the "License");

** you may not use this file except in compliance with the License.

** You may obtain a copy of the License at

** ?http://www.apache.org/licenses/LICENSE-2.0

**

** Unless required by applicable law or agreed to in writing, software

** distributed under the License is distributed on an "AS IS" BASIS,

** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

** See the License for the specific language governing permissions and

** limitations under the License.

*/

#define LOG_TAG "su"

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

/*

* SU can be given a specific command to exec. UID _must_ be

* specified for this (ie argc => 3).

*

* Usage:

* su 1000

* su 1000 ls -l

*/

int main(int argc, char **argv)

{

????????struct passwd *pw;

????????int uid, gid, myuid;

????????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;????????

}

}

/* Until we have something better, only root and the shell can use su. */

????myuid = getuid();

????if (myuid != AID_ROOT && myuid != AID_SHELL) {

????????????fprintf(stderr,"su: uid %d not allowed to su\n", myuid);

????????????return 1;

?????}

????if(setgid(gid) || setuid(uid)) {

????????fprintf(stderr,"su: permission denied\n");

????????return 1;

????}

????/* User specified command for exec. */

????????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) {

????/* Copy the rest of the args from main. */

????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;

????}

}

/* Default exec shell. */

execlp("/system/bin/sh", "sh", NULL);

????fprintf(stderr, "su: exec failed\n");

????return 1;

}

從main函數(shù)的源代碼中可以看到

/* Until we have something better, only root and the shell can use su. */

????myuid = getuid();

????if (myuid != AID_ROOT && myuid != AID_SHELL) {

????fprintf(stderr,"su: uid %d not allowed to su\n", myuid);

????return 1;

}

這個函數(shù)可以看出,su文件檢測當(dāng)前用戶如果不是Root用戶或者Shell用戶窍侧,將會直接退出su命令县踢。

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;

}

}

如果參數(shù)小于2,uid(將要切換的用戶id)和gid(將要切換的用戶組id)都會切換到Root用戶和Root用戶組伟件,C語言中如果一個命令不加任何參數(shù)硼啤,argc值就等于1,也就是說斧账,如果你只輸入了su命令谴返,將自動切換到Root用戶和Root用戶組。

if(setgid(gid) || setuid(uid)) {

????????fprintf(stderr,"su: permission denied\n");

????????return 1;

}

setgid和setuid函數(shù)是最關(guān)鍵的獲取Root權(quán)限的函數(shù)咧织,如果設(shè)置成功則返回0亏镰,所以只有當(dāng)兩個函數(shù)返回都為0的時候,才算成功獲取Root權(quán)限拯爽。

/* Default exec shell. */

execlp("/system/bin/sh", "sh", NULL);

這段代碼將當(dāng)前進程替換成一個新進程索抓,也就是以Root用戶登錄的一個新的Shell。

后記

有關(guān)Android設(shè)備提取Root權(quán)限最基本的原理就是這些了,但一般情況下往往沒這么簡單逼肯,我們也知道不同的機型Root的方式也不一樣耸黑,因為廠商對待Root設(shè)備的態(tài)度不一樣,有的堅決反對篮幢,有的不鼓勵不支持大刊,有的想方設(shè)法阻止你Root,或者只有Nexus系列的原生系統(tǒng)才會如此的簡單吧三椿,但萬變不離其宗缺菌,原理上不會差太多。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末搜锰,一起剝皮案震驚了整個濱河市伴郁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蛋叼,老刑警劉巖肩杈,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秀鞭,死亡現(xiàn)場離奇詭異左医,居然都是意外死亡涯鲁,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進店門歌馍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來握巢,“玉大人,你說我怎么就攤上這事松却【翟粒” “怎么了?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵玻褪,是天一觀的道長。 經(jīng)常有香客問我公荧,道長带射,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任循狰,我火速辦了婚禮窟社,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绪钥。我一直安慰自己灿里,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布程腹。 她就那樣靜靜地躺著匣吊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上色鸳,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天社痛,我揣著相機與錄音,去河邊找鬼命雀。 笑死蒜哀,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的吏砂。 我是一名探鬼主播撵儿,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼狐血!你這毒婦竟也來了淀歇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤氛雪,失蹤者是張志新(化名)和其女友劉穎房匆,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體报亩,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡浴鸿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了弦追。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片岳链。...
    茶點故事閱讀 40,567評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖劲件,靈堂內(nèi)的尸體忽然破棺而出掸哑,到底是詐尸還是另有隱情,我是刑警寧澤零远,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布苗分,位于F島的核電站,受9級特大地震影響牵辣,放射性物質(zhì)發(fā)生泄漏摔癣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一纬向、第九天 我趴在偏房一處隱蔽的房頂上張望择浊。 院中可真熱鬧,春花似錦逾条、人聲如沸琢岩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽担孔。三九已至江锨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間攒磨,已是汗流浹背泳桦。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留娩缰,地道東北人灸撰。 一個月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像拼坎,于是被迫代替她去往敵國和親浮毯。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,585評論 2 359

推薦閱讀更多精彩內(nèi)容