Hide Veil itself from target apps by default
An installed hooking module is as much a tell as a root manager, but Veil's own package wasn't in the hidden list, so any scoped app could find it with getPackageInfo or the installed-package lists. It's now a default alongside KernelSU and Magisk. DEFAULT_HIDDEN_PACKAGES only applies while no list has been saved, so a one-time migration adds Veil to an existing list the first time the settings screen opens; a flag stops it from re-adding Veil after a manual removal. Discovery is unaffected: the hooked process resolves Veil's provider through ActivityManager, not the hooked ApplicationPackageManager. Verified on device (Android 16, Vector) with Veil Probe: getPackageInfo for Veil now throws NameNotFoundException, the probe still registers, and every other hooked path stays hidden. Co-Authored-By: agent <agent@bdeshi.space>
This commit is contained in:
4 files changed
+22
-5
No files matched your search
@@ -35,7 +35,7 @@ Per app, per feature — anything not listed gets everything hidden by default.
|
|||||||
| USB / wireless debugging | `adb_enabled` / `adb_wifi_enabled` |
|
| USB / wireless debugging | `adb_enabled` / `adb_wifi_enabled` |
|
||||||
| Developer options | Developer Options enabled state |
|
| Developer options | Developer Options enabled state |
|
||||||
| Mock location | Legacy pre-Marshmallow flag only |
|
| Mock location | Legacy pre-Marshmallow flag only |
|
||||||
| Root / manager apps | Configurable package list (default: KernelSU, Magisk) |
|
| Root / manager apps | Package list (default: KernelSU, Magisk, Veil itself) |
|
||||||
| Build tags/type | Real build swapped for `release-keys` / `user` |
|
| Build tags/type | Real build swapped for `release-keys` / `user` |
|
||||||
|
|
||||||
Doesn't cover native-level root/hook detection or remote attestation (Play Integrity,
|
Doesn't cover native-level root/hook detection or remote attestation (Play Integrity,
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ package space.bdeshi.veil
|
|||||||
data class FeatureInfo(val label: String, val description: String)
|
data class FeatureInfo(val label: String, val description: String)
|
||||||
|
|
||||||
object Features {
|
object Features {
|
||||||
|
const val SELF_PACKAGE = "space.bdeshi.veil"
|
||||||
const val PREFS_NAME = "veil_prefs"
|
const val PREFS_NAME = "veil_prefs"
|
||||||
const val KEY_PREFIX = "features_"
|
const val KEY_PREFIX = "features_"
|
||||||
const val HIDDEN_PACKAGES_KEY = "hidden_packages"
|
const val HIDDEN_PACKAGES_KEY = "hidden_packages"
|
||||||
const val DISCOVERED_PACKAGES_KEY = "discovered_packages"
|
const val DISCOVERED_PACKAGES_KEY = "discovered_packages"
|
||||||
|
const val SELF_HIDDEN_MIGRATED_KEY = "self_hidden_migrated"
|
||||||
const val PROVIDER_AUTHORITY = "space.bdeshi.veil.provider"
|
const val PROVIDER_AUTHORITY = "space.bdeshi.veil.provider"
|
||||||
|
|
||||||
const val ACCESSIBILITY = "accessibility"
|
const val ACCESSIBILITY = "accessibility"
|
||||||
@@ -52,9 +54,13 @@ object Features {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Veil itself belongs here too: an installed hooking module is as much a tell as a root
|
||||||
|
// manager. Hiding it from PackageManager doesn't affect discovery, which resolves Veil's
|
||||||
|
// provider through ActivityManager rather than the hooked ApplicationPackageManager.
|
||||||
val DEFAULT_HIDDEN_PACKAGES: Set<String> = setOf(
|
val DEFAULT_HIDDEN_PACKAGES: Set<String> = setOf(
|
||||||
"me.weishu.kernelsu",
|
"me.weishu.kernelsu",
|
||||||
"com.topjohnwu.magisk",
|
"com.topjohnwu.magisk",
|
||||||
|
SELF_PACKAGE,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun keyFor(packageName: String): String = KEY_PREFIX + packageName
|
fun keyFor(packageName: String): String = KEY_PREFIX + packageName
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
prefs = getSharedPreferences(Features.PREFS_NAME, Context.MODE_PRIVATE)
|
prefs = getSharedPreferences(Features.PREFS_NAME, Context.MODE_PRIVATE)
|
||||||
|
migrateSelfIntoHiddenList()
|
||||||
|
|
||||||
val padding = dp(16)
|
val padding = dp(16)
|
||||||
val root = LinearLayout(this).apply {
|
val root = LinearLayout(this).apply {
|
||||||
@@ -203,6 +204,18 @@ class SettingsActivity : AppCompatActivity() {
|
|||||||
return cardView to content
|
return cardView to content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A list saved before Veil joined DEFAULT_HIDDEN_PACKAGES never picks up the new default,
|
||||||
|
// so add it once. The flag keeps a later manual removal from being undone.
|
||||||
|
private fun migrateSelfIntoHiddenList() {
|
||||||
|
if (prefs.getBoolean(Features.SELF_HIDDEN_MIGRATED_KEY, false)) return
|
||||||
|
val editor = prefs.edit().putBoolean(Features.SELF_HIDDEN_MIGRATED_KEY, true)
|
||||||
|
if (prefs.contains(Features.HIDDEN_PACKAGES_KEY)) {
|
||||||
|
editor.putStringSet(Features.HIDDEN_PACKAGES_KEY, hiddenPackages() + Features.SELF_PACKAGE)
|
||||||
|
}
|
||||||
|
editor.apply()
|
||||||
|
fixPermissions()
|
||||||
|
}
|
||||||
|
|
||||||
private fun hiddenPackages(): Set<String> =
|
private fun hiddenPackages(): Set<String> =
|
||||||
prefs.getStringSet(Features.HIDDEN_PACKAGES_KEY, Features.DEFAULT_HIDDEN_PACKAGES) ?: Features.DEFAULT_HIDDEN_PACKAGES
|
prefs.getStringSet(Features.HIDDEN_PACKAGES_KEY, Features.DEFAULT_HIDDEN_PACKAGES) ?: Features.DEFAULT_HIDDEN_PACKAGES
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ import de.robv.android.xposed.XSharedPreferences
|
|||||||
import de.robv.android.xposed.XposedHelpers
|
import de.robv.android.xposed.XposedHelpers
|
||||||
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam
|
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam
|
||||||
|
|
||||||
private const val SELF_PACKAGE = "space.bdeshi.veil"
|
|
||||||
|
|
||||||
// Keyed by the Settings class each key actually lives on, so we only ever install hooks on
|
// Keyed by the Settings class each key actually lives on, so we only ever install hooks on
|
||||||
// the one class that could plausibly be asked about a given feature — never both.
|
// the one class that could plausibly be asked about a given feature — never both.
|
||||||
private val SECURE_NULL_STRING_KEYS_BY_FEATURE = mapOf(
|
private val SECURE_NULL_STRING_KEYS_BY_FEATURE = mapOf(
|
||||||
@@ -46,7 +44,7 @@ private fun keysForEnabledFeatures(
|
|||||||
class VeilHook : IXposedHookLoadPackage {
|
class VeilHook : IXposedHookLoadPackage {
|
||||||
|
|
||||||
override fun handleLoadPackage(lpparam: LoadPackageParam) {
|
override fun handleLoadPackage(lpparam: LoadPackageParam) {
|
||||||
if (lpparam.packageName == SELF_PACKAGE) return
|
if (lpparam.packageName == Features.SELF_PACKAGE) return
|
||||||
|
|
||||||
reportScoped(lpparam)
|
reportScoped(lpparam)
|
||||||
|
|
||||||
@@ -114,7 +112,7 @@ class VeilHook : IXposedHookLoadPackage {
|
|||||||
|
|
||||||
private fun openPrefs(): XSharedPreferences? {
|
private fun openPrefs(): XSharedPreferences? {
|
||||||
return try {
|
return try {
|
||||||
XSharedPreferences(SELF_PACKAGE, Features.PREFS_NAME).apply { reload() }
|
XSharedPreferences(Features.SELF_PACKAGE, Features.PREFS_NAME).apply { reload() }
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user