獲取system權限
上一篇隨筆簡單介紹了下Android權限的一些規則,我們發現很多事如果沒有system權限基本上無法完成,那么如何讓自己的應用獲取system權限呢?
一般情況下,設定apk的權限,可在AndroidManifest.xml中添加android:sharedUserId="android.uid.xxx>
例如: 給apk添加system權限
1 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2 ... ... 3 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文件簽名。首先找到密鑰文件,在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"這個屬性。通過sharedUserId,擁有同一個UserId的多個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",這樣也是保護了系統的安全。
獲取Root權限
一般linux 獲取root權限是通過執行su命令,那能不能在apk程序中也同樣執行一下該命令呢?Linux 編程中,有一組函數族:
1 int execl(const char *path, const char *arg, ...); 2 3 int execlp(const char *file, const char *arg, ...); 4 5 int execle(const char *path, const char *arg, ..., char *const envp[]); 6 7 int execv(const char *path, char *const argv[]); 8 9 int execvp(const char *file, char *const argv[]); 10 11 int execve(const char *path, char *const argv[], char *const envp[]);
在java中我們可以借助 Runtime.getRuntime().exec(String command)訪問底層Linux下的程序或腳本,這樣就能執行su命令,使apk具有root權限,能夠訪問系統中需要root權限才能執行的程序或腳本了。
還是舉個例子,
1 public class VisitRootfileActivity extends Activity { 2 private static final String TAG = "VisitRootfileActivity"; 3 Process process = null; 4 Process process1 = null; 5 DataOutputStream os = null; 6 DataInputStream is = null; 7 /** Called when the activity is first created. */ 8 @Override 9 public void onCreate(Bundle savedInstanceState) { 10 super.onCreate(savedInstanceState); 11 setContentView(R.layout.main); 12 try { 13 process = Runtime.getRuntime().exec("/system/xbin/su"); /*這里可能需要修改su 14 15 的源代碼 (注掉 if (myuid != AID_ROOT && myuid != AID_SHELL) {*/ 16 17 os = new DataOutputStream(process.getOutputStream()); 18 is = new DataInputStream(process.getInputStream()); 19 os.writeBytes("/system/bin/ls" + " \n"); //這里可以執行具有root 權限的程序了 20 os.writeBytes(" exit \n"); 21 os.flush(); 22 process.waitFor(); 23 } catch (Exception e) { 24 Log.e(TAG, "Unexpected error - Here is what I know:" + e.getMessage()); 25 } finally { 26 try { 27 if (os != null) { 28 os.close(); 29 } 30 if (is != null) { 31 is.close(); 32 } 33 process.destroy(); 34 } catch (Exception e) { 35 } 36 }// get the root privileges 37 } 38 }
