Android許可權結構和常見問題

來源:互聯網
上載者:User

                Android系統是運行在Linux核心上的,Android與Linux分別有自己的一套嚴格的安全及許可權機制,

    很多像我這樣的新手,尤其是習慣了windows低安全限制的使用者,很容易在這方面弄混淆,下面是我總結的Android系統許可權相關的內容,

    作為這段時間對android許可權學習的總結,也希望能對大家有所協助,不正確之處請指出。

    首先分清兩個概念:

    要區分apk運行時的擁有的許可權與在檔案系統上被訪問(讀寫執行)的許可權兩個概念。

    apk程式是運行在虛擬機器上的,對應的是Android獨特的許可權機制,只有體現到檔案系統上時才使用linux的使用權限設定。

    (一)linux檔案系統上的許可權

    -rwxr-x--x system system 4156 2010-04-30 16:13 test.apk

    代表的是相應的使用者/使用者組及其他人對此檔案的存取權限,與此檔案運行起來具有的許可權完全不相關。

    比如上面的例子只能說明system使用者擁有對此檔案的讀寫執行許可權;system組的使用者對此檔案擁有讀、執行許可權;其他人對此檔案只具有執行許可權。

    而test.apk運行起來後可以幹哪些事情,跟這個就不相關了。

    千萬不要看apk檔案系統上屬於system/system使用者及使用者組,或者root/root使用者及使用者組,就認為apk具有system或root許可權。

    (二)Android的許可權規則

    (1)Android中的apk必須簽名

    這種簽名不是基於權威認證的,不會決定某個應用允不允許安裝,而是一種自我簽署憑證。

    重要的是,android系統有的許可權是基於簽名的。比如:system等級的許可權有專門對應的簽名,簽名不對,許可權也就擷取不到。

    預設產生的APK檔案是debug簽名的。

    擷取system許可權時用到的簽名,見:如何使Android應用程式擷取系統許可權

    (2)基於UserID的進程層級的安全機制

    大家都知道,進程有獨立的地址空間,進程與進程間預設是不能互相訪問的,是一種很可靠的保護機制。

    Android通過為每一個安裝在裝置上的包(apk)分配唯一的linux userID來實現,名稱為"app_"加一個數字,比如app_43

    不同的UserID,運行在不同的進程,所以apk之間預設便不能相互訪問。

    Android提供了如下的一種機制,可以使兩個apk打破前面講的這種壁壘。

    在AndroidManifest.xml中利用sharedUserId屬性給不同的package分配相同的userID,通過這樣做,兩個package可以被當做同一個程式,

    系統會分配給兩個程式相同的UserID。當然,基於安全考慮,兩個package需要有相同的簽名,否則沒有驗證也就沒有意義了。

    (這裡補充一點:並不是說分配了同樣的UserID,兩程式就運行在同一進程, 下面為PS指令摘取的,

    顯然,system、app_2分別對應的兩個進程的PID都不同,不知Android到底是怎樣實現它的機制的)

    User PID PPID

    system 953 883 ffffffff afe0cbcc S system_server

    app_2 1072 883 ffffffff afe0dcc4 S com.android.inputmethod.

    system 1083 883 ffffffff afe0dcc4 S android.process.omsservi

    app_2 1088 883 ffffffff afe0dcc4 S android.process.acore

    (3)預設apk產生的資料對外是不可見的

    實現方法是:Android會為程式儲存的資料分配該程式的UserID。

    藉助於Linux嚴格的檔案系統存取權限,便實現了apk之間不能相互訪問似有資料的機制。

    例:我的應用程式建立的一個檔案,預設許可權如下,可以看到只有UserID為app_21的程式才能讀寫該檔案。

    -rw------- app_21 app_21 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:

    在應用安裝的時候,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 的API中有提供 SystemClock.setCurrentTimeMillis()函數來修改系統時間,可惜無論你怎麼調用這個函數都是沒用的,無論模擬器還是真機,在logcat中總會得到"Unable to open alarm driver: Permission denied ".這個函數需要root許可權或者運行與系統進程中才可以用。

    本來以為就沒有辦法在應用程式這一層改系統時間了,後來在網上搜了好久,知道這個目的還是可以達到的。

    第一個方法簡單點,不過需要在Android系統源碼的環境下用make來編譯:

    1. 在應用程式的AndroidManifest.xml中的manifest節點中加入android:sharedUserId="android.uid.system"這個屬性。

    2. 修改Android.mk檔案,加入LOCAL_CERTIFICATE := platform這一行

    3. 使用mm命令來編譯,產生的apk就有修改系統時間的許可權了。

    第二個方法麻煩點,不過不用開虛擬機器跑到源碼環境下用make來編譯:

    1. 同上,加入android:sharedUserId="android.uid.system"這個屬性。

    2. 使用eclipse編譯出apk檔案,但是這個apk檔案是不能用的。

    3. 用壓縮軟體開啟apk檔案,刪掉META-INF目錄下的CERT.SF和CERT.RSA兩個檔案。

    4. 使用目標系統的platform密鑰來重新給apk檔案簽名。這步比較麻煩,首先找到密鑰檔案,在我的Android源碼目錄中的位置是"build\target\product\security",下面的platform.pk8和platform.x509.pem兩個檔案。然後用Android提供的Signapk工具來簽名,signapk的原始碼是在"build\tools\signapk"下,用法為"signapk platform.x509.pem platform.pk8 input.apk output.apk",檔案名稱最好使用絕對路徑防止找不到,也可以修改原始碼直接使用。

    這樣最後得到的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:sharedUserId屬性不只可以把apk放到系統進程中,也可以配置多個APK運行在一個進程中,這樣可以共用資料,應該會很有用的。 博主補充:

    signapk編譯結束後在 android目錄下/out/host/linux-x86/framework/signapk.jar

    使用方法:java -jar signapk.jar platform.x509.pem platform.pk8 test.apk test_signed.apk

    實踐證明,第二種方法不需要刪掉META-INF目錄下的CERT.SF和CERT.RSA兩個檔案,直接signapk就可以。

    編寫使用root許可權的android應用程式這個是如何執行su命令的使用

    publicstaticboolean runRootCommand(String command){

      Process process =null;

      DataOutputStream os =null;

      try{

           process =Runtime.getRuntime().exec("su");

           os =newDataOutputStream(process.getOutputStream());

           os.writeBytes(command+"\n");

           os.writeBytes("exit\n");

          os.flush();

           process.waitFor();

      }catch(Exception e){

          Log.d("*** DEBUG ***", "Unexpected error - Here is what I know: "+e.getMessage());

          return false;

      }finally{

          try{

              if(os !=null){

                      os.close();

                    }

                    process.destroy();

                    }catch(Exception e){

                      // nothing

                    }

            }returntrue;

          }

      }

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.