YinkoShield

Knowledge Center / Mobile runtime attacks / mobile runtime attacks · 2025·12

Overlay injection — system-overlay UI manipulation on Android

An overlay attack registers a window above the legitimate banking activity, renders an interface that looks like the host app, and captures the user's input there. The host application receives nothing — the user pressed buttons on the overlay's view, which forwards selectively. The mechanism is a documented Android API used legitimately by accessibility tools and password managers; the abuse pattern is well-known.

[ overlay injection — TYPE_APPLICATION_OVERLAY ] [ banking activity ] legitimate Activity from the host app PIN entry · amount · payee drawn by the app — but never received window stack: bottom [ malicious overlay ] TYPE_APPLICATION_OVERLAY PIN entry · amount · payee drawn on top — what the user actually sees captures input above window stack: top // the registration call WindowManager wm = ...; LayoutParams lp = new LayoutParams( TYPE_APPLICATION_OVERLAY, FLAG_NOT_TOUCH_MODAL ‖ ...); wm.addView(view, lp); // requires SYSTEM_ALERT_WINDOW // runtime-grantable on Android < 13 substrate signal: runtime.environment { overlay.detected · type · from_pkg }
A malicious overlay registers as TYPE_APPLICATION_OVERLAY and renders above the legitimate banking activity. The user supplies input to the overlay; the legitimate app receives nothing.

1. Mechanism

A foreground application can request a window of type TYPE_APPLICATION_OVERLAY (introduced in Android 8.0 / API 26 to consolidate the previous TYPE_SYSTEM_ALERT_WINDOW, TYPE_PHONE, TYPE_PRIORITY_PHONE, TYPE_SYSTEM_OVERLAY, and TYPE_SYSTEM_ERROR types), which the platform composites above other application windows [1]. The overlay is drawn by the requesting app and is part of that app’s process; it is not part of whichever activity is nominally in the foreground. With FLAG_NOT_TOUCH_MODAL set, touches outside the overlay’s bounds pass to the window underneath; combined with a non-focusable, partially-transparent overlay, this lets the attacker capture inputs falling on selected regions while the host app continues to render and respond to the rest.

The user-visible effect: the screen looks correct. The PIN screen or amount-confirmation screen rendered by the legitimate banking app is hidden underneath. The user types on what is actually the overlay; the typed values go to the attacker’s process; selectively, control returns to the legitimate app at the moment that produces the most-useful artefact (a credential, a confirmed amount).

2. Where in the runtime it operates

The attack sits in the Android window-manager layer. The relevant calls:

  • WindowManager.addView(View, LayoutParams) registers the overlay window. The LayoutParams.type field is set to TYPE_APPLICATION_OVERLAY.
  • The SYSTEM_ALERT_WINDOW permission is required. It is a special app access (App Ops), not a runtime permission: the app cannot request it via requestPermissions(); the user must navigate to the overlay-permission Settings screen via ACTION_MANAGE_OVERLAY_PERMISSION and grant it there, observable to the app via Settings.canDrawOverlays().
  • Foreground-service rules and notification rules are separate Android changes. From Android 12 (API 31), foreground services must declare a foregroundServiceType and certain types surface system-managed notifications [3]. From Android 13 (API 33), the runtime POST_NOTIFICATIONS permission [4] gates whether the app can post user-visible notifications at all — not specifically an overlay-rule. Operators wanting an overlay-aware notification UX should consult both changes.
  • The platform’s WindowManagerService composites the overlay above the foreground activity. From the host app’s perspective, there is no platform-exposed API to enumerate or block windows that another app drew on top.

3. Which checkpoints it bypasses

  • Play Integrity / SafetyNet (legacy). A device running an overlay attack passes Play Integrity at every tier. The overlay is a legitimate API call from a legitimate app; nothing about the device profile, the boot state, or the calling APK signature changes.
  • App Attest / DeviceCheck. Both produce valid assertions; the attestation is unrelated to the window stack the user is looking at.
  • FIDO2 / WebAuthn. A passkey assertion validly signs a server challenge; the overlay altered what the user thought they were authenticating, not what the authenticator signed.
  • Hardware attestation. The chain validates; the overlay is not a key-provenance attack.

The attack succeeds because none of the standard checkpoints observe the foreground UI compositional state. They observe the device, the app, and the cryptographic call — not what the user saw at the moment of input.

4. Which signals make it observable

runtime.environment and overlay.detected. The canonical platform signal is per-touch: every MotionEvent delivered to a sensitive view carries MotionEvent.FLAG_WINDOW_IS_OBSCURED (API 9+) when another window covered the touch target at the moment of dispatch, and FLAG_WINDOW_IS_PARTIALLY_OBSCURED (API 29+) for partial-overlay cases [5]. The substrate consults these flags on touches received during sensitive surfaces and records them.

The substrate cannot, on a stock non-rooted device, enumerate overlays drawn by other apps directly — Android’s package-visibility rules and the absence of a public “list-foreign-overlay-windows” API mean the per-touch flag is the truth. What the substrate can observe in support is the host process’s own WindowManager interactions, the host app’s view hierarchy not receiving expected touches, and (where the substrate is itself an accessibility-aware host SDK) the accessibility-event stream attribution.

5. Evidence Token shape when observed

When the substrate sees an active overlay during a sensitive event, the Evidence Token includes a runtime.environment event of class overlay.detected. As noted in §4, the source of the overlay signal on a stock non-rooted device is the per-touch FLAG_WINDOW_IS_OBSCURED flag — the identifying package of the overlaying window is not available via this path.

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": "runtime.environment",
    "type":  "overlay.detected",
    "data": {
      "during":         "credential_entry",
      "host_activity":  "com.bank.app.PinEntryActivity",
      "source_flag":    "FLAG_WINDOW_IS_OBSCURED"
    }
  }]
}

The operator’s verifier processes the event alongside the rest of the signed sequence produced by Execution Evidence Infrastructure (EEI) — the device-identity infrastructure layer for banking and payments. The presence of an obscured touch during the credential event is what informs the operator’s decision; an obscured touch outside the credential window may be benign.

6. Cross-references

7. External references

[1] Android Developers. WindowManager.LayoutParams. developer.android.com/reference/android/view/WindowManager.LayoutParams. Cited 2025-12-15.

[2] Android Developers. SYSTEM_ALERT_WINDOW permission. developer.android.com/reference/android/Manifest.permission#SYSTEM_ALERT_WINDOW. Cited 2025-12-15.

[3] Android Developers. Android 12 — Behavior changes: foreground service types and notification requirements. developer.android.com/about/versions/12/behavior-changes-12. Cited 2025-12-15.

[4] Android Developers. Android 13 — Runtime notification permission (POST_NOTIFICATIONS). developer.android.com/about/versions/13/changes/notification-permission. Cited 2025-12-15.

[5] Android Developers. MotionEvent — FLAG_WINDOW_IS_OBSCURED (API 9+), FLAG_WINDOW_IS_PARTIALLY_OBSCURED (API 29+). developer.android.com/reference/android/view/MotionEvent. Cited 2025-12-15.