原地址:http://blog.csdn.net/hsluoyc/article/details/50560782
防止原地址不能使用随闪,我就ctrl + v
第1章 Root的基本原理
Android的內(nèi)核就是Linux姥闪,所以Android獲取root其實(shí)和Linux獲取root權(quán)限是一回事兒原茅。
你想在Linux下獲取root權(quán)限的時(shí)候就是執(zhí)行sudo或者su窖逗,接下來(lái)系統(tǒng)會(huì)提示你輸入root用戶(hù)的密碼均芽,密碼正確就獲得root權(quán)限了忘苛。Android本身就不想讓你獲得Root權(quán)限,大部分手機(jī)出廠的時(shí)候根本就沒(méi)有su這個(gè)程序丙者。所以你想獲得Android的root權(quán)限,第一步就是要把編譯好的su文件拷貝到Android手機(jī)的/system/bin或者/system/xbin/目錄下营密。我們先假設(shè)你可以把su放在xbin下械媒,接下來(lái)你可以在Android手機(jī)的adb shell或者串口下輸入su了。
Linux下su以后輸入密碼就可以root了评汰,但Android里的su和Linux里的su是不一樣的纷捞,Android里的su不是靠驗(yàn)證密碼的,而是看你原來(lái)的權(quán)限是什么被去。意思就是如果你是root主儡,那你可以通過(guò)su切換到別的用戶(hù),比如說(shuō)shell,wifi,audio什么的编振。但如果你是root之外的其他用戶(hù)缀辩,就不能切換回root了臭埋,會(huì)提示你permission denied踪央。(具體su是怎么做到這一點(diǎn)的,我準(zhǔn)備過(guò)幾天有時(shí)間的時(shí)候?qū)懺谙旅嫫耙酰瑔为?dú)說(shuō)明)
也就說(shuō)用root運(yùn)行su才有用畅蹂,但我這個(gè)時(shí)候還沒(méi)有root怎么辦呢?這就涉及到另外個(gè)問(wèn)題荣恐。
一般我們?cè)贚inux的console下輸入ls -l 會(huì)列出所有文件的權(quán)限液斜。
比如:-rwxr-xr-x,用過(guò)Linux的人都知道r代表該文件可讀叠穆,w代表可寫(xiě)少漆,x代表可執(zhí)行,-就代表沒(méi)有該權(quán)限硼被。第一個(gè)rwx代表文件所有者的權(quán)限示损,第二個(gè)rwx代表和所有者同組人的權(quán)限蟀俊,第三個(gè)rwx代表其他用戶(hù)對(duì)該文件的權(quán)限祥楣。但下面這個(gè)文件就比較特殊。
rws筐咧,它的執(zhí)行權(quán)限標(biāo)志位是一個(gè)s仔掸,s代表當(dāng)任何一個(gè)用戶(hù)執(zhí)行該文件的時(shí)候都擁有文件所有者的權(quán)限脆贵,這文件的所有者是root,簡(jiǎn)單點(diǎn)說(shuō)就是不管誰(shuí)執(zhí)行這個(gè)文件起暮,他執(zhí)行的時(shí)候都是以root身份執(zhí)行的卖氨。
也就說(shuō)即使我不是root也有可能以root身份來(lái)執(zhí)行程序,那么我就把一個(gè)所有者是root的su程序權(quán)限標(biāo)志位置成-rwsr-xr-x,那么不管誰(shuí)執(zhí)行它筒捺,都是root身份執(zhí)行持搜,su就可以順利執(zhí)行成功了,執(zhí)行成功之后我就是root身份了焙矛。
問(wèn)題都清楚了葫盼,就是你需要把一個(gè)所有者是root的su拷貝到Android手機(jī)上,并且把su的權(quán)限標(biāo)志位置成-rwsr-xr-x村斟。能把這個(gè)事情搞定你就成功root了一個(gè)手機(jī)贫导。
大概意思就是兩行代碼
cp /data/tmp/su /system/bin/ #copy su 到/system/分區(qū)
chown root:root su #su的所有者置成root
chmod 4775 /system/bin/su #把su置成-rwsr-xr-x
然而,執(zhí)行上面的每一行代碼都需要root權(quán)限才能成功蟆盹。
意思就是說(shuō)孩灯,你只有有root權(quán)限的情況下才能執(zhí)行上面兩行代碼,而這兩行代碼就是為了讓你獲得root權(quán)限的逾滥,這是一個(gè)邏輯閉環(huán)峰档,那么如何打破這個(gè)邏輯閉環(huán)呢?
一個(gè)辦法就是找一個(gè)本身已經(jīng)有root權(quán)限的進(jìn)程來(lái)啟動(dòng)我上面的兩行代碼寨昙,那我這兩行代碼一啟動(dòng)就是root權(quán)限讥巡,就可以順利執(zhí)行了。但是已經(jīng)有root權(quán)限的進(jìn)程都是出廠時(shí)候就裝到手機(jī)上的舔哪,代碼寫(xiě)死了欢顷,你沒(méi)法控制它執(zhí)行你自己的代碼啊。這個(gè)時(shí)候就需要你找漏洞了捉蚤,比如用來(lái)破解Android2.3 root權(quán)限的zergRush漏洞就是利用一個(gè)擁有root權(quán)限的進(jìn)程棧溢出漏洞抬驴。
第2章 Root的由來(lái)
什么是Root?
Root本身是指Linux系統(tǒng)的root帳戶(hù),該帳戶(hù)擁有整個(gè)系統(tǒng)至高無(wú)上的權(quán)利缆巧,系統(tǒng)中的所有對(duì)象它都可以操作布持,對(duì)于Android手機(jī)用戶(hù)來(lái)說(shuō)的Root是指擁有Root權(quán)限,一般情況下陕悬,手機(jī)廠商出于安全考慮會(huì)關(guān)閉手機(jī)的Root權(quán)限题暖,手機(jī)系統(tǒng)是運(yùn)行在普通用戶(hù)權(quán)限下的,用戶(hù)是無(wú)法操作系統(tǒng)中的文件與數(shù)據(jù)的墩莫。
Root與刷機(jī)本身是有很多關(guān)聯(lián)的芙委,而且隨著刷機(jī)工具的便利與刷機(jī)原理的變化,兩者的關(guān)系更加是模糊不清了狂秦。不同廠商針對(duì)獲取Root權(quán)限設(shè)置了不同的要塞灌侣。
首先從刷機(jī)說(shuō)起,如HTC手機(jī)在刷機(jī)前需要保證S-OFF裂问,S-OFF代表什么呢侧啼?S代表SecurityLock安全鎖牛柒,保護(hù)鎖的意思,S-OFF就是關(guān)掉鎖保護(hù)痊乾。然后是Motorola的手機(jī)皮壁,這個(gè)廠商對(duì)于不同型號(hào)的手機(jī)設(shè)置是不同的,很多Motorola型號(hào)的手機(jī)將BootLoader是鎖住的哪审,因此蛾魄,在刷機(jī)前需要先解鎖BootLoader。還有中興手機(jī)湿滓,這廠商更是變態(tài)滴须,一次次的版本升級(jí)只是為了鎖住用戶(hù)不讓用戶(hù)升級(jí),也就導(dǎo)致了同一型號(hào)的手機(jī)由于版本不同有的型號(hào)帶Recovery叽奥,有的又不帶扔水。三星的手機(jī)現(xiàn)在可以說(shuō)是最好賣(mài)的,一方面是出色的硬件配置與外觀朝氓,另一方面是有眾多的Rom包可以刷魔市。三星的好幾款手機(jī)是Google源碼的測(cè)試樣機(jī),而且三星手機(jī)在出廠時(shí)對(duì)用戶(hù)的限制相比其它品牌是較少的赵哲,這也是廣大Android開(kāi)發(fā)者對(duì)它青睞有加的原因待德。
早先的Android手機(jī)要想獲取Root權(quán)限可以有以下幾種方式:
1)使用本地提權(quán)漏洞利用工具來(lái)直接Root,這是最原始最純潔的方式誓竿。隨著廠商對(duì)Rom的升級(jí)磅网,這些內(nèi)核的漏洞隨時(shí)都可能被修補(bǔ)谈截,因此筷屡,這種Root方法在時(shí)間與空間上都有著很大的局限性。
2)由于手機(jī)廠商對(duì)硬件的封閉簸喂,加上內(nèi)核補(bǔ)丁修補(bǔ)很完全毙死,這個(gè)時(shí)候獲取Root權(quán)限就更難了,這個(gè)時(shí)候刷機(jī)與Root就聯(lián)合起來(lái)了喻鳄,由于不能從系統(tǒng)內(nèi)部通過(guò)Exploits來(lái)獲取Root權(quán)限扼倘,只能通過(guò)修改Rom包來(lái)達(dá)到Root的目的,這也是目前很多第三方Rom包自帶了Root的原因除呵,然而手機(jī)廠商也不是吃干飯的再菊,手機(jī)廠商在OTA升級(jí)時(shí)使用Recovery對(duì)包簽名進(jìn)行驗(yàn)證來(lái)防止用戶(hù)刷入修改過(guò)的包。對(duì)于這種變態(tài)的廠商颜曾,只能通過(guò)FastBoot來(lái)線(xiàn)刷了纠拔,這里內(nèi)容就不再展開(kāi)了。
3)當(dāng)然泛豪,還有一部分廠商稠诲,為了吸引更多用戶(hù)購(gòu)買(mǎi)他們的手機(jī)侦鹏,還是在手機(jī)中偷偷的留了后門(mén)的,比如不鎖BootLoader臀叙,讓用戶(hù)刷第三方的Recovery略水,又或是干脆留個(gè)以前的漏洞不補(bǔ),讓用戶(hù)自己來(lái)Exploits等等
第3章 RageAgainstTheCage漏洞分析
假設(shè)需要破解的Android系統(tǒng)具備如下條件:
1)可以通過(guò)adb連接到設(shè)備劝萤,一般意味著驅(qū)動(dòng)程序已經(jīng)安裝渊涝。
2)但是adb獲得用戶(hù)權(quán)限是shell用戶(hù),而不是root床嫌。
要想理解root破解過(guò)程我們首先需要了解一下adb工具驶赏,SDK中包含adb工具,設(shè)備端有adbd服務(wù)程序后臺(tái)運(yùn)行既鞠,為開(kāi)發(fā)機(jī)的adb程序提供服務(wù)煤傍,adbd的權(quán)限,決定了adb的權(quán)限嘱蛋。具體用戶(hù)可查看/system/core/adb下的源碼蚯姆,查看Android.mk你將會(huì)發(fā)現(xiàn)adb和adbd其實(shí)是一份代碼,然后通過(guò)宏來(lái)編譯洒敏。
查看adb.c的adb_main函數(shù)你將會(huì)發(fā)現(xiàn)adbd中有如下代碼:
int adb\_main(int is\_daemon)
{
......
property\_get("ro.secure", value, "");
if (strcmp(value, "1") == 0) {
// don't run as root if ro.secure is set...
secure = 1;
......
}
if (secure) {
......
setgid(AID\_SHELL);
setuid(AID\_SHELL);
......
}
}
從中我們可以看到adbd會(huì)檢測(cè)系統(tǒng)的ro.secure屬性龄恋,如果該屬性為1則將會(huì)把自己的用戶(hù)權(quán)限降級(jí)成shell用戶(hù)。一般設(shè)備出廠的時(shí)候在/default.prop文件中都會(huì)有:
1: ro.secure=1
這樣將會(huì)使adbd啟動(dòng)的時(shí)候自動(dòng)降級(jí)成shell用戶(hù)凶伙。
然后我們?cè)俳榻B一下adbd在什么時(shí)候啟動(dòng)的呢郭毕?答案是在init.rc中配置的系統(tǒng)服務(wù),由init進(jìn)程啟動(dòng)函荣。我們查看init.rc中有如下內(nèi)容:
# adbd is controlled by the persist.service.adb.enable system property
service adbd /sbin/adbd
disabled
對(duì)Android屬性系統(tǒng)少有了解的朋友將會(huì)知道显押,在init.rc中配置的系統(tǒng)服務(wù)啟動(dòng)的時(shí)候都是root權(quán)限(因?yàn)閕nit進(jìn)行是root權(quán)限,其子程序也是root)傻挂。由此我們可以知道在adbd程序在執(zhí)行:
/* then switch user and group to "shell" */
setgid(AID_SHELL);
setuid(AID_SHELL);
代碼之前都是root權(quán)限乘碑,只有執(zhí)行這兩句之后才變成shell權(quán)限的。
這樣我們就可以引出root破解過(guò)程中獲得root權(quán)限的方法了金拒,那就是讓以上面setgid和setuid函數(shù)執(zhí)行失敗兽肤,也就是降級(jí)失敗,那就繼續(xù)在root權(quán)限下面運(yùn)行了绪抛。
這其實(shí)利用了一個(gè)RageAgainstTheCage漏洞资铡,具體分析請(qǐng)參考《 Android adb setuid提權(quán)漏洞的分析》和《 RageAgainstTheCage》。這里面做一個(gè)簡(jiǎn)單說(shuō)明:
1)出廠設(shè)置的ro.secure屬性為1幢码,則adbd也將運(yùn)行在shell用戶(hù)權(quán)限下
2)adb工具創(chuàng)建的進(jìn)程ratc也運(yùn)行在shell用戶(hù)權(quán)限下笤休;
3)ratc一直創(chuàng)建子進(jìn)程(ratc創(chuàng)建的子程序也將會(huì)運(yùn)行在shell用戶(hù)權(quán)限下),緊接著子程序退出蛤育,形成僵尸進(jìn)程宛官,占用shell用戶(hù)的進(jìn)程資源葫松,直到到達(dá)shell用戶(hù)的進(jìn)程數(shù)為RLIMIT_NPROC的時(shí)候(包括adbd、ratc及其子程序)底洗,這是ratc將會(huì)創(chuàng)建子進(jìn)程失敗腋么。這時(shí)候殺掉adbd,adbd進(jìn)程因?yàn)槭茿ndroid系統(tǒng)服務(wù)亥揖,將會(huì)被Android系統(tǒng)自動(dòng)重啟珊擂,這時(shí)候ratc也在競(jìng)爭(zhēng)產(chǎn)生子程序。在adbd程序執(zhí)行上面setgid和setuid之前费变,ratc已經(jīng)創(chuàng)建了一個(gè)新的子進(jìn)程摧扇,那么shell用戶(hù)的進(jìn)程限額已經(jīng)達(dá)到,則adbd進(jìn)程執(zhí)行setgid和setuid將會(huì)失敗挚歧。根據(jù)代碼我們發(fā)現(xiàn)失敗之后adbd將會(huì)繼續(xù)執(zhí)行扛稽。這樣adbd進(jìn)程將會(huì)運(yùn)行在root權(quán)限下面了。
4)這時(shí)重新用adb連接設(shè)備滑负,則adb將會(huì)運(yùn)行在root權(quán)限下面了在张。
通過(guò)上面的介紹我們發(fā)現(xiàn)利用RageAgainstTheCage漏洞,可以使adbd獲得root權(quán)限矮慕,也就是adb獲得了root權(quán)限帮匾。拿到root權(quán)限剩下的問(wèn)題就好辦了,復(fù)制破解之后的su程序到系統(tǒng)中痴鳄,都是沒(méi)有什么技術(shù)含量的事情了瘟斜。
其實(shí)堵住adbd的這個(gè)漏洞其實(shí)也挺簡(jiǎn)單的:
/* then switch user and group to "shell" */
if (setgid(AID_SHELL) != 0) {
exit(1);
}
if (setuid(AID_SHELL) != 0) {
exit(1);
}
如果發(fā)現(xiàn)setgid和setuid函數(shù)執(zhí)行失敗,則adbd進(jìn)程異常退出痪寻,就把這個(gè)漏洞給堵上了螺句。為什么這么多設(shè)備都沒(méi)有堵上這個(gè)漏洞呢?我覺(jué)得是設(shè)備廠商的策略(不排除傻X的廠商存在哦)槽华,雖然知道怎么封堵漏洞但是就是留著個(gè)后門(mén)給大家壹蔓,讓第三方給自己定制rom,提高自己系統(tǒng)的易用性猫态。
第4章 Superuser與su如何協(xié)作
su與SuperUser.apk是如何協(xié)作的
在Root后手機(jī)會(huì)植入su與superuser.apk兩個(gè)文件,前者會(huì)被放入手機(jī)的/system/bin目錄下披摄,后者被放到/system/app目錄下亲雪,它們組合在一起,為系統(tǒng)提供了su權(quán)限的管理疚膊。這兩個(gè)工具目前由xda論壇上的ChainsDD在維護(hù)(順便說(shuō)一下义辕,國(guó)內(nèi)xxRoot工具也有自已的su與SuperUser.apk文件,修改取自并修改于ChainsDD的代碼寓盗,并且版權(quán)被切)灌砖。 su程序與Linux平臺(tái)上的su本身無(wú)太大差別璧函,只是由于系統(tǒng)的特殊性去掉了部分內(nèi)容,并加上了一些控制代碼基显。su程序保留的命令行參數(shù)不多蘸吓,"-c"與"-s"可能是最常用的,整個(gè)程序核心功能由兩個(gè)方向性的函數(shù)allow()與deny()組成撩幽,在經(jīng)過(guò)計(jì)算獲取到了命令行參數(shù)與命令后库继,會(huì)執(zhí)行以下代碼:
if(su_from.uid == AID\_ROOT || su_from.uid == AID_SHELL)
allow(shell, orig_umask);
if (stat(REQUESTOR_DATA_PATH, &st) < 0) {
PLOGE("stat");
deny();
}
……
setgroups(0, NULL);
setegid(st.st_gid);
seteuid(st.st_uid);
AID_ROOT與AID_SHELL分別是root與shell權(quán)限,程序直接放行窜醉,stat()函數(shù)會(huì)檢查手機(jī)是否安裝有SuperUser.apk宪萄,沒(méi)有程序會(huì)拒絕執(zhí)行。條件滿(mǎn)足就會(huì)以Superuser的權(quán)限往下執(zhí)行:
db =database_init();
if (!db) {
LOGE("sudb - Could not open database,prompt user");
dballow = DB_INTERACTIVE;
} else {
LOGE("sudb - Database opened");
dballow = database_check(db, &su_from,&su_to);
sqlite3_close(db);
db = NULL;
LOGE("sudb - Database closed");
}
switch (dballow){
case DB_DENY: deny();
case DB_ALLOW: allow(shell,orig_umask);
case DB_INTERACTIVE: break;
default: deny();
}
database_init()與database_check()負(fù)責(zé)從SuperUser.apk程序databases目錄下的permissions.sqlite數(shù)據(jù)庫(kù)中讀取權(quán)限設(shè)置榨惰,這也是為什么SuperUser.apk有能力控制su的原因0萦ⅰ(人家主動(dòng)找上門(mén)的)等dballow弄到手,該放行該拒絕就看著辦了琅催,如果沒(méi)搜索到記錄就代表是第一次聊记,需要往下建立socket來(lái)send_intent,send_intent()采用底層構(gòu)造Intent方式來(lái)發(fā)送廣播恢暖,這個(gè)廣播會(huì)被SuperUser.apk接收排监,等返回后會(huì)給你返回個(gè)字符串”ALLOW”或”DENY”,這時(shí)候su程序該咋地就咋地了:
if(send_intent(&su_from, &su_to, socket_path, -1, 0) < 0) {
deny();
}
if(socket_receive_result(socket_serv_fd, buf, sizeof(buf)) < 0) {
deny();
}
……
if (!strcmp(result, "DENY")) {
deny();
} else if(!strcmp(result, "ALLOW")) {
allow(shell, orig_umask);
} else {
LOGE("unknown response from SuperuserRequestor: %s", result);
deny();
}
下面是SuperUser.apk的工作了杰捂,上面的廣播會(huì)被SuperUser.apk的SuRequestReceiver廣播接收者收到舆床,廣播接收者首先讀取prompt設(shè)置,如果用戶(hù)要的是自動(dòng)處理嫁佳,那就根據(jù)這個(gè)值來(lái)對(duì)Root權(quán)限請(qǐng)求自動(dòng)拒絕或自動(dòng)放行挨队,如果不自動(dòng)處理,就到數(shù)據(jù)庫(kù)中搜索權(quán)限規(guī)則蒿往,并根據(jù)結(jié)果發(fā)回處理盛垦,另外SuperUser除了對(duì)普通的程序進(jìn)程su權(quán)限控制外,還提供了NFC瓤漏、SecretCode腾夯、PinCode的監(jiān)控,SuperUser同時(shí)注冊(cè)了安裝與卸載Apk的廣播接收者蔬充,在安裝與卸載時(shí)會(huì)對(duì)權(quán)限數(shù)據(jù)庫(kù)中的條目進(jìn)行更新或刪除操作蝶俱,限于篇幅,SuperUser的詳細(xì)實(shí)現(xiàn)在此就不再展開(kāi)了饥漫。