我在博文《Android程序的安全系統》中提到兩種讓root權限的辦法。最近在網(wǎng)上發(fā)現很多朋友轉載那篇文章,但是對那篇文章中提到的第一種方法怎樣實(shí)現,不是很明白。本文將會(huì )以一個(gè)例子實(shí)現來(lái)演示怎樣讓一個(gè)Android應用程序獲得root權限。
問(wèn)題
我遇到的問(wèn)題是我想在Java應用程序中動(dòng)態(tài)mount一個(gè)NFS的系統,但是執行mount命令必須要要root權限才可以。一般情況下,在A(yíng)ndroid的Java層是不能獲得root權限的。
思路
我在博文《Android程序的安全系統》中提到兩種思路:
1、實(shí)現一個(gè)init實(shí)現一個(gè)Service,來(lái)幫助Android應用程序執行root權限的命令。
2、實(shí)現一個(gè)虛擬設備,這個(gè)設備幫助Android應用程序執行root權限的命令。
本文將會(huì )選擇第一種來(lái)解決Android應用程序mount NFS文件系統的問(wèn)題。
Init.rc Service
在A(yíng)ndroid系統init.rc中定義很多Service,具體定義格式可以參考《Android Platform Developer’s Guide》中的“Android Init Language”。Init.rc中定義的Service將會(huì )被Init進(jìn)程創(chuàng )建,這樣將可以獲得root權限。
現在問(wèn)題是Android應用程序怎樣啟動(dòng)讓init進(jìn)程知道我們想運行那個(gè)進(jìn)程呢?答案是設置系統屬性“ctl.start”,把“ctl.start”設置為你要運行的Service,假設為“xxx”,Android系統將會(huì )幫你運行“ctl.start”系統屬性中指定的Service。那么運行結果init進(jìn)程將會(huì )將會(huì )寫(xiě)入命名為“init.svc.+Service名稱(chēng)”的屬性中,也就是“init.svc.xxx”屬性,應用程序可以參考查閱這個(gè)值來(lái)確定Service執行的情況。想更深入了解Android property系統可以參考博文《(翻譯)Android屬性系統》。
Android property權限
難道Android屬性“ctl.start”是所有進(jìn)程都可以設置的嗎?那世界不就亂套了,誰(shuí)都可以可以執行init.rc中Service了,查看property_service.c中的源碼,設置Android系統屬性的函數為handle_property_set_fd:
1: void handle_property_set_fd(int fd)
2: { 3: ......4: switch(msg.cmd) {
5: case PROP_MSG_SETPROP:
6: msg.name[PROP_NAME_MAX-1] = 0; 7: msg.value[PROP_VALUE_MAX-1] = 0; 8: 9: if(memcmp(msg.name,"ctl.",4) == 0) {
10: if (check_control_perms(msg.value, cr.uid, cr.gid)) {
11: handle_control_message((char*) msg.name + 4, (char*) msg.value);
12: } else {
13: ERROR("sys_prop: Unable to %s service ctl [%s] uid: %d pid:%d\n",
14: msg.name + 4, msg.value, cr.uid, cr.pid); 15: } 16: } 17: ...... 18: } 19: }從源碼中我們發(fā)現如果設置“ctl.”開(kāi)頭的Android系統property,將會(huì )調用check_control_perms函數來(lái)檢查調用者的權限,其定義如下:
1: static int check_control_perms(const char *name, int uid, int gid) {
2: int i;
3: if (uid == AID_SYSTEM || uid == AID_ROOT)
4: return 1;
5: 6: /* Search the ACL */
7: for (i = 0; control_perms[i].service; i++) {
8: if (strcmp(control_perms[i].service, name) == 0) {
9: if ((uid && control_perms[i].uid == uid) ||
10: (gid && control_perms[i].gid == gid)) {11: return 1;
12: } 13: } 14: }15: return 0;
16: }我們發(fā)現root權限和system權限的應用程序將會(huì )授權修改“ctl.”開(kāi)頭的Android系統屬性。否則將會(huì )檢查control_perms全局變量中的定義權限和Service。
如果想更深入的了解Android Init進(jìn)程和Android Property的權限控制,請參考《Android Permission》。
實(shí)例
通過(guò)上面的介紹我們基本已經(jīng)有思路了,下面以上面提出的mount nfs文件系統為例說(shuō)明:
1、首先定義一個(gè)執行mount的腳本,我把它位于/system/etc/mount_nfs.sh,定義如下:
1: #!/system/bin/sh 2: 3: /system/bin/busybox mount -o rw,nolock -t nfs 192.168.1.6:/nfs_srv /data/mnt不要忘了把它加上可執行權限。
2、在init.rc中加入一個(gè)Service定義,定義如下:
1: service mount_nfs /system/etc/mount_nfs.sh 2: oneshot 3: disabled3、讓自己的應用程序獲得system權限,博文《Android程序的安全系統》中提到了怎樣獲得system權限,請參考,這里就不贅述了。
4、在自己應用程序中設置System系統屬性“ctl.start”為“mount_nfs”,這樣Android系統將會(huì )幫我們運行mount_nfs系統屬性了。這里需要強調的是不能夠調用System.getProperty,這個(gè)函數只是修改JVM中的系統屬性。而不能修改Android的系統屬性??梢哉{用android.os.SystemProperties(Android 2.1 Eclair系統可以調用這個(gè)API),如果你的Android版本不能調用這個(gè)類(lèi),只能通過(guò)JNI,調用C/C++層的API property_get和property_set函數了。如果想詳細了解請參考《(翻譯)Android屬性系統》。代碼如下:
1: SystemProperties.set("ctl.start", "mount_nfs");
5、最后在自己應用程序中,讀取“init.svc.mount_nfs”Android系統Property,檢查執行結果。代碼如下:
1: while(true)
2: {3: mount_rt = SystemProperties.get("init.svc.mount_nfs", "");
4: if(mount_rt != null && mount_rt.equals("stopped"))
5: {6: return true;
7: } 8: 9: try
10: { 11: Thread.sleep(1000);12: }catch(Exception ex){
13: Log.e(TAG, "Exception: " + ex.getMessage());
14: } 15: }init進(jìn)程維護一個(gè)service的隊列,所以我們需要輪訓來(lái)查詢(xún)service的執行結果。
通過(guò)上面的這些步驟,Android應用程序就能夠調用init.rc中定義的Service了。這樣你的Android應用程序也就獲得了root權限。
總結
通過(guò)上文可以看出,在A(yíng)ndroid獲得root權限還是需要一些前提的,比如:
1、必須是Android系統開(kāi)發(fā)人員,否則你無(wú)法修改init.rc等文件。 2、你的應用程序必須要獲得system權限。
這樣可以防止root權限被應用程序無(wú)限制的使用,最終危及Android系統安全。
希望本文對你能有所幫助,如果有錯誤之處敬請指正。



bevis
2011-01-20 14:51:20
謝謝simon,每次定期的來(lái)你這里看看,總會(huì )學(xué)到很多知識。前幾天就剛好遇到你說(shuō)的這個(gè)問(wèn)題,今天來(lái)這里看了一下,問(wèn)題看來(lái)可以解決了,呵呵,謝謝!
[回復]
Simon_fu 回復:
一月 20th, 2011 at 15:52
歡迎你多來(lái)關(guān)注Simon,也歡迎你對Simon的文章多提寶貴意見(jiàn)!大家共同進(jìn)步!
[回復]