Appium 为什么会被检测
用 Appium 做 App 自动化(抢票、薅羊毛、批量操作)时,经常遇到"脚本一跑就触发验证,手动操作就没事"——App 检测到了自动化框架。检测点分几层:
1. 系统属性层
Appium 驱动基于 UIAutomator2/Espresso,会在系统里留特征:
// 检测代码的典型实现
// UIAutomator2 的服务端口和包名特征
getSystemService("uiautomator") != null
// 或检测已安装包
pm.getInstalledPackages() 包含 "io.appium.uiautomator2.server"2. 输入事件层
Appium 的点击/滑动通过系统 API 注入,事件特征和真实触摸不同:
MotionEvent.getToolType():真实触摸是TOOL_TYPE_FINGER,注入的可能是其他值- 事件的
downTime/eventTime间隔模式:真实操作有自然抖动,脚本的事件时间戳过于规整 - 压力值(pressure)和接触面积(size):真实手指按压有值且变化,注入事件常为固定值
3. 行为层
脚本的操作路径、速度、坐标精度(每次都点正中心)都是统计特征。
绕过方案
系统属性层:root 后卸载/冻结 Appium 的服务包(用的时候装,用完冻结),或 Xposed hook 包管理器的查询接口,对 Appium 相关包名返回"未安装"。
输入事件层:放弃 Appium 的事件注入,改用更底层的输入方式:
# 方案1:adb shell input(事件来自 shell 用户,特征比 Appium 少)
adb shell input tap 500 800
adb shell input swipe 300 1000 300 500 800 # 800ms 的滑动
# 方案2:root 后直接写 /dev/input/eventX(最底层,和真实触摸同通道)
# 用 sendevent 命令或自己写程序注入/dev/input 层注入的事件和真实触摸走完全相同的内核通道,应用层无法区分——这是自动化点击的终极方案。
行为层:操作路径拟人化(参考"行为风控"篇):随机坐标偏移、拟人滑动轨迹、随机间隔。
精髓一:检测点逆向先行
别盲目绕过——先逆向 App 的自动化检测代码:
jadx 搜关键词:
"uiautomator" "appium" "isAutomation" "checkAutomation"
MotionEvent.getToolType / getPressure 的调用点把检测清单列出来,逐条对抗。很多 App 的自动化检测其实只做了系统属性层(查 Appium 包名),冻结服务包就过了。
精髓二:Appium 的替代方案对比
| 方案 | 检测难度 | 开发效率 | 适用 |
|---|---|---|---|
| Appium | 易被检测 | 高(API 完善) | 弱检测 App、测试场景 |
| adb input 命令 | 中等 | 低(坐标硬编码) | 简单操作 |
| /dev/input 注入 | 极难检测 | 低 | 强检测 App |
| 无障碍服务(AccessibilityService) | 中等 | 中 | 需要读界面内容的场景 |
| 协议模拟(无 UI) | 不触发 UI 检测 | 高 | 终极方案 |
能协议模拟就别 UI 自动化——UI 自动化天然慢、脆、易被检测,协议层方案在所有维度碾压。UI 自动化只用于协议无法覆盖的场景(如必须真人交互的验证环节)。
精髓三:无障碍服务的双刃剑
很多"脚本 App"(按键精灵、自动点击器)基于无障碍服务实现。检测无障碍的方法:
// App 检测无障碍服务列表
AccessibilityManager am = ...;
am.getEnabledAccessibilityServiceList(...) // 有可疑服务即判定绕过:Xposed hook 该方法返回空列表。但注意无障碍服务本身也是业务能力(能读屏幕内容做智能决策),对抗检测的同时可以合法使用它的能力——这是"按键精灵类"工具的技术底座。
总结
- Appium 检测三层:系统属性、输入事件特征、行为统计
- 终极输入方案是 /dev/input 层注入,与真实触摸同通道
- 先逆向检测代码列清单,很多 App 只查了包名
- 能协议模拟就别 UI 自动化,维度碾压
交流微信:run1255