Root原理分析及防Root新思路

第1章 Root的基本原理

Android的內核就是Linux,所以Android獲取root其實和Linux獲取root權限是一回事兒。

你想在Linux下獲取root權限的時候就是執行sudo或者su,接下來系統會提示你輸入root用戶的密碼,密碼正確就獲得root權限了。Android本身就不想讓你獲得Root權限,大部分手機出廠的時候根本就沒有su這個程序。所以你想獲得Android的root權限,第一步就是要把編譯好的su文件拷貝到Android手機的/system/bin或者/system/xbin/目錄下。我們先假設你可以把su放在xbin下,接下來你可以在Android手機的adb shell或者串口下輸入su了。

Linux下su以後輸入密碼就可以root了,但Android裏的su和Linux裏的su是不一樣的,Android裏的su不是靠驗證密碼的,而是看你原來的權限是什麼。意思就是如果你是root,那你可以通過su切換到別的用戶,比如說shell,wifi,audio什麼的。但如果你是root之外的其他用戶,就不能切換回root了,會提示你permission denied。(具體su是怎麼做到這一點的,我準備過幾天有時間的時候寫在下面,單獨說明)

也就說用root運行su纔有用,但我這個時候還沒有root怎麼辦呢?這就涉及到另外個問題。

一般我們在Linux的console下輸入ls -l 會列出所有文件的權限。

比如:-rwxr-xr-x,用過Linux的人都知道r代表該文件可讀,w代表可寫,x代表可執行,-就代表沒有該權限。第一個rwx代表文件所有者的權限,第二個rwx代表和所有者同組人的權限,第三個rwx代表其他用戶對該文件的權限。但下面這個文件就比較特殊。

rws,它的執行權限標誌位是一個s,s代表當任何一個用戶執行該文件的時候都擁有文件所有者的權限,這文件的所有者是root,簡單點說就是不管誰執行這個文件,他執行的時候都是以root身份執行的。

也就說即使我不是root也有可能以root身份來執行程序,那麼我就把一個所有者是root的su程序權限標誌位置成-rwsr-xr-x,那麼不管誰執行它,都是root身份執行,su就可以順利執行成功了,執行成功之後我就是root身份了。

問題都清楚了,就是你需要把一個所有者是root的su拷貝到Android手機上,並且把su的權限標誌位置成-rwsr-xr-x。能把這個事情搞定你就成功root了一個手機。

大概意思就是兩行代碼

 

cp /data/tmp/su /system/bin/ #copy su 到/system/分區
chown root:root su #su的所有者置成root
chmod 4775 /system/bin/su #把su置成-rwsr-xr-x

然而,執行上面的每一行代碼都需要root權限才能成功。

意思就是說,你只有有root權限的情況下才能執行上面兩行代碼,而這兩行代碼就是爲了讓你獲得root權限的,這是一個邏輯閉環,那麼如何打破這個邏輯閉環呢?

一個辦法就是找一個本身已經有root權限的進程來啓動我上面的兩行代碼,那我這兩行代碼一啓動就是root權限,就可以順利執行了。但是已經有root權限的進程都是出廠時候就裝到手機上的,代碼寫死了,你沒法控制它執行你自己的代碼啊。這個時候就需要你找漏洞了,比如用來破解Android2.3 root權限的zergRush漏洞就是利用一個擁有root權限的進程棧溢出漏洞。

第2章 Root的由來

什麼是Root?

Root本身是指Linux系統的root帳戶,該帳戶擁有整個系統至高無上的權利,系統中的所有對象它都可以操作,對於Android手機用戶來說的Root是指擁有Root權限,一般情況下,手機廠商出於安全考慮會關閉手機的Root權限,手機系統是運行在普通用戶權限下的,用戶是無法操作系統中的文件與數據的。

Root與刷機本身是有很多關聯的,而且隨着刷機工具的便利與刷機原理的變化,兩者的關係更加是模糊不清了。不同廠商針對獲取Root權限設置了不同的要塞。

首先從刷機說起,如HTC手機在刷機前需要保證S-OFF,S-OFF代表什麼呢?S代表SecurityLock安全鎖,保護鎖的意思,S-OFF就是關掉鎖保護。然後是Motorola的手機,這個廠商對於不同型號的手機設置是不同的,很多Motorola型號的手機將BootLoader是鎖住的,因此,在刷機前需要先解鎖BootLoader。還有中興手機,這廠商更是變態,一次次的版本升級只是爲了鎖住用戶不讓用戶升級,也就導致了同一型號的手機由於版本不同有的型號帶Recovery,有的又不帶。三星的手機現在可以說是最好賣的,一方面是出色的硬件配置與外觀,另一方面是有衆多的Rom包可以刷。三星的好幾款手機是Google源碼的測試樣機,而且三星手機在出廠時對用戶的限制相比其它品牌是較少的,這也是廣大Android開發者對它青睞有加的原因。

