From 32c926841b3284b21b4ee9b9f775d918653e9faa Mon Sep 17 00:00:00 2001 From: bdeshi Date: Tue, 3 Nov 2026 20:19:02 +0600 Subject: [PATCH] Hide hidden packages from four more PackageManager lookups Veil Probe showed KernelSU and Veil still resolvable through lookups the hooks didn't cover, so an app could find either by skipping getPackageInfo: - getPackageUid(name, flags) -> NameNotFoundException - getPackageInfo(VersionedPackage, flags) -> NameNotFoundException - getApplicationEnabledSetting(name) -> IllegalArgumentException, which is what the real call throws for an unknown package - getLaunchIntentForPackage(name) -> null Same pattern as the existing hooks: set the result or throwable before the original runs, so errors for packages that really don't exist still come from the platform unwrapped. Verified on device with Veil Probe: all eight rows (four lookups x KernelSU and Veil) now report HIDDEN, no LEAK/FAIL/ERROR, and a scoped app still starts. Co-Authored-By: agent --- .../main/java/space/bdeshi/veil/VeilHook.kt | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/app/src/main/java/space/bdeshi/veil/VeilHook.kt b/app/src/main/java/space/bdeshi/veil/VeilHook.kt index d002968..1b5f794 100644 --- a/app/src/main/java/space/bdeshi/veil/VeilHook.kt +++ b/app/src/main/java/space/bdeshi/veil/VeilHook.kt @@ -3,6 +3,7 @@ package space.bdeshi.veil import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo import android.content.pm.PackageManager +import android.content.pm.VersionedPackage import android.os.Build import de.robv.android.xposed.IXposedHookLoadPackage import de.robv.android.xposed.XC_MethodHook @@ -157,6 +158,36 @@ class VeilHook : IXposedHookLoadPackage { } } + // Same lookup keyed by a VersionedPackage rather than a name. + val throwIfVersionedHidden = object : XC_MethodHook() { + override fun beforeHookedMethod(param: MethodHookParam) { + val name = (param.args.getOrNull(0) as? VersionedPackage)?.packageName + if (name != null && name in hiddenPackages) { + param.throwable = PackageManager.NameNotFoundException(name) + } + } + } + + // For an unknown package the real getApplicationEnabledSetting throws an unchecked + // IllegalArgumentException, not NameNotFoundException. + val throwUnknownIfHidden = object : XC_MethodHook() { + override fun beforeHookedMethod(param: MethodHookParam) { + val name = param.args.getOrNull(0) as? String + if (name != null && name in hiddenPackages) { + param.throwable = IllegalArgumentException("Unknown package: $name") + } + } + } + + val nullIfHidden = object : XC_MethodHook() { + override fun beforeHookedMethod(param: MethodHookParam) { + val name = param.args.getOrNull(0) as? String + if (name != null && name in hiddenPackages) { + param.result = null + } + } + } + val filterList = object : XC_MethodHook() { override fun afterHookedMethod(param: MethodHookParam) { @Suppress("UNCHECKED_CAST") @@ -189,6 +220,27 @@ class VeilHook : IXposedHookLoadPackage { } catch (t: Throwable) { // Not present with this signature on this API level. } + try { + XposedHelpers.findAndHookMethod(clazz, "getPackageUid", stringType, flagsType, throwIfHidden) + } catch (t: Throwable) { + // Not present with this signature on this API level. + } + try { + XposedHelpers.findAndHookMethod(clazz, "getPackageInfo", VersionedPackage::class.java, flagsType, throwIfVersionedHidden) + } catch (t: Throwable) { + // Not present with this signature on this API level. + } + } + + try { + XposedHelpers.findAndHookMethod(clazz, "getLaunchIntentForPackage", stringType, nullIfHidden) + } catch (t: Throwable) { + // Not present on this API level. + } + try { + XposedHelpers.findAndHookMethod(clazz, "getApplicationEnabledSetting", stringType, throwUnknownIfHidden) + } catch (t: Throwable) { + // Not present on this API level. } for (flagsType in appFlagsClasses) { try {