Android system debugging
· 10 min read

Rooted Android detection: userspace signals and attestation limits

This reference groups the original device investigation by observation layer: packages, features, permissions, properties, mounts, logs and attestation. Each table entry describes a local change or a remaining limit in that setup. It is not a guarantee about every app, ROM, hardware root of trust or server-side decision.

ChannelProbeCountermeasureLayer
Package listgetInstalledPackagesHideMyApplistsystem_server
System featureshasSystemFeatureStockMasksystem_server
Custom permissionspermission enumStockMasksystem_server
Build identityBuild.FINGERPRINTresetprop / PIFproperty layer
Boot statero.boot.verifiedbootstateresetpropproperty layer
Root binariesFile.exists("/system/bin/su")Magiskimage/mount layer
Process listenumerate /proc/<pid>hidepid=invisiblekernel
In-process hooks/proc/self/mapsShamiko denylistinjection layer
Magisk mounts/proc/self/mountinfoShamikoper-app namespace
Global /proccmdlinebind-mountglobal /proc
Custom servicesgetServicedeny ... findSELinux
Device logsREAD_LOGSrevoke + StockMasklogd/SELinux
Isolated /proccmdline inside namespaceNonekernel
AttestationsetAttestationChallengeNoneTEE

I filtered responses in system_server by caller UID, keeping injected code out of the app processes. The returned information also had to agree across interfaces: a single mismatched partition fingerprint triggered RASP alerts instantly.

Two limits remained beyond these userspace changes:

+--------------------------------+       +--------------------------------+
|  Shamiko-isolated /proc        |       |  Hardware key attestation      |
+--------------------------------+       +--------------------------------+
| Isolation hides magisk mounts  |       | The TEE reports the real boot- |
| but restores the real cmdline. |       | loader state. Strict backends  |
| A module can't reach it; only  |       | reject forgeries.              |
| a boot-image/kernel edit does. |       | Only stock passes.             |
+--------------------------------+       +--------------------------------+

First, Shamiko’s mount-namespace isolation gives the app a clean view, stripping Magisk bind-mounts. But doing so restores the genuine /proc/self/cmdline and /proc/version. Since my Zygisk module didn’t inject into the isolated app, there was no code present to rewrite those files.

Second, the Android Key Attestation (Google, 2024) checks the hardware-reported boot state. The TEE records the boot state natively and signs it via a key userspace cannot read. A forged chain can satisfy local checks, but server-side validation against the hardware root fails instantly. A userspace module cannot produce a signature with the TEE’s private key.

For the attestation boundary, read the Wallet card-add investigation; for test context, use the app-context audit.

androiddetectionsynthesisrasp

Comments