早先的Android手機要想獲取Root權限可以有以下幾種方式:

1)使用本地提權漏洞利用工具來直接Root,這是最原始最純潔的方式。隨着廠商對Rom的升級,這些內核的漏洞隨時都可能被修補,因此,這種Root方法在時間與空間上都有着很大的侷限性。

2)由於手機廠商對硬件的封閉,加上內核補丁修補很完全,這個時候獲取Root權限就更難了,這個時候刷機與Root就聯合起來了,由於不能從系統內部通過Exploits來獲取Root權限,只能通過修改Rom包來達到Root的目的,這也是目前很多第三方Rom包自帶了Root的原因,然而手機廠商也不是喫乾飯的,手機廠商在OTA升級時使用Recovery對包簽名進行驗證來防止用戶刷入修改過的包。對於這種變態的廠商,只能通過FastBoot來線刷了,這裏內容就不再展開了。

3)當然,還有一部分廠商,爲了吸引更多用戶購買他們的手機,還是在手機中偷偷的留了後門的,比如不鎖BootLoader,讓用戶刷第三方的Recovery,又或是乾脆留個以前的漏洞不補,讓用戶自己來Exploits等等

 

第3章 RageAgainstTheCage漏洞分析

假設需要破解的Android系統具備如下條件:

1)可以通過adb連接到設備,一般意味着驅動程序已經安裝。 
2)但是adb獲得用戶權限是shell用戶,而不是root。

要想理解root破解過程我們首先需要了解一下adb工具,SDK中包含adb工具,設備端有adbd服務程序後臺運行,爲開發機的adb程序提供服務,adbd的權限,決定了adb的權限。具體用戶可查看/system/core/adb下的源碼,查看Android.mk你將會發現adb和adbd其實是一份代碼,然後通過宏來編譯。

查看adb.c的adb_main函數你將會發現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會檢測系統的ro.secure屬性,如果該屬性爲1則將會把自己的用戶權限降級成shell用戶。一般設備出廠的時候在/default.prop文件中都會有:

1: ro.secure=1

這樣將會使adbd啓動的時候自動降級成shell用戶。

然後我們再介紹一下adbd在什麼時候啓動的呢?答案是在init.rc中配置的系統服務,由init進程啓動。我們查看init.rc中有如下內容:

 

   # adbd is controlled by the persist.service.adb.enable system property
   service adbd /sbin/adbd
       disabled

對Android屬性系統少有了解的朋友將會知道,在init.rc中配置的系統服務啓動的時候都是root權限(因爲init進行是root權限,其子程序也是root)。由此我們可以知道在adbd程序在執行:

 

   /* then switch user and group to "shell" */
   setgid(AID_SHELL);
   setuid(AID_SHELL);

代碼之前都是root權限,只有執行這兩句之後才變成shell權限的。

這樣我們就可以引出root破解過程中獲得root權限的方法了,那就是讓以上面setgid和setuid函數執行失敗,也就是降級失敗,那就繼續在root權限下面運行了。

這其實利用了一個RageAgainstTheCage漏洞,具體分析請參考《 Android adb setuid提權漏洞的分析》和《 RageAgainstTheCage》。這裏面做一個簡單說明:

1)出廠設置的ro.secure屬性爲1,則adbd也將運行在shell用戶權限下 
2)adb工具創建的進程ratc也運行在shell用戶權限下;

3)ratc一直創建子進程(ratc創建的子程序也將會運行在shell用戶權限下),緊接着子程序退出,形成殭屍進程,佔用shell用戶的進程資源,直到到達shell用戶的進程數爲RLIMIT_NPROC的時候(包括adbd、ratc及其子程序),這是ratc將會創建子進程失敗。這時候殺掉adbd,adbd進程因爲是Android系統服務,將會被Android系統自動重啓,這時候ratc也在競爭產生子程序。在adbd程序執行上面setgid和setuid之前,ratc已經創建了一個新的子進程,那麼shell用戶的進程限額已經達到,則adbd進程執行setgid和setuid將會失敗。根據代碼我們發現失敗之後adbd將會繼續執行。這樣adbd進程將會運行在root權限下面了。 
4)這時重新用adb連接設備,則adb將會運行在root權限下面了。

