中文站

Android 模拟点击研究,如何突围“黑灰产”的自动化作弊?

导读:模拟点击是指通过脚本、系统指令完成一些自动化点击的操作,不需要人为点击,一般应用在自动化测试,帮助阅读屏幕文字等。本文主要介绍几种主流的模拟点击技术及应用。

文|李伊洋
网易易盾 Android 安全工程师

背景

模拟点击是指通过脚本、系统指令完成一些自动化点击的操作,不需要人为点击,一般应用在自动化测试,帮助视障或是老年群体更方便使用手机。但随着技术的更新,模拟点击也被应用在了不同的场景,如自动化抢红包、自动聊天等黑灰产场景中。本文主要介绍几种主流的模拟点击技术及其应用。

软件场景

对于 View 较多的软件,如 IM、电商、短视频等软件,有时会面临抢红包、聊天 Bot、抢商品秒杀等自动化脚本的风险。因为 View 较为复杂,所以这类脚本往往是依赖于无障碍服务来实现的。因为系统层的支持,导致无障碍服务对 View 操作十分便利。对于不依赖无障碍的模拟点击工具而言,想要读取 View 是很困难的,例如想要知道一个用户名,需要截图 OCR 匹配字库,所以对于这部分内容,无障碍服务具有天然的优势。

自动化抢红包


自动化抢红包有违开发商的初衷,破坏了公平竞争的环境,容易引起用户的不满和投诉,不利于应用的长久可持续发展。

自动聊天

一些交友类 APP 内有聊天收费模式,这便吸引了黑灰产通过脚本自动聊天来谋利,比如下面的脚本,可自动接收和回复消息。其原理还是用了模拟点击,自动输入文字和点击发送按钮,但是配合精选的问答库,使得其可信度很高。


这样的做法破坏了厂商的营销策略,是从厂商这里“薅羊毛”。

游戏场景

对于游戏而言,常见的场景是脚本批量开新号、群控操作、脚本挂机以及脚本快速操作等。这类的模拟点击工具往往带有很强的识图、识色功能,通常可以根据几个像素点的颜色来判断游戏是否进入了需要操作的阶段,例如进入副本等。

自动挂机脚本


在部分 SLG 游戏中,允许玩家间进行资源交易,原本这能够拉近玩家间的距离,带动身边人一起游玩,但是因为批量挂机脚本,导致原本玩家会从黑灰厂商那里用现金购买资源,这就会导致资源贬值,破坏游戏货币系统,影响游戏正常运转。

自动日常任务、批量起新号


大部分的游戏在新手期往往会有大量的奖励,例如抽卡游戏,批量开启的新号会有人一直购买。相较于游戏中的充值抽卡,通过购买拥有新手奖励的新号去赌运气,成本会更低廉。但对于游戏方而言,这部分收益就白白流失了,由黑灰产商家赚去了。同理还有批量完成日常任务,其本意是为了保证用户不流失,能够每日都上线,但是黑灰厂商可以批量操作大量的账号完成每日任务,其核心思路与批量起新号类似,通过积少成多的奖励,给只想要特定种类的人抽卡使用,或者“代肝”,使原本保证玩家上线的手段失效,给游戏方造成巨大的损失。

自动跑环、跑任务


在类传奇游戏中,自动跑环的脚本也十分常见,与上一种行为类似,一般也是用于批量开新号使用,这样也会破坏游戏公平性,影响货币体系。

除此之外,模拟点击对于软件和游戏的危害还有很多,出于篇幅的考虑就不再一一展示。下文将从技术角度分析这些模拟点击的实现方式。

现状及原理

从市面上的脚本工具来看,较为出名的有“按键精灵”、“触动精灵”、“Auto.js”等软件。从他们的实现原理来看,Android 端的模拟点击可以说是多种多样的。

在早期,“按键精灵”等软件通过向 "/dev/input/event*" 路径下写入数据,从而实现模拟点击,不过这样做法会修改文件权限,很容易被检测出来。


于是后来,各种花样的模拟点击手法就多了起来,下文将分类来详细介绍。

无障碍服务

AccessibilityService(无障碍服务类):对于无障碍服务而言,最强大的内容并不在于对坐标的点击模式,事实上,直到 Android7.0+ 版本才开始支持对任意坐标的点击、长按、拖动等操作点击模式。

而除开直接对 View 控件属性的读取,无障碍服务也可以对 View 控件进行操作,比如说按钮的点击长按、文本框的输入、多选框的选择、下拉框的选择等。


现如今,主要针对游戏的模拟点击工具也开始慢慢加入无障碍服务的模式,例如“按键精灵”与“一键玩”等,因为其不依赖 root 的性质,导致很多没有 root 的玩家也可以体验到脚本。

