天天看點

Andriod 權限詳解 與linux檔案通路權限詳解

前言

Android系統是基于linux進行開發的,linux的檔案系統是否與Android 系統權限或者動态權限申請中權限有關聯。

1.Linux檔案通路權限介紹

Linux檔案權限采用10位數字進行控制一個檔案/檔案夾的通路權限,x_xxx_xxx_xxx.

Andriod 權限詳解 與linux檔案通路權限詳解

第一位代碼檔案類型 _,檔案類型共有7種,除了 _表示正常檔案類型外,還有下面的六種

“d”目錄

“l”符号連結

“c”字元專門裝置檔案

“b”塊專門裝置檔案

“p”先進先出

“s”套接字

1.1 檔案通路快速查驗表

通過這個表可以直覺的看到兩種權限的表示方法:字元表示、數字表示.

注:數字表示采用3位八進制表示,如果權限為0777,這裡先介紹後三位,首位的0稍後介紹。777表示檔案所有者,檔案所屬組,所有其他使用者均可讀寫執行。l例如_444,則表示檔案所屬組,所有其他使用者均可讀,表示的意思和_r _ r r 表示的一樣。還有其他組合,随意拼接。

Andriod 權限詳解 與linux檔案通路權限詳解
1.2. 常用操作指令
指令 指令解釋 其他
whoami 目前“操作使用者”的使用者辨別
su 切換使用者身份
groups 看您屬于哪一組
groups 使用者辨別 daemon 檢視其他使用者在哪一個組
chown 改變檔案所有者 都要一個使用者名或組名作參數
chgrp 改變檔案組 都要一個使用者名或組名作參數
1.3 檔案通路權限字元表示方式解釋

這裡隻介紹常用的兩種 _,d, _代表檔案類型,d 代表目錄類型。這裡均指的是的首位位置。

普通檔案即實際儲存資料的地方,其并不具備删除自身的權限:

r:可讀取檔案的實際内容

w:可編輯、新增、修改該檔案的實際内容

x:可被執行

目錄檔案即儲存有目錄結構和檔案權限:

r:可讀取目錄結構和權限

w:可更改目錄結構清單、建立、删除、重命名、轉移子檔案、目錄

x:表示使用者可進入到該目錄中

1.4 修改檔案權限的方式

Linux系統為了保證通路安全,所有建立的檔案以 0222 為預設通路權限。可以使用Umask指令來檢視。

當我們在linux系統上通路一個檔案提示通路權限不足時,通常會采用

chmod系統指令來提升目前使用者通路權限。chmod 帶有兩個或多個參數:“mode”

$ chmod +x test.sh  對于使用者,組,其他所有人均可以執行
 $ chmod -x test.sh       …均不可執行      

還可以針對具體的組改變通路權限,對于“使用者”三元組使用 u,對于“組”三元組使用 g,對于“其他/每個人”使用 o:

$ chmod go-w test.sh  對群組和其他使用者去掉寫權限      

​​Chmod 其他修改權限的方式及首位表示意義解釋​​:

2.Android 檔案通路權限介紹

6.0之後Android增加了運作時權限申請,在6.0之前的版本隻需要在清單檔案中聲明需要的權限即可。而6.0之後除了提前聲明所需要的通路的權限,在用到該權限的地方,還需要動态授予權限。

2.1 Android 權限規則
  1. Android build 出來的apk預設擁有Debug簽名,如果apk不進行簽名是無法進行安裝到裝置或者模拟器上的。

    為什麼需要簽名?直接給出答案,Android 系統有的權限是基于簽名的。

  2. 基于UserID的程序級别的安全機制

    Linux 系統擁有程序保護機制,程序之間是無法互相對應進行的獨立空間。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.      
  1. AndroidManifest.xml中的顯式權限聲明

    Android預設應用是沒有任何權限去操作其他應用或系統相關特性的,應用在進行某些操作時都需要顯式地去申請相應的權限。

    一般以下動作時都需要申請相應的權限:

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)中有相關記錄。      
  1. 權限繼承/UserID繼承

    當我們遇到apk權限不足時,我們有時會考慮寫一個linux程式,然後由apk調用它去完成某個它沒有權限完成的事情,很遺憾,這種方法是行不通的。

    前面講過,android權限是在程序層面的,也就是說一個apk應用啟動的子程序的權限不可能超越其父程序的權限(即apk的權限),

    即使單獨運作某個應用有權限做某事,但如果它是由一個apk調用的,那權限就會被限制。

    實際上,android是通過給子程序配置設定父程序的UserID實作這一機制的。

