Android 獲取ROOT許可權原理解析
一、 概述
本文介紹了android中獲取root許可權的方法以及原理,讓大家對android玩家中常說的“越獄”有一個更深層次的認識。
二、 Root的介紹
1. Root 的目的
可以讓我們擁有掌控手機系統的許可權,比如刪除一些system/app下面的無用軟體,更換開關機鈴聲和動畫,攔截狀態列彈出的廣告等。
2. Root的原理介紹
谷歌的android系統管理員使用者就叫做root,該帳戶擁有整個系統至高無上的權利,它可以訪問和修改你手機幾乎所有的檔案,只有root才具備最高級別的管理許可權。我們root手機的過程也就是獲得手機最高使用許可權的過程。同時為了防止不良軟體也取得root
特別說明:我們燒機中的Eng版本並沒有Root許可權
3. Root的方法
從Root的原理我們瞭解到,root過程分三步:
- a. adb push su /system/bin
- b. adb push SuperUser.apk /system/app
- c. adb shell chmod 4755 /system/bin/su
若系統是eng版的,做到以上三步,那麼我們Root就大功告成,但實際是不行的。為什麼呢?原因有三:
1、user
2、 chmod需要Root權才能執行(死迴圈了)
3、有些系統在啟動時會自動將su的4755許可權設成755,甚至直接刪除su
那麼針對這種情況,我們怎麼辦呢?非常簡單:燒一個eng版本的boot.img就行了
可以用展訊的燒錄工具,或者用fastboot模式從sd卡燒一個boot.img檔案即可
至此,我們Root就成功了,可以用R.E(Root Explorer)在根目錄建立和刪除檔案。
三、 深入理解Root機制
其流程是:
- 1. Su 被使用者呼叫
- 2. Su 建立了一個socket監聽
- 3. Su 向Superuser傳送了一個廣播,說是有一個程式要請求root
- 4. Su 等待socket 資料接收。有超時處理。
- 5. Superuser 介面收到廣播後,彈出一個對話方塊,詢問使用者
- 6. Superuser 向傳來的資料中的socket寫回使用者應答結果。
- 7. Su 根據socket得到的結果處理應該不應該繼續執行
- 8. 完成提權管理
superuser.apk這個程式是root成功後,專門用來管理root許可權使用的,防止被惡意程式濫用。
我們有兩點疑問:
1. superuser是怎麼知道誰想用root許可權?
2. superuser是如何把使用者的選擇告訴su程式的?
即superuser和su程式是如何通訊的,他們倆位於不通的時空,一個在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是否存在:
- File su = new File("/system/bin/su");
- // 檢測su檔案是否存在,如果不存在則直接返回
- if (!su.exists()) {
- Toast toast = Toast.makeText(this, "Unable to find /system/bin/su.", Toast.LENGTH_LONG);
- toast.show();
- return;
- }
- //如果大小一樣,則認為su檔案正確,直接返回了事。
- if (su.length() == suStream.available())
- {
- suStream.close();
- return; //
- }
- // 如果檢測到/system/bin/su檔案存在,但是不對頭,則把自帶的su先寫到"/data/data/com.koushikdutta.superuser/su"
- //再寫到/system/bin/su。
- byte[] bytes = new byte[suStream.available()];
- DataInputStream dis = new DataInputStream(suStream);
- dis.readFully(bytes);
- FileOutputStream suOutStream = new FileOutputStream("/data/data/com.koushikdutta.superuser/su");
- suOutStream.write(bytes);
- suOutStream.close();
- Process process = Runtime.getRuntime().exec("su");
- DataOutputStream os = new DataOutputStream(process.getOutputStream());
- os.writeBytes("mount -oremount,rw /dev/block/mtdblock3 /system\n");
- os.writeBytes("busybox cp /data/data/com.koushikdutta.superuser/su /system/bin/su\n");
- os.writeBytes("busybox chown 0:0 /system/bin/su\n");
- os.writeBytes("chmod 4755 /system/bin/su\n");
- os.writeBytes("exit\n");
- os.flush();
有程序使用root許可權,superuser是怎麼知道的呢,關鍵是句:
- sprintf(sysCmd, "am start -a android.intent.action.MAIN
- -n com.koushikdutta.superuser/com.koushikdutta.superuser.SuperuserRequestActivity
- --ei uid %d --ei pid %d > /dev/null", g_puid, ppid);
- if (system(sysCmd))
- return executionFailure("am.");
原理是am命令,am的用法:
- usage: am [subcommand] [options]
- start an Activity: am start [-D] [-W] <INTENT>
- -D: enable debugging
- -W: wait for launch to complete
- start a Service: am startservice <INTENT>
- send a broadcast Intent: am broadcast <INTENT>
- start an Instrumentation: am instrument [flags] <COMPONENT>
- -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT)
- -e <NAME> <VALUE>: set argument <NAME> to <VALUE>
- -p <FILE>: write profiling data to <FILE>
- -w: wait for instrumentation to finish before returning
- start profiling: am profile <PROCESS> start <FILE>
- stop profiling: am profile <PROCESS> stop
- <INTENT> specifications include these flags:
- [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]
- [-c <CATEGORY> [-c <CATEGORY>] ...]
- [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]
- [--esn <EXTRA_KEY> ...]
- [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]
- [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]
- [-n <COMPONENT>] [-f <FLAGS>]
- [--grant-read-uri-permission] [--grant-write-uri-permission]
- [--debug-log-resolution]
- [--activity-brought-to-front] [--activity-clear-top]
- [--activity-clear-when-task-reset] [--activity-exclude-from-recents]
- [--activity-launched-from-history] [--activity-multiple-task]
- [--activity-no-animation] [--activity-no-history]
- [--activity-no-user-action] [--activity-previous-is-top]
- [--activity-reorder-to-front] [--activity-reset-task-if-needed]
- [--activity-single-top]
- [--receiver-registered-only] [--receiver-replace-pending]
- [<URI>]<span style="font-family:Calibri;font-size:14px;"> </span>
還有個疑點,就是su怎麼知道使用者是允許root許可權還是反對呢?原來是上面提到的白名單起來作用,superuser把使用者的選擇放入:
/data/data/com.koushikdutta.superuser/databases/superuser.sqlite 資料庫中,然後su程序再去讀該資料庫來判斷是否允許。
- static int checkWhitelist()
- {
- sqlite3 *db;
- int rc = sqlite3_open_v2(DBPATH, &db, SQLITE_OPEN_READWRITE, NULL);
- if (!rc)
- {
- char *errorMessage;
- char query[1024];
- sprintf(query, "select * from whitelist where _id=%d limit 1;", g_puid);
- struct whitelistCallInfo callInfo;
- callInfo.count = 0;
- callInfo.db = db;
- rc = sqlite3_exec(db, query, whitelistCallback, &callInfo, &errorMessage);
- if (rc != SQLITE_OK)
- {
- sqlite3_close(db);
- return 0;
- }
- sqlite3_close(db);
- return callInfo.count;
- }
- sqlite3_close(db);
- return 0;
- }
四、 資原始檔的獲取
從上文的原始碼地址獲取原始碼,替換系統的system/extras/su/下面的su.c和Android.mk檔案,使用編譯命令 ./mk td28 u adr system/extras/su/編譯成功後會生成out/target/product/hsdroid/system/xbin/su檔案,而Superuser.apk就是普通的apk檔案,都在原始碼地址裡面可以下載,下載後倒入到eclipse即可直接執行。
五、 總結
在閱讀完本文後,可以站在專業的角度瞭解root的真正原理,以及有使用者有需求時我們可以幫助其快速的解決問題。