Knowledge Center / Mobile runtime attacks / mobile runtime attacks · 2026·02
Magisk and Zygisk — rootkit-class module abuse
Magisk is the dominant Android root-management framework. Zygisk is its in-zygote module loader: a Magisk feature that lets modules run code inside the Android zygote process before each app fork. By the time the target app's first line of code runs, Zygisk modules are already mapped into its address space. The injection precedes everything the app does to defend itself.
1. Mechanism
The Android zygote [3] is a long-running process forked at boot
that serves as the parent of every application process. When
ActivityManagerService decides to start an app, it sends a
fork request to the zygote, which copies its address space and
hands the child to the platform’s process-launcher.
Zygisk [2] hooks into this flow. Magisk-mounted as part of the boot sequence, Zygisk attaches to the zygote process and registers a pre-fork callback. When a fork is about to happen, Zygisk:
- Receives the target package’s identity.
- Iterates installed Zygisk modules; each module’s
preAppSpecialize()hook decides whether to inject for this target. - Modules that opt to inject have their native libraries
(
module.sofiles)dlopen-ed into the zygote’s address space. - The fork then proceeds. The child’s address space is a copy of the parent’s — including the just-loaded modules.
The result: when the target app’s Application.onCreate() runs,
the Zygisk modules are already there. There is no opportunity
for the app to detect the modules at startup before they’ve had
a chance to install hooks.
2. Where in the runtime it operates
Three platform layers are involved:
- The Magisk boot stack.
magiskinitruns early — Magisk is mounted into the boot path via a patched boot image, before init has finished bringing up the rest of the system — and re-mounts system partitions to a copy-on-write overlay. Boot integrity is broken at this point — Verified Boot reportsUnverified. - The zygote process. Zygisk attaches a hook into the
zygote’s fork pipeline.
initforks the zygote at boot;system_serveris itself forked from the zygote (sosystem_serveris the zygote’s child, not the other way around), and every app process is also a zygote fork. Zygisk intercepts atpreAppSpecialize/preServerSpecializeso modules are present in the forked child before any app code runs. - The forked app process. The app inherits the modules. Hooks installed into ART, libc, or app-specific symbols can be in place from instruction zero.
3. Which checkpoints it bypasses
MEETS_DEVICE_INTEGRITY. Often defeated by the combination of Zygisk + DenyList + Shamiko + a current device-profile workaround. The device profile reported to Play Integrity comes from a Zygisk-modified set of values.MEETS_STRONG_INTEGRITY. Generally not defeated.MEETS_STRONG_INTEGRITYreads from the chip-level RootOfTrust, which records the unlocked bootloader.- Android Key Attestation. Not defeated for the same reason —
the chain reflects the bootloader state at the chip layer
(
verifiedBootState=Unverified,deviceLocked= false).
4. Which signals make it observable
code.integrity and device.integrity. The Trusted Runtime
Primitive observes:
- The presence of unexpected
.sofiles mapped into the process’s address space at the earliest app callback (Application.attachBaseContext) — these mappings exist before any app code runs because they were inherited from the zygote parent’s address space at fork time. The signal is presence at first user-code observation, inferred from the maps snapshot taken atattachBaseContext;/proc/<pid>/mapsdoes not carry per-mapping load timestamps, so the inference is from order-of-presence, not from a clock. - The chip-level RootOfTrust’s
verifiedBootStatefrom the hardware-attestation chain, which isUnverified(orFailed) whenever Magisk is active. - The Magisk-specific paths and properties when not cloaked (the weakest of the three signals — DenyList / Shamiko target exactly this kind of probe).
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": "verified_boot.unverified",
"data": {
"verified_boot_state": "Unverified",
"device_locked": false,
"source": "key_attestation_extension"
}
},
{
"ts": "2026-06-15T10:23:14.040Z",
"class": "code.integrity",
"type": "lib.zygote_inherited",
"data": {
"lib": "/data/adb/modules/example/lib/arm64/libmod.so",
"evidence": "mapping_present_at_first_app_callback",
"method": "maps_read_in_application_attachBaseContext"
}
}
]
}
The signal is “this .so was already mapped before any user
code ran”, inferred from the maps snapshot taken at the earliest
app callback. Distinguishes Zygisk-style pre-fork injection
(present at fork) from post-launch ptrace injection (mapped
after). Execution Evidence Infrastructure (EEI) — the
device-identity infrastructure layer for banking and payments —
signs the pair (Verified-Boot state + zygote-inherited mappings)
so the operator’s verifier reads both together.
6. Cross-references
- Sibling articles:
root-cloaking,library-injection-frida-xposed,runtime-memory-manipulation - Theme 2:
hardware-attestation - Architecture:
/architecture/zero-trust-bootstrap
7. External references
[1] Magisk. Developer Guide. topjohnwu.github.io/Magisk/guides.html. Cited 2026-02-08.
[2] Magisk. Zygisk API. topjohnwu.github.io/Magisk/guides.html#zygisk. Cited 2026-02-08.
[3] AOSP. Zygote and Application Process. source.android.com/docs/core/runtime/process-lifecycle. Cited 2026-02-08.