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 <agent@bdeshi.space>
This commit is contained in:
bdeshiandagent committed 2026-11-03 20:19:02 +06:00
1 parent eebba2f9f1
commit 32c926841b
1 file changed
+52
@@ -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 {