中文 · English
从手机触摸埋点数据里,判定一次点击 / 滑动来自 人手、软件脚本,还是某一种作弊硬件。
不只是"人机识别"——它会告诉你是哪一种机器。
同一个动作,各重复 250 次,把轨迹叠在一起。 左边是真人,右边是自动化脚本——不需要任何算法,肉眼就能看出区别。
这个项目做的事,是把这种区别拆成 9 个可量化的维度, 让程序不仅能判断"不是人",还能判断"是哪一种机器"。
输入:App 触摸埋点 CSV 输出:
# 未知点击/滑动行为识别报告
- 手势总数:50
- 预测类别数:1
## 总体预测分布
| 预测类别 | 数量 | 占比 |
|--------------------|-----|---------|
| 自动化脚本-屏幕录制 | 50 | 100.00% |
## 分组正式判定
| 分组 | 样本数 | 最低样本量 | 状态 | 最终判断 | 组内主类别占比 |
|--------------------|-------|----------|-------|---------------------|-----------|
| gesture_type=SWIPE | 50 | 30 | 可判定 | 自动化脚本-屏幕录制 | 100.00% |
这份输出可以直接复现:
example_outputs/就是它,输入是仓库里的人工测试数据/touch_20260724_194625*。
每条判定都带证据,不是黑箱打分:
| 实际设备 | 判定 | 证据 |
|---|---|---|
| 机械臂 | 机械臂 | 存在明显接触面积,进入真实接触 / 物理触控分支;接触面积中等、压力偏低、速度波动偏高,符合机械臂 / 物理工具特征 |
| 真人 | 真人 | 存在明显接触面积;接触面积较大、压力更自然且存在压力波动,符合真人触控;滑动速度较高且速度波动处于自然范围 |
| 屏幕录制脚本 | 自动化脚本-屏幕录制 | 接触面积接近 0 且平均压力接近 1,符合注入 / 非真实接触类基础特征;逐点压力波动接近 0;路径冗余率落在录制轨迹常见区间 |
对应的原始特征值:
| 实际设备 | 接触面积 (px²) | 平均压力 | 速度波动系数 |
|---|---|---|---|
| 真人 | 21252 | 0.419 | 0.669 |
| 机械臂 | 8057 | 0.155 | 0.617 |
| 屏幕录制脚本 | 0 | 1.000 | 0.002 |
| 鼠标点击器 | 0 | 0.941 | 0.354 |
| 真人 | 对照基准 |
| 软件类 | 代码开发脚本 · 屏幕录制脚本 · HID |
| 硬件类 | 电容点击器 · 鼠标点击器 · 机械臂 · 自动滑屏点赞器 · 刷屏器一 · 刷屏器二 |
每一类工具的轨迹签名都不一样——这也是"能分辨出是哪一种机器"的直观来源:
从左上到右下依次是:真人、机械臂、鼠标点击器、代码开发脚本、屏幕录制脚本、自动滑屏点赞器、刷屏器一、刷屏器二。同样是 250 次滑动——
- 真人散成一片扇形,起点终点各不相同,还带着自然的弯曲
- 机械臂分布最接近真人,但明显更集中、更有结构(它是最难分辨的一类)
- 代码脚本是一根根笔直的竖线,钉在固定的几个 X 坐标上
- 屏幕录制只剩两条折线——250 次操作,回放的是同一段录制
- 刷屏器和自动滑屏点赞器收缩成一小束,物理电机只会走那一条道
全部结论来自实测。
实验录像截帧。左:机械臂用摄像头看屏幕、机械爪物理点击;中:电容点击器的硅胶头吸在屏幕上;右:鼠标点击器通过蓝牙 HID 驱动。
我们采购了 8 类市售作弊硬件(总计 1863.6 元,从 61.9 元的电容点击器到 1535 元的机械臂),外加自建的软件脚本对照组;在 3 部手机、不同系统版本上,让真人和每一类工具做同样的点击、滑动、长按;覆盖平放 / 竖放 / 手持坐着 / 手持行走 / 地铁等多种手机状态;每类每场景重复 300–500 次;采集端每十几毫秒记录一组数据。
累计有效样本 7.5 万+ 条手势。
然后从 9 个维度逐项比对:
| 维度 | 区分力 | 主要结论 |
|---|---|---|
| 滑动速度波动系数 | 很高 | 脚本类接近 0;真人约 0.51;机械臂约 0.65;刷屏器一最高约 1.09 |
| 按压接触面积 | 很高 | 软件注入 / HID / 鼠标点击器大多为 0;真人最大;机械臂、刷屏器、电容点击器为非零中高面积 |
| 按压力度 | 高 | 脚本 / HID / 自动滑屏点赞器几乎恒为 1;真人、机械臂、刷屏器、电容点击器处于更低且互不相同的区间 |
| 压力波动系数 | 高 | 脚本 / HID 几乎为 0;真人约 0.23 |
| 滑动平均速度 | 中高 | 自动滑屏点赞器最快,真人较快,鼠标点击器最慢 |
| 滑动路径冗余率 | 中 | 代码脚本几乎直线;真人实际划过的路比两点直线多约 4.8% |
| 滑动平均曲率 | 中 | 代码脚本、电容点击器接近 0;机械臂、真人、刷屏器更高 |
| 线性加速度合量 † | 中 | 反映手机是否被真实手持移动,手持行走显著高于平放 |
| 陀螺仪合量 † | 中 | 同上,平放 / 竖放接近 0 |
† 这两维的判定规则需要「手机状态」(手持 / 平放 / 行走)作为上下文。 埋点未提供该字段时,引擎按其余 7 维判定——线上数据通常属于这种情况。 详见已知边界。
以"压力波动"这一维为例,9 类工具的分布长这样:
真人(n=19,354)是一条自然的钟形分布,P50 ≈ 0.23; 代码脚本、屏幕录制、自动滑屏点赞器几乎 100% 落在 0——每一次按压的力度分毫不差; 鼠标点击器则堆在 1.4142 这个古怪的固定值上。 机器最大的破绽不是做得差,恰恰是做得太完美。
其余 8 个维度的完整图表见 docs/02 · 九维度分析。
一句话总结实验结论:像人程度的稳定排序是
代码脚本 < 鼠标点击器 < 电容点击器 < 机械臂 < 真人。 段位最高的机械臂能在单个维度上骗过判定——速度曲线、轨迹曲率都接近真人—— 但躲不过 9 个维度交叉:它的抖动是机械运动特有的规律歪曲,压力波动也太小。 多维组合,才能锁死高段位工具。
完整实验数据与逐维度分析见 docs/。
python3 -m venv .venv && source .venv/bin/activate
pip install -e .
gesture-classify \
--summary-csv 你的数据.csv \
--trajectory-csv 你的数据_trajectory.csv \
--output-dir ./out纯 Python 标准库实现,零第三方依赖,Python ≥ 3.9。
不安装也能直接跑:
PYTHONPATH=src python3 -m gesture_behavior_classifier.cli \
--summary-csv 你的数据.csv --trajectory-csv 你的数据_trajectory.csv --output-dir ./out需要两个 CSV:
手势级汇总(一行一次手势)
gesture_index gesture_type start_x/y end_x/y duration_ms avg_pressure touch_major/minor avg_curvature linear_x/y/z gyro_x/y/z …
轨迹点(一行一个采样点,强烈建议提供)
gesture_index point_index x y pressure touch_major touch_minor vx_px_s vy_px_s curvature
压力波动、接触面积、速度波动、路径冗余率都依赖逐点数据,只给汇总 CSV 会损失大部分判别力。
这些字段长什么样,看采集时的实时读数最直观——下面是鼠标点击器点一下屏幕,手机记下的原始信号:
注意 接触面积: 0.0 × 0.0 px ——它根本没碰到屏幕,事件是从蓝牙 HID 通道注入的。
这就是判定的第一层分水岭:有没有真实的物理接触,装不出来。
至于同一张图里的 压力: avg=0.500,它是第一轮观察到的模式;
第二轮换批次实测却是 0.94——这个不一致后来成了我们最主要的误判来源,
也是"阈值必须按机型标定"最直接的例证,详见 docs/04 · 验证与局限。
没有采集端? 仓库里的
人工测试数据/是 5 组盲测原始数据, 克隆下来即可复现下方的盲测结果,不需要装任何东西。我们实验用的 Android 采集 App 也在 Releases 页面提供, 但它是实验室工具,不建议装在日常手机上——安装前请先读 采集 App 说明。
| 文件 | 内容 |
|---|---|
识别报告.md |
面向阅读的汇总报告 |
分组正式判定.csv |
正式结论:满足最低样本量后的批次判断 |
手势识别结果.csv |
每条手势的预测类别、置信度、命中规则证据、各类别得分 |
手势特征明细.csv |
每条手势算出的全部 9 维特征 |
批次识别汇总.csv |
按动作类型和手机状态的预测分布 |
用 5 种典型方式各采一批未参与规则制定的新数据,喂给引擎做盲判。 样本量很小(每组 50–66 条),下表是原始计数而非统计意义上的准确率估计:
| 实际设备 | 判对 / 总数 | 主要错误 |
|---|---|---|
| 真人-食指滑动 | 50 / 50 | — |
| 屏幕录制脚本 | 50 / 50 | — |
| 真人-拇指滑动 | 53 / 54 | 1 条输出未知 |
| 鼠标点击器 | 39 / 50 | 11 条误判为 HID |
| 机械臂 | 48 / 66 | 18 条输出未知 |
⚠️ 别把这几行当准确率指标用。 每组只有几十条, 即使 50/50 全对,置信区间下限也只在 93% 左右; 换一批设备、换一款机型,结果都会变。 这组数字的作用是说明错误发生在哪里,不是给出性能承诺。
没有出现跨大类的错误——真人从未被判成机器,机器也从未被判成真人。 所有错误都发生在同一大类内部,或退化成"未知"。这是目前最值得信赖的一点。
弱的两行我们照样放出来,归因分析见 docs/04 · 验证与局限。 欢迎带着你自己的数据来提 issue 或 PR。
请务必先读这一节——它决定了这个项目能不能用在你的场景里。
- 不是实时拦截器。 SWIPE 需 ≥30 条、TAP 需 ≥50 条才输出正式结论,低于门槛只给参考值。做的是账号 / 会话级定性,拦不住单次请求。合适的位置是跟在现有拦截链路后面做定性和溯源,不是替代它。
- 需要端侧埋点。 压力、接触面积、逐点轨迹只有 App 内能采到,网关侧、服务端日志里没有这些字段。
- 阈值需按机型标定。 接触面积、速度阈值是绝对值,与屏幕 DPI、触控驱动、ROM 强相关。当前阈值基于我们的实验设备,接入新机型时这是必须先做的一步——阈值集中在一个 JSON 里,标定不需要改代码。
- 传感器两维需要上下文。 线性加速度 / 陀螺仪的规则依赖「手机状态」标注,埋点未提供时按 7 维判定。
- 规则引擎,不是训练出来的模型。 每条判定可解释、可审计、可以直接拿去出报告;代价是它不会自己适应新设备。
confidence不是概率。 它是规则得分的单调变换,只适合同一批数据内部排序,不能当作"有 99% 的把握"来读。
- 摸底 —— 采一批真实流量,看你的 App 上机器操作占多少、分别是什么工具
- 打标 —— 为你已有的风控模型产出带工具类型的黑样本,解决标注样本稀缺的问题
- 分级 —— 工具成本可以作为判断对手投入强度的参考:61 元的电容点击器和 1535 元的机械臂,背后的组织化程度不在一个量级。具体怎么处置由你的风控策略决定
所有阈值集中在 default_rules.json,改 JSON 即可,不需要动代码:
gesture-classify --config 我的阈值.json ...也可以调整分组口径和样本量门槛:
# 默认只按 gesture_type 分组(适合无上下文的线上数据)
gesture-classify --group-by gesture_type,phone_status ...
# 更保守的样本量要求
gesture-classify --min-samples 100 ...src/gesture_behavior_classifier/
├── features.py # 从原始 CSV 计算 9 维特征
├── rules.py # 规则打分与单条手势判定
├── aggregate.py # 批次聚合与最低样本量门槛
├── report.py # Markdown 报告生成
├── cli.py # 命令行入口
└── config/
└── default_rules.json # 全部阈值
docs/ # 完整实验数据与逐维度分析
example_outputs/ # 一次真实运行的完整输出样例
人工测试数据/ # 5 组盲测数据,可直接复现 README 里的准确率
tests/
人工测试数据/ 里包含 104 条真人手势(54 条拇指滑动 + 50 条食指滑动),
以及各类工具产生的对照数据。关于其中的真人数据:
- 来源:本项目内部测试人员在实验环境下录制,参与者事先知悉数据将随项目公开并表示同意。
- 内容:仅包含触摸坐标、压力、接触面积、时间戳与设备传感器读数。 不含姓名、设备标识、账号、位置、通讯录或任何可定位到个人的字段。
- 用途:仅供复现本项目实验与开展防御性研究。
触摸动力学在学理上属于行为生物特征。虽然从数十条滑动曲线反向识别到具体个人在实践中不可行, 我们仍然把来源和边界写在这里——发布生物特征相关数据集却不说明来源,是不应该的。
如果你基于本项目采集自己的数据,请自行评估适用的个人信息保护义务。
Releases 页面的 gesture-collector-v2.apk 是我们做实验时用的 Android 采集端。
SHA-256 f3e6a1940a16641a431b0654bf2cf36a02db31babdf752fa07696d122dbf91f2
大小 11,543,975 bytes
它采集什么:当前应用内的触摸事件(坐标、压力、接触面积、时间戳)与设备传感器读数 (加速度计、陀螺仪、重力、磁力计),写入本机 CSV 文件。不联网、不上传、不读取其他应用的数据。
使用建议:
- 这是实验室工具,用于在专用测试机上复现实验,不建议装在日常使用的手机上
- 安装前请核对上面的 SHA-256;不匹配就不要装
- 只从本仓库的 Releases 页面获取,不要从第三方镜像下载
想改造成自己的埋点,直接照着 docs/01 · 实验方法 里的字段规范做即可,不必依赖这个 APK。
抢票、抢购、直播刷量、游戏挂机——跟你抢的很多根本不是人,而是一批几十块钱就能买到、专门用来模拟真人操作手机的设备。
这些设备能被识别出来。我们把方法和数据都公开,是希望更多平台能把它们挡在门外。
平台每挡住一台机器,真人就多拿回一点本该属于自己的东西。
- 本项目仅用于防御性的安全研究与风控能力建设,请勿用于任何非法用途。
- 本项目不提供任何作弊设备的购买渠道、货源信息或使用教程。文档中列出设备价格与实现原理, 目的是说明检测方法的实验依据和对手的成本结构。
- 文中提及的设备名称、协议名称及商标归各自权利人所有,本项目与其均无关联。
- 判定结果是基于统计特征的推断,可能出现误判。是否据此对用户采取处置措施, 以及由此产生的后果,由使用方自行判断和承担。
- 按 Apache-2.0 约定,本项目按"现状"提供,不附带任何明示或默示的担保。




