實(shí)在的東西一定要收藏 轉(zhuǎn)自:http://my.unix-center.net/~Simon_fu/?p=531
最近在移植Android過程中遇到了Android程序(apk)權(quán)限的問題。最近也對這方面進(jìn)行了一些了解,在此和大家分享。
Android框架是基于Linux內(nèi)核構(gòu)建,所以Android安全系統(tǒng)也是基于Linux的安全架構(gòu)建立的。在Linux安全系統(tǒng)中,用戶和組起著重
要的作用,Linux中所有的資源給不同的用戶和用戶組設(shè)置了不同的訪問屬性。如果你對Linux下面用戶和組的概念不熟悉,請先補(bǔ)習(xí)一下Linux基礎(chǔ)
知識。
在Android系統(tǒng)中,系統(tǒng)為每一個(gè)應(yīng)用程序(apk)創(chuàng)建了一個(gè)用戶和組。這個(gè)用戶和組都是受限用戶,不能訪問系統(tǒng)的數(shù)據(jù),只能訪問自己的文件和目
錄,當(dāng)然它也不能訪問其他應(yīng)用程序的數(shù)據(jù)。這樣設(shè)計(jì)可以盡可能地保護(hù)應(yīng)用程序的私有數(shù)據(jù),增強(qiáng)系統(tǒng)的安全性和健壯性。
但是有一些應(yīng)用程序是需要訪問一些系統(tǒng)資源的。比如Setting程序,他就需要訪問wiffi,在系統(tǒng)中創(chuàng)建刪除文件等等操作。怎樣做到這一點(diǎn)兒呢?Android通過一定途徑可以獲得system權(quán)限。獲得system用戶權(quán)限,需要以下步驟:
1. 在應(yīng)用程序的AndroidManifest.xml 中的manifest節(jié)點(diǎn)中加入android:sharedUserId ="android.uid.system"這個(gè)屬性。 2. 修改Android.mk文件,加入LOCAL_CERTIFICATE := platform這一行 3. 使用mm命令來編譯,生成的apk就有修改系統(tǒng)時(shí)間的權(quán)限了。
一般情況下system用戶權(quán)限就已經(jīng)夠用了,system用戶可以在系統(tǒng)中創(chuàng)建和刪除文件,訪問設(shè)備等等。但是有些情況下system權(quán)限還是不夠的。
比如:設(shè)置網(wǎng)卡IP地址,ifconfig 命令是需要root權(quán)限的。我可以很肯定的說,在Android下面應(yīng)用程序是沒有可能拿到root權(quán)限的。但
是如果我的應(yīng)用程序需要root權(quán)限怎么辦呢?只能想辦法繞般過去。就以我的問題為例,設(shè)置網(wǎng)卡IP地址,root權(quán)限下面命令為:
ifconfig eth0 192.168.1.188
在普通用戶或者system用戶權(quán)限下面這條命令是不起作用的,但是不會返回失敗和異常,這個(gè)我個(gè)人認(rèn)為是Android的bug。那么怎樣實(shí)現(xiàn)這個(gè)功能呢?我想出了兩個(gè)辦法。
1、系統(tǒng)啟動的時(shí)候init進(jìn)程創(chuàng)建一個(gè)后臺進(jìn)程,該進(jìn)程處于root用戶權(quán)限下面。用來監(jiān)聽系統(tǒng)中應(yīng)用程序的請求(可以用socket實(shí)現(xiàn)),并代其完成。這樣應(yīng)用程序就可以執(zhí)行root用戶權(quán)限的任務(wù)了。
2、實(shí)現(xiàn)一個(gè)虛擬的設(shè)備,該設(shè)備的功能就是在內(nèi)核態(tài)幫應(yīng)用程序執(zhí)行相應(yīng)的命令。Linux內(nèi)核態(tài)沒有權(quán)限的問題了。肯定可以執(zhí)行成功。
我解決設(shè)置網(wǎng)卡IP地址問題時(shí),選擇是后者。相對來說設(shè)計(jì)比較簡單。
如果你到網(wǎng)上去搜一下,你會發(fā)現(xiàn)很多文章說怎樣讓Android應(yīng)用程序獲得root權(quán)限。如果你不想浪費(fèi)時(shí)間就不要相信他們,因?yàn)槟切┩緩绞歉静豢赡塬@得root權(quán)限的。
我的后續(xù)博文《Android應(yīng)用程序獲得root權(quán)限》講解讓應(yīng)用程序(APK)通過第一種方法獲得root權(quán)限的方法,請關(guān)注。
############################################ 我在博文《Android程序的安全系統(tǒng)》中提到兩種讓root權(quán)限的辦法。最近在網(wǎng)上發(fā)現(xiàn)很多朋友轉(zhuǎn)載那篇文章,但是對那篇文章中提到的第一種方法怎樣實(shí)現(xiàn),不是很明白。本文將會以一個(gè)例子實(shí)現(xiàn)來演示怎樣讓一個(gè)Android應(yīng)用程序獲得root權(quán)限。
問題
我遇到的問題是我想在Java應(yīng)用程序中動態(tài)mount一個(gè)NFS的系統(tǒng),但是執(zhí)行mount命令必須要要root權(quán)限才可以。一般情況下,在Android的Java層是不能獲得root權(quán)限的。
思路
我在博文《Android程序的安全系統(tǒng)》中提到兩種思路:
1、實(shí)現(xiàn)一個(gè)init實(shí)現(xiàn)一個(gè)Service,來幫助Android應(yīng)用程序執(zhí)行root權(quán)限的命令。 2、實(shí)現(xiàn)一個(gè)虛擬設(shè)備,這個(gè)設(shè)備幫助Android應(yīng)用程序執(zhí)行root權(quán)限的命令。
本文將會選擇第一種來解決Android應(yīng)用程序mount NFS文件系統(tǒng)的問題。
Init.rc Service
在Android系統(tǒng)init.rc中定義很多Service,具體定義格式可以參考《Android Platform Developer’s Guide》中的“Android Init Language”。Init.rc中定義的Service將會被Init進(jìn)程創(chuàng)建,這樣將可以獲得root權(quán)限。
現(xiàn)在問題是Android應(yīng)用程序怎樣啟動讓init進(jìn)程知道我們想運(yùn)行那個(gè)進(jìn)程呢?答案是設(shè)置系統(tǒng)屬性“ctl.start”,把
“ctl.start”設(shè)置為你要運(yùn)行的Service,假設(shè)為“xxx”,Android系統(tǒng)將會幫你運(yùn)行“ctl.start”系統(tǒng)屬性中指定的
Service。那么運(yùn)行結(jié)果init進(jìn)程將會將會寫入命名為“init.svc.+Service名稱”的屬性中,也就是“init.svc.xxx”
屬性,應(yīng)用程序可以參考查閱這個(gè)值來確定Service執(zhí)行的情況。想更深入了解Android property系統(tǒng)可以參考博文《(翻譯)Android屬性系統(tǒng)》。
Android property權(quán)限
難道Android屬性“ctl.start”是所有進(jìn)程都可以設(shè)置的嗎?那世界不就亂套了,誰都可以可以執(zhí)行init.rc中Service了,查看
property_service.c中的源碼,設(shè)置Android系統(tǒng)屬性的函數(shù)為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ā)現(xiàn)如果設(shè)置“ctl.”開頭的Android系統(tǒng)property,將會調(diào)用check_control_perms函數(shù)來檢查調(diào)用者的權(quán)限,其定義如下:
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ā)現(xiàn)root權(quán)限和system權(quán)限的應(yīng)用程序?qū)跈?quán)修改“ctl.”開頭的Android系統(tǒng)屬性。否則將會檢查control_perms全局變量中的定義權(quán)限和Service。
如果想更深入的了解Android Init進(jìn)程和Android Property的權(quán)限控制,請參考《Android Permission》。
實(shí)例
通過上面的介紹我們基本已經(jīng)有思路了,下面以上面提出的mount nfs文件系統(tǒng)為例說明:
1、首先定義一個(gè)執(zhí)行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
不要忘了把它加上可執(zhí)行權(quán)限。
2、在init.rc中加入一個(gè)Service定義,定義如下:
1: service mount_nfs /system/etc/mount_nfs.sh
2: oneshot
3: disabled
3、讓自己的應(yīng)用程序獲得system權(quán)限,博文《Android程序的安全系統(tǒng)》中提到了怎樣獲得system權(quán)限,請參考,這里就不贅述了。
4、在自己應(yīng)用程序中設(shè)置System系統(tǒng)屬性“ctl.start”為“mount_nfs”,這樣Android系統(tǒng)將會幫我們運(yùn)行mount_nfs系統(tǒng)屬性了。這里需要強(qiáng)調(diào)的是不能夠調(diào)用System.getProperty,
這個(gè)函數(shù)只是修改JVM中的系統(tǒng)屬性。而不能修改Android的系統(tǒng)屬性?梢哉{(diào)用
android.os.SystemProperties(Android 2.1
Eclair系統(tǒng)可以調(diào)用這個(gè)API),如果你的Android版本不能調(diào)用這個(gè)類,只能通過JNI,調(diào)用C/C++層的API
property_get和property_set函數(shù)了。如果想詳細(xì)了解請參考《(翻譯)Android屬性系統(tǒng)》。代碼如下:
1: SystemProperties.set("ctl.start", "mount_nfs");
5、最后在自己應(yīng)用程序中,讀取“init.svc.mount_nfs”Android系統(tǒng)Property,檢查執(zhí)行結(jié)果。代碼如下:
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)程維護(hù)一個(gè)service的隊(duì)列,所以我們需要輪訓(xùn)來查詢service的執(zhí)行結(jié)果。
通過上面的這些步驟,Android應(yīng)用程序就能夠調(diào)用init.rc中定義的Service了。這樣你的Android應(yīng)用程序也就獲得了root權(quán)限。
總結(jié)
通過上文可以看出,在Android獲得root權(quán)限還是需要一些前提的,比如:
1、必須是Android系統(tǒng)開發(fā)人員,否則你無法修改init.rc等文件。 2、你的應(yīng)用程序必須要獲得system權(quán)限。
這樣可以防止root權(quán)限被應(yīng)用程序無限制的使用,最終危及Android系統(tǒng)安全。
希望本文對你能有所幫助,如果有錯(cuò)誤之處敬請指正。
|