Android系统Root与静默安装
Android系統Root與靜默安裝
靜默安裝,指的是安裝時無需任何用戶干預,直接按默認設置安裝應用。因為,它的無需用戶干預,很多情況下變成了用戶壓根不知道,應用不知不覺就安裝上了。是在推廣上極為流氓的手段,很類似PC上的捆綁安裝。正因為靜默安裝時極為流氓的推廣行為,所以,其推廣價格也極其高。
Android應用安裝有如下四種方式
| 系統應用安裝 | 開機時完成,需要加入開機執行的腳本,沒有安裝界面 |
| 網絡下載應用安裝 | 通過系統market應用完成,沒有安裝界面 |
| ADB工具中進行安裝 | 使用pm install命令,沒有安裝界面。 |
| 第三方應用安裝 | 通過SD卡里的APK文件安裝,有安裝界面,由PackageInstaller.apk應用處理安裝及卸載過程的界面。 |
應用安裝的流程及路徑
| /system/app | 系統自帶的應用程序存放,Root權限才可更改 |
| /data/app | 用戶程序安裝的目錄,有刪除權限。安裝時把apk文件復制到此目錄 |
| /data/data | 存放應用程序的數據 |
| Data/dalvik-cache | 將apk中的dex文件安裝到dalvik-cache目錄下 |
安裝過程
復制APK安裝包到data/app目錄下,解壓并掃描安裝包,把dex文件(Dalvik字節碼)保存到dalvik-cache目錄,并data/data目錄下創建對應的應用數據目錄。
卸載過程
刪除安裝過程中在上述三個目錄下創建的文件及目錄。
權限聲明
Google的安全策略要求任何應用在安裝確認的時候應該提示APK安裝包的權限,即確認開發者在AndroidManafest.xml中聲明的權限。當然,Google在Android上也做了一些操作,允許一些系統內部的應用不經過授權界面直接進行安裝。而系統進入安裝界面其實也是根據此intent跳轉到了PackageInstaller應用來完成權限的提示與安裝的。
這里寫代碼片`我們在應用程序中控制安裝應用APP,其實就是發送一個如下的intent。去調用packageinstaller進行安裝,具體的操作代碼如下:
/* 安裝apk */ Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType(Uri.parse("file://"+ fileName),"application/vnd.android.package-archive"); context.startActivity(intent);對比應用正常安裝的流程,靜默安裝的本質就是去掉如下圖所示的用戶授權同意安裝的過程,直接進行應用安裝。
源碼分析
閱讀過源碼后我們知道,系統的安裝過程其實是調用了系統中的PackageInstaller來完成的。希望做到靜默安裝,就是找到一個方法,繞過PackageInstaller中的權限授予提示,繼續完成安裝的步驟。
所以,思路很簡單,我們可以從兩方面去操作:
- 找到PackageInstaller源碼,跳過權限授予提醒,直接調用后面的安裝API即可完成安裝。(這樣能夠良好的兼容正常安裝,不易出錯)
- 使用pm install 命令進行安裝。
調用PackageInstaller中隱藏的API
查看PackageInstaller源碼我們能夠發現,其實PackageInstaller也是通過使用PackageManager進行安裝的。調用的是其installPackage方法,但是此方法是一個abstract,且是對外不可見的(hide),
定義如下所示:
public abstractclass PackageManager { ……… /*** 安裝應用APK文件* @param packageURI 待安裝的APK文件位置,可以是'file:'或'content:' URI.* @param observer 一個APK文件安裝狀態的觀察器* @param flags 安裝形式 INSTALL_FORWARD_LOCK, INSTALL_REPLACE_EXISTING, INSTALL_ALLOW_TEST.* @paraminstallerPackageName APK安裝包的PackageName*/ // @SystemApi public abstract void installPackage(UripackageURI, PackageInstallObserverobserver,int flags,StringinstallerPackageName); }且PackageManager與installPackage兩者皆為abstract抽象的。其具體實現都在ApplicationPackageManager中,其installPackage中的實現為:
final classApplicationPackageManager extends PackageManager {......ApplicationPackageManager(ContextImpl context, IPackageManager pm) {mContext = context;mPM = pm;}@Overridepublic void installPackage(Uri packageURI, IPackageInstallObserver observer,intflags, String installerPackageName){try {mPM.installPackage(packageURI, observer, flags, installerPackageName);} catch (RemoteException e) {// Should never happen!}} }可見調用的installPackage方法為IPackageManager中的installPackage方法。在ContextImpl中通過調用
ActivityThread.getPackageManager()獲得IPackageManager實例對象。而在在ActivityThread.getPackageManager()方法中,是調用SystemService中的名為package的Service來實例化的。代碼如下:
因為,installPackage是系統的API,為了使用PackageManagerService.installPackage(),考慮通過反射機制可以調用installPackage()。
但其中難以得到的是其參數中的IPackageInstallObserver類型,我們看來一下IPackageInstallObserver,發現IPackageInstallObserver是由aidl文件定義的。這個也難不倒我們,通過aidl文件的特性,將IPackageInstallObserver.aidl文件拷到本地程序中,可以得到類IPackageInstallObserver.calss,通過它反射出installPackage()方法。
但在invoke調用該方法時,卻無法得到IPackageInstallObserver的實例對象,IPackageInstallObserver的實例對象必須通過IPackageInstallObserver.Stub.asInterface(Binder binder)方式得到,無法得到與其綁定的Binder對象,因而無法執行反射出來的方法。
其次,應為是系統API,需要聲明安裝應用的權限:android.permission.INSTALL_PACKAGES。當時這類比較敏感的權限不是說聲明系統就會給予的,還需要我們的安裝包APK文件擁有與系統相同的簽名,才能完成靜默安裝操作。這個方式的靜默安裝,對于廣泛的推廣應用是不現實的。
使用pm命令安裝
pm 命令是Android里面PackageManage的命令行,用于安裝包的操作。而系統也主要是提供我們在adb
shell中進行使用pm命令,因此pm命令也存在與“/system”目錄下,當然,擁有了Root權限后的應用程序就能夠使用它進行靜默安裝了。
具體的操作代碼如下所示:
// xxx.apk放置在內置儲存的根目錄下 execCommand("system/bin/pminstall -r " + "sdcard/xxx.apk"); // 執行command public booleanexecCommand(String cmd) {Process process = null;try {process = Runtime.getRuntime().exec(cmd);process.waitFor();} catch (Exception e) {return false;} finally {try {process.destroy();} catch (Exception e) {}}return true; }pm命令源碼目錄:
/frameworks/base/cmds/pm/src/com/android/commands/pm/Pm.java,
我們查看其源碼,如下:
public finalclass Pm {IPackageManager mPm;IUserManager mUm;private WeakHashMap<String, Resources> mResourceCache= new WeakHashMap<String, Resources>();private String[] mArgs;private int mNextArg;private String mCurArgData;private static final String PM_NOT_RUNNING_ERR ="Error: Could not access thePackage Manager. Is the systemrunning?";public static void main(String[] args) {new Pm().run(args);}/*** 解析命令參數* @param args 參數*/public void run(String[] args) {boolean validCommand = false;if (args.length < 1) {showUsage();return;}mUm =IUserManager.Stub.asInterface(ServiceManager.getService("user"));mPm =IPackageManager.Stub.asInterface(ServiceManager.getService("package"));if (mPm == null) {System.err.println(PM_NOT_RUNNING_ERR);return;}......if("install".equals(op)) {runInstall();return;}......}/*** 開始安裝*/private void runInstall() {......// 安裝邏輯的具體調用PackageInstallObserver obs = newPackageInstallObserver();try {VerificationParamsverificationParams = new VerificationParams(verificationURI,originatingURI, referrerURI, VerificationParams.NO_UID,null);mPm.installPackageWithVerificationAndEncryption(apkURI, obs, installFlags,installerPackageName, verificationParams, encryptionParams);synchronized (obs) {while (!obs.finished) {try {obs.wait();} catch(InterruptedException e) {}}if (obs.result ==PackageManager.INSTALL_SUCCEEDED) {System.out.println("Success");} else {System.err.println("Failure["+installFailureToString(obs.result)+ "]");}}} catch (RemoteException e) {System.err.println(e.toString());System.err.println(PM_NOT_RUNNING_ERR);}}...... }發現其實pm命令也是調用了PackageManager中的安裝方法,只不過是一個驗證和加密的方法installPackageWithVerificationAndEncryption進行安裝的。即,它的安裝過程與PackageInstaller是一樣的。
而我們安裝應用APP的時候,可以是自己的APK安裝包文件存儲在兩個地方“data/app”與“system/app”下,靜默安裝的時候一般情況都是選擇將自己的APK文件push到“system/app”目錄下, 因為此目錄是系統應用的目錄,在此目錄下的惡意應用,進行偷發短信、竊取郵件等操作,用戶是很難察覺的。
刪除預裝
大部分的普通用戶Root手機的主要目的就是刪除系統預先安裝的應用程序,要刪除它們,我們首先要知道什么是預裝應用,它們存放在哪里。或者我們換一個思路來看看,系統制造商將應用程序的APK文件存放在哪里才能變為系統的應用。
1. 系統默認的常規應用存放處
Android系統的捆綁應用軟件基本安裝在“/system/app”文件夾下,刪除下面的對應的了第三方軟件APK文件即可完美卸載。我們知道“/system”是系統的目錄,對此目錄進行操作需要Root權限,所以我們刪除預裝應用需要Root手機。每個系統程序基本上都是成對的,對應的刪除掉后綴分別是.apk 和.odex(優化過的dex文件)文件即可刪除預裝應用。
如下圖,使用了Root Explorer查看“/system/app”目錄。則能夠看到了系統中的所有的系統內置應用程序。
2. 修改系統引導的預裝
對于存放Apk文件到”/system/app“目錄下已經是很普通的預裝方式了,這就導致了,預裝應用很容易就被卸載掉。惡意的手機ROM就會想著更加惡心的方法來留住預裝應用,比如修改系統ROM的邏輯,讓系統在開機的時候檢測一下自己的預裝是否完整然后重新安裝。那么,當然系統預裝應用的安裝文件也會在另一個保存一份。
這類的預裝應用,又稱為“開機靜默安裝”,常用的方式就是修改init.rc,添加一個開機執行的腳本,在腳本中調用一個Service使用pm install命令批量安裝應用。
如,自頂一個一個init.local.rc內容如下:
在系統的init.rc腳本中調用init.local.rc如下:
#在sysinit前面加 # Include extrainit fileimport /system/etc/init.local.rc而具體的預裝腳本存在/system/bin/ loadpreinstalls.sh# do preinstall job if [ ! -e /data/.notfirstrun ] then echo "dopreinstall sys" >> /system/log.txt #安裝/system/preinstall下的所有apk文件APKLIST=`ls /system/preinstall/*.apk`for INFILES in $APKLISTdoecho setup package:$INFILESpm install -r $INFILESdoneecho "dopreinstall sd" >> /system/log.txt #安裝/sdcard/preinstall下的所有apk文件APKLIST=`ls /sdcard/preinstall/*.apk`for INFILES in $APKLISTdoecho setup package:$INFILESpm install -r $INFILESdoneecho "do preinstall ok" >> /system/log.txtbusybox touch /data/.notfirstrun fiecho "============================================">> /system/log.txt exit此方式做預裝用戶在使用Root后刪除掉/system/app下的已安裝應用后,系統重啟后又會執行啟動腳本自動重裝預裝應用回來,且預裝apk文件的存放目錄根據不同的系統ROM還不一樣,是極為流氓的推廣策略。當然,我們通過分析已經看到了,如果要刪除此類的預裝應用,只需要全盤的掃描apk文件再進行刪除即可。
/*
* @author zhoushengtao(周圣韜)
* @since 2015年1月27日 上午14:02:22
* @weixin stchou_zst
* @blog http://blog.csdn.net/yzzst
* @交流學習QQ群:341989536
* @私人QQ:445914891
/
總結
以上是生活随笔為你收集整理的Android系统Root与静默安装的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Informix创建/修改主键
- 下一篇: 2021鸿蒙系统什么时候上线 鸿蒙支持哪