1. 程式人生 > >Android 獲取ROOT許可權原理解析

Android 獲取ROOT許可權原理解析

一、 概述

本文介紹了android中獲取root許可權的方法以及原理,讓大家對android玩家中常說的“越獄”有一個更深層次的認識。

二、 Root的介紹

1.       Root 的目的

可以讓我們擁有掌控手機系統的許可權,比如刪除一些system/app下面的無用軟體,更換開關機鈴聲和動畫,攔截狀態列彈出的廣告等。

2.       Root的原理介紹

谷歌的android系統管理員使用者就叫做root,該帳戶擁有整個系統至高無上的權利,它可以訪問和修改你手機幾乎所有的檔案,只有root才具備最高級別的管理許可權。我們root手機的過程也就是獲得手機最高使用許可權的過程。同時為了防止不良軟體也取得root

使用者的許可權,當我們在root的過程中,還會給系統裝一個程式,用來作為執行提示,由使用者來決定,是否給予最高許可權。這個程式的名字叫做Superuser.apk。當某些程式執行su指令想取得系統最高許可權的時候,Superuser就會自動啟動,攔截該動作並作出詢問,當用戶認為該程式可以安全使用的時候,那麼我們就選擇允許,否則,可以禁止該程式繼續取得最高許可權。Root的過程其實就是把su檔案放到/system/bin/ Superuser.apk 放到system/app下面,還需要設定/system/bin/su可以讓任意使用者可執行,有set uidset gid的許可權。即要在android機器上執行命令:adb shell chmod 4755 /system/bin/su
。而通常,廠商是不會允許我們隨便這麼去做的,我們就需要利用作業系統的各種漏洞,來完成這個過程。

特別說明:我們燒機中的Eng版本並沒有Root許可權

3.       Root的方法

Root的原理我們瞭解到,root過程分三步:

  1. a.        adb push su /system/bin  
  2. b.        adb push SuperUser.apk /system/app  
  3. c.       adb shell chmod 4755 /system/bin/su  

若系統是eng版的,做到以上三步,那麼我們Root就大功告成,但實際是不行的。為什麼呢?原因有三:

1user

版的/system路徑是隻讀許可權,不能簡單寫入

2 chmod需要Root權才能執行(死迴圈了)

3、有些系統在啟動時會自動將su4755許可權設成755,甚至直接刪除su

那麼針對這種情況,我們怎麼辦呢?非常簡單:燒一個eng版本的boot.img就行了

可以用展訊的燒錄工具,或者用fastboot模式從sd卡燒一個boot.img檔案即可

至此,我們Root就成功了,可以用R.E(Root Explorer)在根目錄建立和刪除檔案。

三、 深入理解Root機制

其流程是:

  1. 1.       Su 被使用者呼叫  
  2. 2.       Su 建立了一個socket監聽  
  3. 3.       Su 向Superuser傳送了一個廣播,說是有一個程式要請求root  
  4. 4.       Su 等待socket 資料接收。有超時處理。  
  5. 5.       Superuser 介面收到廣播後,彈出一個對話方塊,詢問使用者  
  6. 6.       Superuser 向傳來的資料中的socket寫回使用者應答結果。  
  7. 7.       Su 根據socket得到的結果處理應該不應該繼續執行  
  8. 8.       完成提權管理   

superuser.apk這個程式是root成功後,專門用來管理root許可權使用的,防止被惡意程式濫用。

我們有兩點疑問:

1.  superuser是怎麼知道誰想用root許可權?

2.  superuser是如何把使用者的選擇告訴su程式的?

superusersu程式是如何通訊的,他們倆位於不通的時空,一個在java虛擬中,一個在linux的真實程序中。

superuser共有兩個activity: SuperuserActivity SuperuserRequestActivity ,其中SuperuserActivity主要是用來管理白名單的,就是記住哪個程式已經被允許使用root許可權了,省的每次用時都問使用者。

SuperuserRequestActivity 就是用來詢問使用者目前有個程式想使用root許可權,是否允許,是否一直允許,即放入白名單。

這個白名單比較關鍵,是一個sqlite資料庫檔案,位置:

/data/data/com.koushikdutta.superuser/databases/superuser.sqlite

上文說過,root的本質就是往 /system/bin/下放一個su檔案,不檢查呼叫者許可權的su檔案。普通程式可以呼叫該su來執行root許可權的命令。superuser.apk中就自帶了一個這樣的su程式。一開始superuser會檢測/system/bin/su是否存在:

  1. File su = new File("/system/bin/su");  
  2. // 檢測su檔案是否存在,如果不存在則直接返回  
  3. if (!su.exists())  {  
  4. Toast toast = Toast.makeText(this, "Unable to find /system/bin/su.", Toast.LENGTH_LONG);  
  5. toast.show();  
  6. return;  
  7. }   
  8. //如果大小一樣,則認為su檔案正確,直接返回了事。  
  9. if (su.length() == suStream.available())   
  10. {  
  11.   suStream.close();   
  12.   return;   //  
  13. }   
  14. // 如果檢測到/system/bin/su檔案存在,但是不對頭,則把自帶的su先寫到"/data/data/com.koushikdutta.superuser/su"  
  15. //再寫到/system/bin/su。  
  16. byte[] bytes = new byte[suStream.available()];  
  17. DataInputStream dis = new DataInputStream(suStream);  
  18. dis.readFully(bytes);  
  19. FileOutputStream suOutStream = new FileOutputStream("/data/data/com.koushikdutta.superuser/su");  
  20.    suOutStream.write(bytes);  
  21.    suOutStream.close();  
  22.    Process process = Runtime.getRuntime().exec("su");  
  23.    DataOutputStream os = new DataOutputStream(process.getOutputStream());  
  24.    os.writeBytes("mount -oremount,rw /dev/block/mtdblock3 /system\n");  
  25.    os.writeBytes("busybox cp /data/data/com.koushikdutta.superuser/su /system/bin/su\n");  
  26.    os.writeBytes("busybox chown 0:0 /system/bin/su\n");  
  27.    os.writeBytes("chmod 4755 /system/bin/su\n");  
  28.    os.writeBytes("exit\n");  
  29.    os.flush();  

