Knowledge Center / Mobile runtime attacks / mobile runtime attacks · 2026·01
Root cloaking — hiding root state from in-app checks
Root cloaking is the family of techniques that present a clean device profile to in-app integrity probes while the device is, in fact, rooted. Magisk's Hide (legacy) and DenyList (current) hide the rooted state from heuristic checks and from many platform-level probes. They do not, and cannot, hide the rooted state from hardware-backed attestation — the chip signs the bootloader state, and the bootloader was unlocked.
1. Mechanism
Magisk’s DenyList [1] is the modern packaging of root cloaking on Android (Magisk Hide was removed in Magisk v24, January 2022; the DenyList + Zygisk + optional Shamiko stack replaced it). It maintains a list of packages from which Magisk’s modifications to the system should be hidden. When a process on the list starts, Magisk arranges for it to run in a mount namespace where:
- The Magisk binary is not visible in
/proc/<pid>/maps. - Magisk-installed paths (the randomised
supath under/data/adbon modern Magisk; the module directories) do not appear when enumerated by the target. - System properties Magisk normally modifies are presented with their original values to the target.
- The Magisk daemon socket is renamed at random and hidden from the target’s view of the filesystem.
The effect is that an in-app heuristic probe — checking for an
su path, reading ro.debuggable, listing /data/adb/modules,
calling Runtime.exec("which su") — sees a clean device. The
probe is not lying; the platform genuinely returns the clean
values to that process’s view.
2. Where in the runtime it operates
DenyList is a userspace mechanism: the magiskd daemon and
Zygisk (a Zygote-injected runtime) cooperate to give denylisted
processes an isolated mount namespace that does not contain
Magisk’s bind-mounted overlays. There is no kernel module on
modern Magisk and no syscall interception — the isolation is at
the VFS / mount-namespace layer. Because the denylisted process
sees an unmodified namespace, libc-level filesystem and property
probes that route through the standard mount table return clean
values; many libc-level checks therefore fail to detect the
rooted state. (Sufficiently well-targeted detection — checking
for SELinux context drift, parent-process anomalies, or
attestation-state mismatch — can still surface signal.)
What DenyList cannot reach: the Trusted Execution Environment.
The TEE runs in a separate execution context and is not
addressable by code running in the Linux kernel space. When the
TEE signs an attestation that includes the RootOfTrust block
[2] — verifiedBootKey, verifiedBootState, deviceLocked,
verifiedBootHash — those values come from the chip’s view of
the boot chain. The chip knows whether the bootloader was
unlocked. Magisk cannot rewrite that.
3. Which checkpoints it bypasses
- In-app heuristic probes. Defeated for most file /
property / process probes that route through the standard
filesystem view; defeated for
Runtime.exec("which su")and similar shell-out checks. Probes that look at SELinux context, parent-process anomalies, or attestation-state mismatch can still surface signal. MEETS_DEVICE_INTEGRITY. Often defeated when DenyList is paired with a current device-profile workaround. Google iterates against this; the workaround is a moving target.MEETS_STRONG_INTEGRITY. Generally not defeated [3]. This verdict requires hardware-backed evaluation, which reads the RootOfTrust block.- Android Key Attestation. Not defeated. The chain validates
against Google and OEM intermediate roots, but the embedded
RootOfTrustblock declares the unlocked bootloader, and an operator that checksverifiedBootState != Verifiedrejects the device.
4. Which signals make it observable
device.integrity. The Trusted Runtime Primitive includes the
hardware-attestation chain (where available) on each Evidence
Token, with the RootOfTrust block decoded and surfaced as
discrete fields. The substrate also collects multi-layered
heuristic probes — but treats them as supporting evidence, not
as authority. The authority is the chip-signed RootOfTrust.
5. Evidence Token shape when observed
The following example is illustrative; field names, type values, and schema are defined in YEI-001 §4 (available through the spec-access process).
{
"ev": [{
"ts": "2026-06-15T10:23:14Z",
"class": "device.integrity",
"type": "root_of_trust.read",
"data": {
"verified_boot_state": "Unverified",
"device_locked": false,
"verified_boot_key": "f8:23:…:ce",
"heuristic_probes": {
"su_binary_present": false,
"magisk_paths_visible": false,
"comment": "probes clean — but RootOfTrust says unlocked"
}
}
}]
}
The discrepancy between the (cloaked) heuristic probes and the (uncloaked) RootOfTrust is itself a useful signal — and the discrepancy is what Execution Evidence Infrastructure (EEI) — the device-identity infrastructure layer for banking and payments — surfaces in the signed evidence record.
6. Cross-references
- Sibling articles:
magisk-zygisk-modules,hook-detection-bypass - Theme 2:
hardware-attestation,play-integrity - Architecture:
/architecture/zero-trust-bootstrap
7. External references
[1] Magisk. User documentation — DenyList. topjohnwu.github.io/Magisk/install.html. Cited 2026-01-28.
[2] AOSP. Keymaster Tag specification — RootOfTrust. source.android.com/docs/security/features/keystore/tags. Cited 2026-01-28.
[3] Google. Play Integrity STRONG verdict requirements. developer.android.com/google/play/integrity/verdicts-and-remediation. Cited 2026-01-28.