From 299b2653e1a280ff6438cdcb2fa76447b087b4e4 Mon Sep 17 00:00:00 2001 From: Wang Han <416810799@qq.com> Date: Sun, 26 Jul 2026 12:19:08 +0800 Subject: [PATCH] Handle previous signature special case correctly --- .../hook/InstallPackageHelperHook.kt | 88 ++++++++++++++++--- 1 file changed, 77 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/org/lsposed/corepatch/hook/InstallPackageHelperHook.kt b/app/src/main/java/org/lsposed/corepatch/hook/InstallPackageHelperHook.kt index 43db50e..0e89070 100644 --- a/app/src/main/java/org/lsposed/corepatch/hook/InstallPackageHelperHook.kt +++ b/app/src/main/java/org/lsposed/corepatch/hook/InstallPackageHelperHook.kt @@ -3,8 +3,10 @@ package org.lsposed.corepatch.hook import android.annotation.SuppressLint import android.os.Build import org.lsposed.corepatch.Config +import org.lsposed.corepatch.XposedHelper.getOriginInvoker import org.lsposed.corepatch.XposedHelper.hookAfter import org.lsposed.corepatch.XposedHelper.hostClassLoader +import org.lsposed.corepatch.XposedHelper.log object InstallPackageHelperHook : BaseHook() { override val name = "InstallPackageHelperHook" @@ -17,18 +19,82 @@ object InstallPackageHelperHook : BaseHook() { hostClassLoader.loadClass("com.android.server.pm.InstallPackageHelper") val doesSignatureMatchForPermissionsMethod = installPackageHelperClazz.declaredMethods.first { m -> m.name == "doesSignatureMatchForPermissions" } - hookAfter(doesSignatureMatchForPermissionsMethod) { callback -> - if (Config.isBypassDigestEnabled() && Config.isUsePreviousSignaturesEnabled()) { - // If we decide to crack this then at least make sure they are same apks, avoid another one that tries to impersonate. - if (callback.result == false) { - val getPackageNameMethod = - callback.args[1]!!.javaClass.declaredMethods.first { m -> m.name == "getPackageName" } - val packageName = getPackageNameMethod.invoke(callback.args[1]) as String - if (packageName == callback.args[0] as String) { - callback.result = true - } - } + val doesSignatureMatchForPermissionsInvoker = + getOriginInvoker(doesSignatureMatchForPermissionsMethod) + val parsedPackageClass = doesSignatureMatchForPermissionsMethod.parameterTypes[1] + val getPackageNameMethod = parsedPackageClass.methods.first { method -> + method.name == "getPackageName" && method.parameterCount == 0 + }.apply { isAccessible = true } + val installedPackages = createInstalledPackageLookup(installPackageHelperClazz) + + hookAfter(doesSignatureMatchForPermissionsMethod) hook@{ callback -> + if (!Config.isBypassDigestEnabled() || !Config.isUsePreviousSignaturesEnabled()) { + return@hook + } + if (callback.result != false) return@hook + + val parsedPackage = callback.args[1] ?: return@hook + val packageName = getPackageNameMethod.invoke(parsedPackage) as? String ?: return@hook + val sourcePackageName = callback.args[0] as? String ?: return@hook + if (packageName == sourcePackageName) { + callback.result = true + return@hook + } + + val helper = callback.thisObject ?: return@hook + val oldPackage = installedPackages?.invoke(helper, packageName) ?: return@hook + if (!parsedPackageClass.isInstance(oldPackage)) return@hook + + val matches = runCatching { + doesSignatureMatchForPermissionsInvoker?.invoke( + helper, + sourcePackageName, + oldPackage, + callback.args[2], + ) as? Boolean == true + }.getOrElse { throwable -> + log("[$name] failed to check the installed package signature", throwable) + false } + if (matches) callback.result = true } } + + private fun createInstalledPackageLookup( + installPackageHelperClazz: Class<*> + ): ((Any, String) -> Any?)? = + runCatching { + val packageManagerField = installPackageHelperClazz.getDeclaredField("mPm").apply { + isAccessible = true + } + val packageManagerClazz = packageManagerField.type + val snapshotComputerMethod = packageManagerClazz.declaredMethods.first { method -> + method.name == "snapshotComputer" && method.parameterCount == 0 + }.apply { isAccessible = true } + val getPackageStateMethod = + snapshotComputerMethod.returnType.declaredMethods.first { method -> + method.name == "getPackageStateInternal" && + method.parameterTypes.contentEquals(arrayOf(String::class.java)) + }.apply { isAccessible = true } + val getAndroidPackageMethod = + getPackageStateMethod.returnType.methods.first { method -> + method.name == "getAndroidPackage" && method.parameterCount == 0 + }.apply { isAccessible = true } + + val lookup: (Any, String) -> Any? = { helper, packageName -> + runCatching { + val packageManager = packageManagerField.get(helper) + val computer = snapshotComputerMethod.invoke(packageManager) + val packageState = getPackageStateMethod.invoke(computer, packageName) + packageState?.let { getAndroidPackageMethod.invoke(it) } + }.getOrElse { throwable -> + log("[$name] failed to find the installed package", throwable) + null + } + } + lookup + }.getOrElse { throwable -> + log("[$name] installed package lookup is unavailable", throwable) + null + } }