標籤:android style code java tar ext
概述:通過閱讀本文可以深刻理解Android系統中獲得Root許可權的方法和原理。本文會詳細介紹Root的目的,原理和代碼層次的具體實現方法。Android Root介紹:
1. Root目的
手機獲得Root許可權以後,使用者就可以完全擁有手機系統的最高許可權,在Linux系統中相當於Root帳號,在Windows系統中相當於Administrator帳號。因為Android系統是基於Linux的,所以叫Root許可權。
有了Root許可權以後,使用者可以自由刪除一些系統內建的無用軟體,更換開關機鈴聲,去除狀態列彈出的廣告和常用軟體中嵌入的第三方廣告平台展示廣告的幹擾,讓你的手機隨心所欲,不再受幹擾,總之一句話Root可以讓你真正享有手機主人的感覺。
2. Root原理介紹
給手機Root的原理大概分為三個步驟:步驟一,把su檔案拷貝到/system/bin/目錄下面。步驟二,把Superuser.apk放到/system/app/目錄下面。步驟三,設定/system/bin/su讓任意使用者都可以運行並且擁有set_uid和set_gid的許可權。
當然,這些操作廠商是不會輕易允許我們這樣做的,這樣我們就需要去利用Android作業系統的各種漏洞去實現這些操作,利用這些漏洞完成以上三步操作的過程就是Root的過程。
Su – Switch User切換使用者。
3. Root方法介紹
從Root的原理我們瞭解到,想要Root需要三個步驟:
- adb push su /system/bin — xbin下是放一些小工具來方便使用的
- adb push SuperUser.apk /system/app
- adb shell chmod 4755 /system/bin/su(關於chmod XXX可以到這裡瞭解一下http://hi.baidu.com/angivo/item/345af44260142b09e9350416)
如果系統是英文版,那麼經過以上三個步驟,Root就大功告成了,通過安裝Root Explorer軟體就可以在根目錄下建立刪除檔案了。但是國內的手機的系統都是經過廠商改造過的中文版,通過以上三個步驟是不行的,原因有以下三點:
- 中文版的/system路徑是唯讀許可權,我們是不能完成寫入或者copy操作的
- chmod命令是需要擁有Root許可權後才可以使用的,我們的在操作的時候是沒有Root許可權的,所以這個命令在我們Root過程中是無法使用的
- 某些廠商定製的系統在系統重新啟動的時候會自動將su的許可權從4755改成755或者直接刪除了su,正是因為這個原因我們經常會碰到,明明我們是已經Root過的手機,但是手機重啟後就沒有Root許可權了。這種只是臨時獲得的Root許可權。
針對以上三點,我們怎麼能夠確保獲得永久的Root許可權呢?一種方案是自己去燒制一個英文版boot.img,刷一個英文版的系統然後再Root就OK了。另外一種方案就是去即時監控system/bin目錄下已有的su檔案是否存在,如果不存在就立即copy一個過去。
4. 深入理解Root機制
Root調用流程如下:
- su被使用者調用
- su建立一個socket監聽,搭建一個通道來完成通訊
- su通過廣播的方式通知superuser目前有一個應用要使用Root
- su等待socket資料通訊完成,通常會有逾時處理
- superuser在收到廣播以後會在介面彈出一個對話方塊,與使用者互動,詢問使用者是否給予Root許可權
- superuser將使用者的選擇結果再通過socket回傳給su
- su根據socket得到的結果在做相應的處理判斷應不應該繼續給Root許可權
- 完成本次授權處理
Superuser.apk這個應用是Root成功後,專門用來管理Root許可權使用的,防止惡意應用濫用。可以去這個地方下載官方的superuser源碼和su檔案:http://superuser.googlecode.com/svn/trunk/ 自己就可以在Eclipse上開啟superuser代碼,完成編譯和安裝。
Superuser和su之間的通訊原理:
Superuser使用運行在Java虛擬機器中,而su是運行在Linux的真是進程中,他們兩個之間通訊superuser這個應用來完成大部分工作,superuser一共有兩個Activity:一個是SuperuserActivity另外一個是SuperuserRequestActivity,其中SuperuserActivity是用來管理白名單的,用來記住那些應用程式已經被允許使用Root許可權了,這樣白名單中的應用再次提權時,就不需要麻煩使用者選擇了。而superuserRequestActivity是用來負責彈出對話方塊詢問使用者當前某個應用請求使用Root許可權,讓使用者來完成選擇授予還是不授予。如果使用者選擇永久授予Root許可權,那會通過SuperuserActivity會將本次提權的應用寫入白名單中。白名單其實就是一個sqlite的資料庫,來儲存使用者選擇永久授予Root許可權的應用程式名稱單。白名單在資料庫中位置為:
/data/data/com.koushikdutta.superuser/databases/superuser.sqlite
上文已經說過,Root的本質就是往 /system/bin/ 目錄下放一個su檔案,並且給su檔案4755的許可權,任何使用者都有調用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.SuperuserRe questActivity --ei uid %d --ei pid %d > /dev/null", g_puid, ppid);
if (system(sysCmd))
return executionFailure("am.");
Superuser操作白名單代碼:
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;
}
5. 資源檔的擷取
從上文的源碼地址擷取原始碼,替換系統的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即可直接運行。