2.2 Android 系統常見權限不足分析

普通apk運作在非系統,非root層級,也就是說看要通路的檔案權限時,看 x_擁有者__使用者組_其他使用者,檢視linux權限組的後三位權限組的權限,另外存放在system/apk 檔案夾下的app擁有的權限高于install apk權限。

  1. log中有明确的提示,權限不足

    這種log中直接提示權限不足的,直接檢視清單檔案中是否進行了聲明。而有的時候即使聲明了權限,還是報權限不足,這種情況屬于

    Android 系統有一些Api及權限是需要apk具有一定的等級才能運作的。 比如

    SystemClock.setCurrentTimeMillis()修改系統時間,WRITE_SECURE_SETTINGS權限好像都是需要有system級的權限才行。也就是說UserID是system.

  2. log日志中沒有報權限不足,但是收到Security 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應用程式擷取系統權限)。

2.3 如何使Android應用程式擷取系統權限

2.3.1 方案一

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

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

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

(3) 使用mm指令來編譯,生成的apk就有修改系統時間的權限了

2.3.2 方案二

第二個方法是直接把eclipse編出來的apk用系統的簽名檔案簽名

(1) 加入android:sharedUserId=“android.uid.system"這個屬性。

(2) 使用eclipse編譯出apk檔案。

(3) 使用目标系統的platform密鑰來重新給apk檔案簽名。首先找到密鑰檔案,在我的Android源碼目錄中的位置是"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”,這樣也是保護了系統的安全。

3.怎樣使Android apk擷取root權限。

一般linux 擷取root權限是通過執行su指令,那能不能在apk程式中也同樣執行一下該指令呢,我們知道在linux程式設計中,有exec函數族:

1. int execl(cONst char *path, const char *arg, ...);  
2. int execlp(const char *file, const char *arg, ...);  
3. int execle(const char *path, const char *arg, ..., char *const envp[]);  
4. int execv(const char *path, char *const argv[]);  
5. int execvp(const char *file, char *const argv[]);  
6. int execve(const char *path, char *const argv[], char *const envp[]);      

Android 中Runtime 類型提供了可以執行的程式api我們可以借助 Runtime.getRuntime().exec(String command)通路底層Linux下的程式或腳本,這樣就能執行su指令,使apk具有root權限,能夠通路系統中需要root權限才能執行的程式或腳本了。

具體例子

1. import java.io.DataInputStream;  
2. import java.io.DataOutputStream;  
3. import java.io.IOException;  
4. import android.app.Activity;  
5. import android.os.Bundle;  
6. import android.util.Log;  
7. public class VisitRootfileActivity extends Activity {  
8.     private static final String TAG = "VisitRootfileActivity";  
9.     Process process = null;  
10.     Process process1 = null;     
11.     DataOutputStream os = null;  
12.     DataInputStream is = null;  
13.     /** Called when the activity is first created. */  
14.     @Override  
15.     public void onCreate(Bundle savedInstanceState) {  
16.         super.onCreate(savedInstanceState);  
17.         setContentView(R.layout.main);  
18.         try {  
19.             process = Runtime.getRuntime().exec("/system/xbin/su"); /*這裡可能需要修改su 
20.                        的源代碼 (注掉  if (myuid != AID_ROOT && myuid != AID_SHELL) {*/  
21.   
22.             os = new DataOutputStream(process.getOutputStream());  
23.             is = new DataInputStream(process.getInputStream());  
24.             os.writeBytes("/system/bin/ls" + " \n");  //這裡可以執行具有root 權限的程式了    
25.               os.writeBytes(" exit \n");  
26.             os.flush();  
27.             process.waitFor();  
28.         } catch (Exception e) {              
29.             Log.e(TAG, "Unexpected error - Here is what I know:" + e.getMessage());  
30.         } finally {  
31.             try {  
32.                 if (os != null) {  
33.                     os.close();  
34.                 }  
35.                 if (is != null) {  
36.                     is.close();  
37.                 }  
38.                 process.destroy();  
39.             } catch (Exception e) {  
40.             }  
41.         }// get the root privileges  
42.     }  
43. }      

總結:

Android 中的權限是基于Android apk運作在的程序權限。而linux中的權限針對的是檔案/檔案夾或者linux系統權限組第一位能表示類型檔案的權限。Android權限與linux權限不是同一個層級的權限,Android 隻有通路底層linux中檔案、檔案夾或者linux系統權限組第一位能表示類型檔案的時候的權限,才能表示同一個權限。

繼續閱讀