View 控件操作

无障碍服务在实现类中继承 AccessibilityService,并重写具体的方法,它会被指定的事件触发, AccessibilityService 的触发的事件(Event)是:android.view.accessibility.AccessibilityEvent 类。

具体实现方法是重写 onAccessibilityEvent 方法,以开源的无障碍工具 Auto.js 为例。


通过上图可知,在服务被指定事件触发后,有一个 rootInActiveWindow 的变量,该变量由 AssessibilityService 中的方法——getRootInActiveWindow() 获得,这个方法返回的是用户当前最希望被操作的那个窗口的根节点。当调用这个方法之后,AccessibilityService 应用就根据获得的这个根节点去遍历所有的子节点,直到找到我们想要的那个子节点。

Activity 的图形是树状结构的,以前文所述的无障碍脚本为例,能发现其最上层的根节点是一个 FrameLayout 布局。


遍历这个根节点的所有子节点后,就可以获得想要操作的窗口中的所有 View 信息,例如文本、ID、Class、父子关系等一系列内容。在 AccessibilityNodeInfo 节点类中,存在 performAction 方法,该方法就可以将想要的操作直接发送给 View。

对于甲方厂商而言,虽然可以一刀切地只使用 Touch 监听,但这样会使原本为残障人士而设置的无障碍服务失去意义。所以需要结合更多的检测方法,用来判断是模拟点击工具带来的不正当使用,而不影响残障人士的正常使用。

手势操作

与模拟点击类工具不同,无障碍并没有将所有的点击事件拆分为一个个原子事件(down、up、move 等),而是将手势看作一个整体去执行。AccessibilityService 中的 dispatchGesture 方法实现了对手势的分发,以一个 Auto.js 脚本为例,这段 JS 代码实现了模拟三个手指下滑。


Auto.js 工具层转换为 Java 层:


构造器,转换为一个手势:


完成分发:


目前,越来越多的游戏类外挂开始采用这种方式以补充对非 root 玩家的覆盖,不论是开发门槛还是使用门槛都十分简单。从上述内容也能看出,这种做法也能保证兼容性,无需修改现有脚本,就能直接用到无障碍服务的外挂版本中。可见在未来,模拟点击类外挂工具兼容无障碍服务将会是越来越常见的情况。

非无障碍服务

对于非无障碍服务实现的模拟点击,实际上是参考了 shell 命令中 input 的实现。


通过源码分析可知:


该方法的实现依赖于系统 API 中的 injectInputEvent 接口,然而对于任何想要从应用外实现模拟点击的工具来说,该方法面临的第一个问题就是权限问题。在 Android 的点击事件分发流程中,native 函数 injectInputEvent 会对传入点击事件的 PID 与 UID 进行权限校验,如果未能获取到权限,就会导致点击流程分发失败。


因此,要使用该功能必须在应用中声明 Manifest.permission.INJECT_EVENTS 权限,同时需要该应用使用 root 或者 adb 权限启动时,才可以获取到该权限,使用该方法实现模拟点击具备更好的性能和更高的隐匿性,也是目前黑灰产中应用广泛的技术之一。

检测

早期的检测一般依赖系统 API 获取已开启的无障碍服务列表,通过黑名单判断是否是恶意应用,从而进行拦截,或者借助已安装应用列表的采集,判断是否有点击工具的痕迹,方式简单粗暴,且在风控场景中误伤率也较高。而随着改包技术、隐私合规的推动,以及 Android 系统正逐步限制对应用安装列表的获取,使得行为检测、点击流程的识别将会成为未来用于识别模拟点击的更可靠的方案。

总结

从网易易盾《2021年游戏安全白皮书》的数据能够看出,如今对于游戏厂商而言,更多是受到模拟点击类外挂的困扰。不同于侵入性的内存外挂,模拟点击类外挂侵入性更低,检测难度更大,使用门槛却相较于其他类型外挂更低。用户们只要开启无障碍服务或是使用 adb,就可以使用模拟点击类外挂厂商和脚本开发者们精心准备好的脚本。

模拟点击类外挂对厂商们的影响是很大的,不论是破坏软件的营销策略,还是破坏游戏的生态体系,都会影响到正常用户的使用体验,影响游戏厂商的收益与口碑。但对于厂商来说,也不能简单粗暴地切断所有的模拟点击,特别是软件的无障碍服务。

近年来,随着智能设备的普及,老年人、残障人士等大量不方便使用智能设备的人群,也对使用智能设备存在一定的需求。市场也在逐渐完善无障碍服务,所以厂商们也需要考虑到无障碍服务与模拟点击的正面影响,要结合 AI 等多维度去判断模拟点击是否作为了不正当方式在使用。

点击立即试用游戏反外挂