一. 簽名分析
使用:
Auto-sign 執(zhí)行命令
? ? java -jar signapk.jar testkey.x509.pem testkey.pk8 update.apk update_signed.apk
通過signapk.jar這個可執(zhí)行jar包叛氨,以“testkey.x509.pem”這個公鑰文件和“testkey.pk8”這個私鑰文件對“update.apk”進行簽名浅碾,簽名后的文件保存為“update_signed.apk”
簽名的APK差異:
MANIFEST.MF: 遍歷所有文件entry 逐個生成SHA1的數(shù)字簽名信息自娩,再用Base64進行編碼(build/tools/signapk/SignApk.java addDigestsToManifest)
SHA1數(shù)字簽名痢缎。簡單地說蹬癌,它就是一種安全哈希算法挫鸽,類似于MD5算法缠捌。它把任意長度的輸入睬罗,通過散列算法變成固定長度的輸出(摘要信息)
CERT.SF Manifest患朱,使用SHA1-RSA算法鲁僚,用私鑰進行簽名
CERT.RSA 公鑰簽名, 同時對比差異的位置。
獲取簽名的api:
frameworks/base/core/java/android/content/pm/PackageParser.java
//archiveFilePath指定APK文件路徑裁厅;flags需設(shè)置PackageManager.GET_SIGNATURES
parsePackage(String archiveFilePath, int flags) {
....
//根據(jù)包名收集簽名信息至PackageParser.Package 簽名在PackageParser.Package.mSignatures
packageParser.collectCertificates(pkg, 0);
....
}
二.PMS分析
調(diào)用
PackageManagerService是通過使用Context的getPackageManager,在ContextImpl返回的PackageManager實際上是new的ApplicationPackageManager
概括
1.啟動
和安裝的重要變量 mInstaller(InstallerConnection) 和 mInstallerService (管理安裝)
ApplicationPackageManager.installCommon {mPM.installPackage}-> PMS installPackageAsUser->PMS (doHandleMessage)INIT_COPY-> MCS_BOUND
startCopy->handleStartCopy()
2.Setting.java 解析 packages.xml 對包名信息解析冰沙。
3.解析安裝APK
過程比較繁雜,整理一下調(diào)用關(guān)系更容易分析执虹。從掃描開始:
1. PMS construction { scanDirLI } -> scanDirLI -> scanPackageLI -> scanPackageInternalLI
2. handleStartCopy-> Handler msg case:CHECK_PENDING_VERIFICATION -> processPendingInstall ->
? installPackageLI -> installNewPackageLIF (安裝新apk) -> scanPackageTracedLI -> scanPackageLI -> scanPackageInternalLI
---------------------------------------------------------------------------------------------
? installPackageLI ->? replacePackageLI -> replaceNonSystemPackageLI -> scanPackageTracedLI -> scanPackageLI -> scanPackageInternalLI
? installPackageLI ->? replacePackageLI -> replaceSystemPackageLI -> scanPackageTracedLI -> scanPackageLI -> scanPackageInternalLI
---------------------------------------------------------------------------------------------
? most of method invoke deletePackageLIF ->? deleteSystemPackageLIF
---------------------------------------------------------------------------------------------
? StorageEventListener onVolumeStateChanged ->
? 1.loadPrivatePackages -> loadPrivatePackagesInner -> scanPackageTracedLI -> scanPackageLI -> scanPackageInternalLI
? 2.unloadPrivatePackages -> unloadPrivatePackagesInner -> scanPackageTracedLI -> scanPackageLI -> scanPackageInternalLI
? 3.updateExternalMediaStatus -> updateExternalMediaStatusInner ->
? ? 1.loadMediaPackages -> scanPackageTracedLI -> scanPackageLI -> scanPackageInternalLI
? ? 2.unloadMediaPackages -> scanPackageTracedLI -> scanPackageLI -> scanPackageInternalLI
---------------------------------------------------------------------------------------------
三.修改
分析代碼我們可以從調(diào)用關(guān)系入手 installNewPackageLIF 看起來比較合理拓挥,于是在:
installNewPackageLI
? ? private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
? ? ? ? ? ? UserHandle user, String installerPackageName, String volumeUuid,
? ? ? ? ? ? PackageInstalledInfo res) {
? ? ? ? // Remember this for later, in case we need to rollback this install
? ? ? ? String pkgName = pkg.packageName;
//checkSignature here ok
//2.后來修改在這里使用pkg.mSignatures 是可以的。
if (!checkSystemSignature(pkg.mSignatures)) {
??? res.setError(INSTALL_FAILED_INVALID_APK, "Can't install unsigned apk");
??? return;
}
//getDataUserPackageDirectory will new file in data/data/xxx.xxx(packageName)
? ? ? ? if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
? ? ? ? final boolean dataDirExists = Environment
? ? ? ? ? ? ? ? .getDataUserPackageDirectory(volumeUuid, UserHandle.USER_OWNER, pkgName).exists();
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,
? ? ? ? ? ? ? ? ? ? System.currentTimeMillis(), user);
//checkSignature here only effect first time install
//1. 剛開始是在這里加入 使用newPackage.mSignatures check簽名最后發(fā)現(xiàn)有問題: 只有第一次有效袋励,第二次無法攔截侥啤。
//原因: getDataUserPackageDirectory 在data/data/目錄創(chuàng)建了相應 apk的包名信息導致在 installPackageLI() 檢查mPackages.containsKey(pkgName)
//已經(jīng)包含了創(chuàng)建的包名導致replace = true 從而走到 replacePackageLIF
/*? ?installPackageLI.java
???????? if (replace) {
? ? ? ? ? ? .......
? ? ? ? ? ? ? ? replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
? ? ? ? ? ? ? ? ? ? ? ? installerPackageName, res, args.installReason);
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
? ? ? ? ? ? ? ? ? ? ? ? args.user, installerPackageName, volumeUuid, res, args.installReason);
? ? ? ? ? ? }
? ? ? ? */
檢查簽名:
? 在Android.mk 中有三種簽名,默認是release 簽名茬故。
? LOCAL_CERTIFICATE := platform
? LOCAL_CERTIFICATE := shared
? LOCAL_CERTIFICATE := media
? 需求是除了platform shared media外的的簽名不安裝
? ? public boolean checkSystemSignature(Signature[] sig) {
? ? ? ? synchronized (mPackages) {
? ? ? ? ? ? final PackageParser.Package p2 = mPackages.get("com.android.xxx");
? ? ? ? ? ? if (p2 == null || p2.mExtras == null) {
? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? }
? ? ? ? ? ? final PackageParser.Package p3 = mPackages.get("com.android.xxxxx");
? ? ? ? ? ? if (p3 == null || p3.mExtras == null) {
? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? }
? ? ? ? ? ? final PackageParser.Package p4 = mPackages.get("com.android.xxxxxxx");
? ? ? ? ? ? if (p4 == null || p4.mExtras == null) {
? ? ? ? ? ? ? ? Log.d(TAG, "p4 = null");
? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? }
? ? ? ? ? ? if (compareSignatures(sig, p2.mSignatures) == PackageManager.SIGNATURE_MATCH
? ? ? ? ? ? ? ? || compareSignatures(sig, p3.mSignatures) == PackageManager.SIGNATURE_MATCH
? ? ? ? ? ? ? ? || compareSignatures(sig, p4.mSignatures) == PackageManager.SIGNATURE_MATCH) {
? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? }else {
? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? }
? ? ? ? }
? ? }
這樣功能已經(jīng)完成盖灸,最后優(yōu)化下,在installPackageLI 中修改 可以更快的生效 因為 installPackageLI 調(diào)用的 installNewPackageLI.
參考: https://blog.csdn.net/long375577908/article/details/78550913