1. 程式人生 > >Android許可權系統詳解及管理

Android許可權系統詳解及管理

系統是執行在Linux核心上的,AndroidLinux分別有自己的一套嚴格的安全及許可權機制,
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具有systemroot許可權。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之間不能相互訪問似有資料的機制。例:我的應用建立的一個檔案,預設許可權如下,可以看到只有UserIDapp_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.

4AndroidManifest.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會在系統logsystem log)中有相關記錄。

5)許可權繼承/UserID繼承當我們遇到apk許可權不足時,我們有時會考慮寫一個linux程式,然後由apk呼叫它去完成某個它沒有許可權完成的事情,很遺憾,這種方法是行不通的。前面講過,android許可權是在程序層面的,也就是說一個apk應用啟動的子程序的許可權不可能超越其父程序的許可權(即apk的許可權),即使單獨執行某個應用有許可權做某事,但如果它是由一個apk呼叫的,那許可權就會被限制。實際上,android是通過給子程序分配父程序的UserID實現這一機制的。

(三)常見許可權不足問題分析首先要知道,普通apk程式是執行在非root、非system層級的,也就是說看要訪問的檔案的許可權時,看的是最後三位。另外,通過system/app安裝的apk的許可權一般比直接安裝或adb install安裝的apk的許可權要高一些。言歸正傳,執行一個android應用程式過程中遇到許可權不足,一般分為兩種情況:
1Log中可明顯看到許可權不足的提示。此種情況一般是AndroidManifest.xml中缺少相應的許可權設定,好好查詢一番許可權列表,應該就可解決,是最易處理的情況。

有時許可權都加上了,但還是報許可權不足,是什麼情況呢?Android系統有一些API及許可權是需要apk具有一定的等級才能執行的。比如 SystemClock.setCurrentTimeMillis()修改系統時間,WRITE_SECURE_SETTINGS許可權好像都是需要有system級的許可權才行。也就是說UserIDsystem.

2Log裡沒有報許可權不足,而是一些其他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設定。

系統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