通過上面的介紹我們發現利用RageAgainstTheCage漏洞,可以使adbd獲得root權限,也就是adb獲得了root權限。拿到root權限剩下的問題就好辦了,複製破解之後的su程序到系統中,都是沒有什麼技術含量的事情了。

其實堵住adbd的這個漏洞其實也挺簡單的:

 

   /* then switch user and group to "shell" */
   if (setgid(AID_SHELL) != 0) {
       exit(1);
   }
   if (setuid(AID_SHELL) != 0) {
       exit(1);
   }

如果發現setgid和setuid函數執行失敗,則adbd進程異常退出,就把這個漏洞給堵上了。爲什麼這麼多設備都沒有堵上這個漏洞呢?我覺得是設備廠商的策略(不排除傻X的廠商存在哦),雖然知道怎麼封堵漏洞但是就是留着個後門給大家,讓第三方給自己定製rom,提高自己系統的易用性。

 

第4章 Superuser與su如何協作

su與SuperUser.apk是如何協作的

   在Root後手機會植入su與superuser.apk兩個文件,前者會被放入手機的/system/bin目錄下,後者被放到/system/app目錄下,它們組合在一起,爲系統提供了su權限的管理。這兩個工具目前由xda論壇上的ChainsDD在維護(順便說一下,國內xxRoot工具也有自已的su與SuperUser.apk文件,修改取自並修改於ChainsDD的代碼,並且版權被切)。

   su程序與Linux平臺上的su本身無太大差別,只是由於系統的特殊性去掉了部分內容,並加上了一些控制代碼。su程序保留的命令行參數不多,"-c"與"-s"可能是最常用的,整個程序核心功能由兩個方向性的函數allow()與deny()組成,在經過計算獲取到了命令行參數與命令後,會執行以下代碼:

 

   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權限,程序直接放行,stat()函數會檢查手機是否安裝有SuperUser.apk,沒有程序會拒絕執行。條件滿足就會以Superuser的權限往下執行:

 

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()負責從SuperUser.apk程序databases目錄下的permissions.sqlite數據庫中讀取權限設置,這也是爲什麼SuperUser.apk有能力控制su的原因!(人家主動找上門的)等dballow弄到手,該放行該拒絕就看着辦了,如果沒搜索到記錄就代表是第一次,需要往下建立socket來send_intent,send_intent()採用底層構造Intent方式來發送廣播,這個廣播會被SuperUser.apk接收,等返回後會給你返回個字符串”ALLOW”或”DENY”,這時候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的工作了,上面的廣播會被SuperUser.apk的SuRequestReceiver廣播接收者收到,廣播接收者首先讀取prompt設置,如果用戶要的是自動處理,那就根據這個值來對Root權限請求自動拒絕或自動放行,如果不自動處理,就到數據庫中搜索權限規則,並根據結果發回處理,另外SuperUser除了對普通的程序進程su權限控制外,還提供了NFC、SecretCode、PinCode的監控,SuperUser同時註冊了安裝與卸載Apk的廣播接收者,在安裝與卸載時會對權限數據庫中的條目進行更新或刪除操作,限於篇幅,SuperUser的詳細實現在此就不再展開了。

第5章 防Root新思路(未驗證):使用Chattr命令

原文: http://zhangge.net/1017.html

Linux下的文件除了權限屬性,還有一些隱藏屬性,使用lsattr來顯示,如果要設置文件的隱藏屬性,需要使用chattr命令。

 

結果中第一列是13個短橫杆,其中每一個橫杆都是一個屬性,如果當前位置上設置了該屬性就會顯示相對應的字符。

一種比較常見的屬性是i屬性。設置了這種屬性的文件將無法【寫入、改名、刪除】,即使是root用戶也不行。這種屬性常用於設置在系統或者關鍵服務中的配置文件,這對提升系統安全性有很大幫助。

Ubuntu環境測試:

1)正常通過touch可以創建,rm可以刪除。

 

2)如果通過chattr +i test.txt,則在調用chattr –I test.txt之前不可刪除、移動、修改內容。

 

思考:借用windows環境下U盤防木馬的思路,通過預置一個不可用不可改的su文件,使得Root類程序在尚不知道我們所採用的方式之前,無法修改我們的su文件,達到無法調用su以獲得永久root權限的目的。

可行性:

1)”chattr命令是用來去除文件的EXT2_IMMUTABLE_FL標誌位。如果系統分區使用ext文件系統的話,病毒會給所有受感染的文件設置此標誌位” ——《Android.KungFu手機病毒清理方法》

2)

 

第6章 零散的知識

1)阿里雲系統,su是個文件夾,要刪除了才能root,現在只是終端能提權
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章