有程序使用root許可權,superuser是怎麼知道的呢,關鍵是句:

  1. sprintf(sysCmd, "am start -a android.intent.action.MAIN  
  2.                                     -n com.koushikdutta.superuser/com.koushikdutta.superuser.SuperuserRequestActivity  
  3.                                  --ei uid %d --ei pid %d > /dev/null", g_puid, ppid);  
  4.   if (system(sysCmd))  
  5.    return executionFailure("am.");  

原理是am命令,am的用法:

  1. usage: am [subcommand] [options]  
  2.    start an Activity: am start [-D] [-W] <INTENT>  
  3.        -D: enable debugging  
  4.        -W: wait for launch to complete  
  5.    start a Service: am startservice <INTENT>  
  6.    send a broadcast Intent: am broadcast <INTENT>  
  7.    start an Instrumentation: am instrument [flags] <COMPONENT>  
  8.        -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT)  
  9.        -e <NAME> <VALUE>: set argument <NAME> to <VALUE>  
  10.        -p <FILE>: write profiling data to <FILE>  
  11.        -w: wait for instrumentation to finish before returning  
  12.    start profiling: am profile <PROCESS> start <FILE>  
  13.    stop profiling: am profile <PROCESS> stop  
  14.    <INTENT> specifications include these flags:  
  15.        [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]  
  16.        [-c <CATEGORY> [-c <CATEGORY>] ...]  
  17.        [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]  
  18.        [--esn <EXTRA_KEY> ...]  
  19.        [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]  
  20.        [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]  
  21.        [-n <COMPONENT>] [-f <FLAGS>]  
  22.        [--grant-read-uri-permission] [--grant-write-uri-permission]  
  23.        [--debug-log-resolution]  
  24.        [--activity-brought-to-front] [--activity-clear-top]  
  25.        [--activity-clear-when-task-reset] [--activity-exclude-from-recents]  
  26.        [--activity-launched-from-history] [--activity-multiple-task]  
  27.        [--activity-no-animation] [--activity-no-history]  
  28.        [--activity-no-user-action] [--activity-previous-is-top]  
  29.        [--activity-reorder-to-front] [--activity-reset-task-if-needed]  
  30.        [--activity-single-top]  
  31.        [--receiver-registered-only] [--receiver-replace-pending]  
  32.        [<URI>]<span style="font-family:Calibri;font-size:14px;"> </span>  

還有個疑點,就是su怎麼知道使用者是允許root許可權還是反對呢?原來是上面提到的白名單起來作用,superuser把使用者的選擇放入:

/data/data/com.koushikdutta.superuser/databases/superuser.sqlite   資料庫中,然後su程序再去讀該資料庫來判斷是否允許。

  1. static int checkWhitelist()  
  2. {  
  3.  sqlite3 *db;  
  4.  int rc = sqlite3_open_v2(DBPATH, &db, SQLITE_OPEN_READWRITE, NULL);  
  5.  if (!rc)  
  6.  {  
  7.   char *errorMessage;  
  8.   char query[1024];  
  9.   sprintf(query, "select * from whitelist where _id=%d limit 1;", g_puid);  
  10.   struct whitelistCallInfo callInfo;  
  11.   callInfo.count = 0;  
  12.   callInfo.db = db;  
  13.   rc = sqlite3_exec(db, query, whitelistCallback, &callInfo, &errorMessage);  
  14.   if (rc != SQLITE_OK)  
  15.   {  
  16.    sqlite3_close(db);  
  17.    return 0;  
  18.   }  
  19.   sqlite3_close(db);  
  20.   return callInfo.count;  
  21.  }  
  22.  sqlite3_close(db);  
  23.  return 0;  
  24. }   

四、 資原始檔的獲取

從上文的原始碼地址獲取原始碼,替換系統的system/extras/su/下面的su.cAndroid.mk檔案,使用編譯命令 ./mk td28 u adr system/extras/su/編譯成功後會生成out/target/product/hsdroid/system/xbin/su檔案,而Superuser.apk就是普通的apk檔案,都在原始碼地址裡面可以下載,下載後倒入到eclipse即可直接執行。

五、 總結

在閱讀完本文後,可以站在專業的角度瞭解root的真正原理,以及有使用者有需求時我們可以幫助其快速的解決問題。