Tapjacking¶
Tricking the user into tapping on something they didn't intend to by placing a transparent or partially obscuring overlay over a sensitive UI element. A specific application of overlay attacks focused on manipulating touch events rather than phishing credentials.
Requirements
| Requirement | Details |
|---|---|
| Permission | SYSTEM_ALERT_WINDOW |
| Condition | Target app does not filter obscured touches |
How It Works¶
- Malware draws a transparent or partially transparent overlay over the target UI
- The overlay shows a benign message ("Tap to continue", a game, a fake dialog)
- When the user taps, the touch passes through to the UI element underneath
- The underlying element could be a permission grant button, an install confirmation, or a settings toggle
The key is FLAG_NOT_TOUCHABLE on the overlay window: when set, touches pass through the overlay to whatever is beneath it. The user sees the overlay content but their tap hits the hidden target.
Classic Scenario¶
Malware wants the user to click "Allow" on a permission dialog:
- Permission dialog appears behind the overlay
- Overlay shows an innocuous UI with a button positioned exactly over "Allow"
- User taps the overlay button
- Touch passes through to "Allow"
- Permission granted without user awareness
Variants¶
Full Overlay Passthrough¶
Entire screen covered with FLAG_NOT_TOUCHABLE. User sees the overlay but all touches go to the app behind it. Used to hide what the user is actually interacting with.
Partial Overlay¶
Only part of the screen is covered. The unobscured area contains the target (e.g., the "Install" button), while the overlay hides surrounding context that would alert the user.
Timing-Based¶
The overlay appears and disappears rapidly, showing for just long enough to catch a tap the user was already making. Harder to detect but less reliable.
Android Mitigations¶
| Version | Mitigation | Bypass |
|---|---|---|
| Android 4.0.3 | filterTouchesWhenObscured attribute added |
Opt-in; most apps don't implement it |
| Android 6.0 | SYSTEM_ALERT_WINDOW moved to special permission (Settings toggle) |
Accessibility service can auto-enable |
| Android 8.0 | TYPE_APPLICATION_OVERLAY renders below system dialogs |
Third-party app UIs remain vulnerable |
| Android 12 | System dialogs set FLAG_WINDOW_IS_PARTIALLY_OBSCURED; overlays untouchable over sensitive system UI |
Accessibility gestures bypass all overlay mitigations entirely |
Remaining Gaps¶
filterTouchesWhenObscuredis opt-in. Apps must set it explicitly. Many don't.- Third-party app UIs (not system dialogs) are still vulnerable.
- Accessibility service gestures bypass all overlay-based mitigations entirely.
Detection During Analysis¶
Static Indicators
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLEcombined withTYPE_APPLICATION_OVERLAYand translucent/transparent pixel format- Overlay window dimensions and position matching known system dialog button locations
Families Using This Technique¶
Modern banking trojans have largely moved past tapjacking toward accessibility abuse, which provides more reliable and comprehensive device control. Tapjacking was primarily seen in earlier malware generations (2014-2017) before accessibility service abuse became the standard approach. Current families that use overlays focus on credential phishing via overlay attacks rather than touch manipulation.
However, tapjacking still appears in specific contexts:
| Family | Usage |
|---|---|
| Anatsa | Overlay to trick user into enabling accessibility service by placing transparent "Allow" button over permission dialog |
| MoqHao | Overlay to trick user into granting default SMS app permission |
| Chameleon | Overlay guiding user to disable biometric authentication in favor of PIN entry |
| GoldPickaxe | Overlay prompting facial biometric capture disguised as verification step |
| TrickMo | Overlay to capture the device screen lock PIN, displayed when the user attempts to unlock their phone or open a targeted app |
| SpyNote | Overlay that guides the user step-by-step through enabling accessibility service, showing arrows and instructions over the real Settings UI |
The primary modern use is not stealing tap events (the classic tapjacking definition) but rather using transparent or misleading overlays to guide users through permission-granting flows. This is a social engineering application of the same overlay mechanism.
Accessibility Gesture Alternative¶
The accessibility service API provides dispatchGesture(), which programmatically injects touch events into any app on screen. This eliminates the need for tapjacking entirely -- no overlay required, no user interaction needed.
GestureDescription.Builder builder = new GestureDescription.Builder();
Path clickPath = new Path();
clickPath.moveTo(targetX, targetY);
builder.addStroke(new GestureDescription.StrokeDescription(clickPath, 0, 50));
dispatchGesture(builder.build(), null, null);
With accessibility service access, the malware can:
- Click any button on any screen, including permission grant dialogs
- Perform swipe gestures to navigate through settings menus
- Type text into input fields using
Bundlearguments withACTION_SET_TEXT - Scroll to find specific UI elements using
AccessibilityNodeInfo.ACTION_SCROLL_FORWARD
This is strictly superior to tapjacking in every way. There is no timing dependency, no overlay to detect, and no user action to intercept. The only requirement is that the user has granted accessibility service permission to the malware, which is itself often obtained through tapjacking or overlay-guided social engineering -- creating a bootstrap chain where tapjacking enables the more powerful accessibility approach.
Modern banking trojans (Anatsa, Xenomorph, Hook) use tapjacking or overlay guidance as a one-time step to obtain accessibility access, then switch entirely to dispatchGesture() and AccessibilityNodeInfo actions for all subsequent device manipulation. The overlay is the scaffolding; accessibility is the building.
Testing for Tapjacking Vulnerability¶
Checking App-Level Protection¶
An app is vulnerable to tapjacking if its sensitive UI elements do not reject touches when an overlay is present. The defense is filterTouchesWhenObscured, which can be set per-view in XML or programmatically.
In layout XML:
Or in code:
Or by checking MotionEvent.FLAG_WINDOW_IS_OBSCURED in onTouchEvent() / onFilterTouchEventForSecurity().
To determine if an app is vulnerable, decompile the APK and search for these indicators. If none are present on security-sensitive views (payment confirmation, permission grants, login), the app is likely vulnerable.
Testing with ADB¶
Create a test overlay without writing a full app:
For a more thorough test, use a minimal overlay app or the WindowManager shell commands available on rooted devices. The steps:
- Install a simple overlay app (or use an existing screen dimmer/filter app)
- Activate the overlay so it covers the target app's UI
- Attempt to tap through the overlay onto sensitive buttons
- If the taps register, the app does not filter obscured touches
Automated Detection with Drozer¶
Check for activities that handle sensitive actions and cross-reference with static analysis for filterTouchesWhenObscured usage. Drozer does not directly test tapjacking, but it identifies the attack surface (exported activities with sensitive functionality) that you then test manually with an overlay.
What to Look For¶
| Indicator | Verdict |
|---|---|
filterTouchesWhenObscured="true" on all sensitive views |
Protected |
onFilterTouchEventForSecurity() override checking obscured flag |
Protected |
| No obscured touch handling anywhere in the codebase | Vulnerable |
FLAG_WINDOW_IS_OBSCURED check only on some views |
Partially vulnerable |