Android 6.0 簽名校驗安裝apk

一. 簽名分析

使用:

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()


關(guān)系圖


應用安裝序列圖

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末磺芭,一起剝皮案震驚了整個濱河市赁炎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌徘跪,老刑警劉巖甘邀,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件琅攘,死亡現(xiàn)場離奇詭異垮庐,居然都是意外死亡,警方通過查閱死者的電腦和手機坞琴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門哨查,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人剧辐,你說我怎么就攤上這事寒亥。” “怎么了荧关?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵溉奕,是天一觀的道長。 經(jīng)常有香客問我忍啤,道長加勤,這世上最難降的妖魔是什么仙辟? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮鳄梅,結(jié)果婚禮上叠国,老公的妹妹穿的比我還像新娘。我一直安慰自己戴尸,他們只是感情好粟焊,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著孙蒙,像睡著了一般项棠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上挎峦,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天沾乘,我揣著相機與錄音,去河邊找鬼浑测。 笑死翅阵,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的迁央。 我是一名探鬼主播掷匠,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼岖圈!你這毒婦竟也來了讹语?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤蜂科,失蹤者是張志新(化名)和其女友劉穎顽决,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體导匣,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡才菠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了贡定。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赋访。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖缓待,靈堂內(nèi)的尸體忽然破棺而出蚓耽,到底是詐尸還是另有隱情,我是刑警寧澤旋炒,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布步悠,位于F島的核電站,受9級特大地震影響瘫镇,放射性物質(zhì)發(fā)生泄漏鼎兽。R本人自食惡果不足惜芹壕,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望接奈。 院中可真熱鬧踢涌,春花似錦、人聲如沸序宦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽互捌。三九已至潘明,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間秕噪,已是汗流浹背钳降。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留腌巾,地道東北人遂填。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像澈蝙,于是被迫代替她去往敵國和親吓坚。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容