使用图色技术和yolo v8来实现防风控
本文提出了一种规避Android无障碍服务风控的智能自动化方案。针对金融、社交等高风控App对传统无障碍脚本的严格检测,该方案创新性地采用视觉驱动技术,结合图色识别与YOLOv8目标检测模型,通过截屏分析界面元素并模拟真实操作。系统利用OpenCV进行像素级匹配或YOLOv8模型识别特定UI组件,再通过底层输入设备(如USBHID)执行点击,完全绕过应用层监控。该方案具有三大优势:无需无障碍权限、
在当前移动应用安全机制日益严密的环境下,基于 Android 无障碍服务(Accessibility Service)的传统自动化脚本已面临严峻挑战。由于无障碍技术依赖系统级接口读取界面控件信息并模拟点击,其行为特征(如高频调用、无真实触摸轨迹、控件树遍历等)极易被金融、社交、游戏等高风控类 App 的反作弊系统识别,进而触发验证、限流甚至账号封禁。为突破这一限制,越来越多的智能辅助方案转向视觉驱动的自动化技术,其中图色识别(Color/Template Matching)与 YOLOv8 目标检测模型的结合成为规避风控的有效路径。
图色技术通过截取屏幕图像,利用像素颜色或模板匹配定位按钮、图标、文字等关键元素,无需依赖应用内部控件结构,从根本上绕开了对无障碍权限的依赖。而 YOLOv8 作为当前先进的轻量化目标检测模型,可在移动端高效运行,实现对复杂界面中特定 UI 元素(如“领取奖励”按钮、“滑块验证”区域)的高精度实时识别。二者结合后,自动化系统仅需“看图操作”:先截图,再通过图色或 YOLOv8 定位目标坐标,最后通过底层输入方式(如 USB HID 或蓝牙 HID)模拟真实点击或滑动。整个过程完全在操作系统图形层完成,不触碰应用逻辑层,行为模式与真人操作高度一致,极大提升了隐蔽性。
此外,该方案具备良好的跨平台兼容性——无论目标 App 是否混淆、是否动态加载界面,只要视觉元素可辨识,即可被定位。同时,配合随机延迟、仿人滑动轨迹等策略,可进一步降低被行为分析模型识别的风险。尽管图色对界面变化敏感、YOLOv8 需要训练数据,但冰狐等智能辅助平台已内置预训练模型和可视化标注工具,大幅降低了使用门槛。综上,基于图色与 YOLOv8 的视觉自动化不仅有效规避了无障碍风控,更代表了未来“无感知、高仿真”智能操作的发展方向。
用户可通过 图色匹配(findColor / findImage) 与 YOLOv8 目标检测 实现不依赖无障碍服务的视觉驱动自动化脚本。该方案通过截屏 + 图像识别定位目标元素,再结合底层输入(如 USB HID 或蓝牙 HID)执行操作,有效规避风控。
一、准备工作
- 启用调试模式
- 在冰狐 App 中开启【调试模式】(路径:设置 → 调试模式),以允许截图和图像识别。
- 准备资源文件
- 将用于图色匹配的小图标模板(如 PNG 格式按钮截图)或 YOLOv8 模型文件(
.onnx格式)上传至冰狐项目资源目录。
- 将用于图色匹配的小图标模板(如 PNG 格式按钮截图)或 YOLOv8 模型文件(
- 选择执行模块
- 若需高隐蔽性,建议配合
usb或ble模块执行点击(避免使用click()等无障碍函数)。
- 若需高隐蔽性,建议配合
二、核心 API 说明
▶ 图色识别(基于 OpenCV)
// 查找单个颜色点(RGB,支持容差)
var point = findColor(r, g, b, [x1, y1, x2, y2], tolerance);
// 查找图像模板(返回中心坐标)
var rect = findImage("template.png", threshold, [x1, y1, x2, y2]);
▶ YOLOv8 目标检测
// 加载 ONNX 模型(首次调用自动缓存)
yolo.loadModel("my_model.onnx");
// 执行检测(返回对象数组:{class: "button", confidence: 0.92, x, y, w, h})
var results = yolo.detect("screen", confidenceThreshold);
注:
"screen"表示对当前屏幕截图进行检测;也可传入本地图片路径。
三、完整示例:使用图色 + USB HID 自动点击“领取”按钮
function main() {
// 1. 连接 USB HID 设备(确保已 OTG 连接)
if (usb.connect() !== 1) {
toast("USB HID 连接失败");
return;
}
usbInit(rsScreenWidth, rsScreenHeight); // 初始化分辨率
// 2. 截图并查找“领取”按钮(使用模板图)
var btn = findImage("lingqu_btn.png", 0.85, [0, 0, rsScreenWidth, rsScreenHeight]);
if (btn) {
console.log("找到按钮,坐标:", btn.x, btn.y);
// 3. 使用 USB HID 点击(非无障碍!)
usb.click(btn.x, btn.y);
sleep(1000);
toast("已点击领取按钮");
} else {
// 4. 若模板匹配失败,尝试用 YOLOv8 检测
tryYoloFallback();
}
}
// YOLOv8 备用方案
function tryYoloFallback() {
yolo.loadModel("reward_button_yolov8s.onnx"); // 预训练模型
var detects = yolo.detect("screen", 0.7);
for (var i = 0; i < detects.length; i++) {
if (detects[i].class === "claim_button") {
var cx = detects[i].x + detects[i].w / 2;
var cy = detects[i].y + detects[i].h / 2;
usb.click(cx, cy);
console.log("YOLOv8 定位成功,点击:", cx, cy);
return;
}
}
toast("未找到目标按钮");
}
// USB HID 分辨率初始化(必须!)
function usbInit(w, h) {
usb.send([0x0E].concat(int2bytes(w, 2), int2bytes(h, 2)));
sleep(3000);
}
四、关键注意事项
-
模板图要求:
lingqu_btn.png应为透明背景或高对比度的小图(建议 50×50 像素内);- 存放于脚本同目录的
res/文件夹中,或通过冰狐 Web 端上传。
-
YOLOv8 模型训练:
- 需使用冰狐提供的标注工具标注数百张界面截图;
- 导出为 ONNX 格式(支持 YOLOv8n/s/m);
- 类别名需与代码中
detects[i].class一致(如"claim_button")。
-
性能优化:
- 限制检测区域(如只扫描屏幕下半部分)可提升速度;
- 设置合理阈值(图色
threshold=0.85,YOLOconfidence=0.7)平衡准确率与误检。
-
风控规避优势:
- 全程未调用
AccessibilityService; - 输入由 USB HID 模拟,行为不可被应用层监控;
- 适用于抖音、拼多多、银行 App 等强风控场景。
- 全程未调用
五、扩展建议
- 结合
ocr()识别文字内容,实现“点击包含‘立即到账’的按钮”; - 使用
findMultiColors()匹配多点颜色特征,提高抗干扰能力; - 添加随机偏移(
click(x+rand(-10,10), y+rand(-10,10)))模拟真人误差。
六、实际例子
使用yolov8实现的番茄小说自动化脚本
function startup(){
home();
// //需删除
// if (findView('txt:冰狐智能辅助@android.widget.TextView', {flag:'find_all', maxStep:10}).length){
// scroll(null, 'left', {type: 1, distance: 0.95, beforeWait: 1000});
// scroll(null, 'left', {type: 1, distance: 0.95, beforeWait: 1000});
// }
if (findView('txt:精品应用@cn:android.widget.TextView', {flag:'find_all'}).length){
gestureClick(323, 473);
if (findView('txt:番茄畅听@cn:android.widget.TextView', {flag:'find_all'}).length){
gestureClick(277, 1605);
}
}
}
//处理福利中心页面逻辑
function zhuanqian_page(){
sleep(6000);
var yolo = new YoloV8();
var temp = yolo.init('yolo_train/best-sim', ['chacha']);
console.log('yolo初始化结果:' + temp);
var ret = yolo.detect(); // 会自动截屏,然后检测截图,识别目标
console.log('检测结果:' + ret);
if (ret && ret.length > 0) {
console.log('检测到chacha');
gestureClick(r[0].left + r[0].width / 2, r[0].top + r[0].height / 2);
}
//在首页点击赚钱进入福利中心页面
if (findView('id:com.xs.fm:id/dpg', {flag:'find_all'}).length){
var ret = findView('id:com.xs.fm:id/dpg', {flag:'find_all'});
var result = extractBounds(ret.views);
if (result) {
gestureClick(result.left_num, result.top_num);
//福利中心
fuli_center();
}
}
// kanju();
return true;
}
function cbFunc() {
console.log('time is coming');
}
//提取动态UI的x,y坐标及width和height
function extractBounds(jsonData) {
var width_num = 0, height_num = 0, left_num = 0, top_num = 0;
//将 JSON 数据转换为字符串
var jsonString = JSON.stringify(jsonData);
console.log('JSON 字符串:' + jsonString); // 打印出完整的 JSON 字符串
//利用正则表达式获取到字符串中第一个括号的起止位置
var boundsRegex1 = new RegExp('\\(([^)]+)\\)', 'g');
console.log('正则表达式一: ' + boundsRegex1);
//使用 exec 方法逐步提取捕获组
var match1 = boundsRegex1.exec(jsonString);
if (match1) {
console.log('匹配到的字段:', match1[0]); // 输出
var str = match1[0];
var regex = new RegExp("\\((\\d+),\\s*(\\d+)");
var strMatch = regex.exec(str);
if (strMatch) {
width_num = parseInt(strMatch[1]); // 第一个数字
height_num = parseInt(strMatch[2]); // 第二个数字
console.log("width: " + width_num); // 870
console.log("height: " + height_num); // 1464
} else {
console.log("未找到匹配的数字");
}
} else {
console.log("未找到 boundsInScreen 字段");
return null;
}
var startIndex = match1.index; // 匹配开始位置
var endIndex = startIndex + match1[0].length; // 匹配结束位置
console.log(`End index: ${endIndex}`);
//利用获取到的起止位置将第一个括号及以前的内容剔除
var temp = jsonString.substring(endIndex + 2);
var newString = JSON.stringify(temp);
console.log('newString: ' + newString);
//再用一次正则表达式获取到第二个括号中的内容
var boundsRegex2 = new RegExp('\\(([^)]+)\\)', 'g');
console.log('正则表达式二: ' + boundsRegex2);
//使用 exec 方法逐步提取捕获组
var match2 = boundsRegex2.exec(newString);
if (match2) {
console.log('匹配到的字段:', match2[0]); // 输出
var str = match2[0];
var regex = new RegExp("\\((\\d+),\\s*(\\d+)");
var strMatch = regex.exec(str);
if (strMatch) {
left_num = parseInt(strMatch[1]); // 第一个数字
top_num = parseInt(strMatch[2]); // 第二个数字
console.log("left: " + left_num); // 870
console.log("top: " + top_num); // 1464
} else {
console.log("未找到匹配的数字");
}
} else {
console.log("未找到 boundsInScreen 字段");
return null;
}
return { width_num: width_num, height_num: height_num, left_num: left_num, top_num: top_num };
}
//福利中心
function fuli_center() {
if (findView('txt:看视频领10次奖励(0/10)@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all'}).length) {
console.log('看视频领10次奖励');
gestureClick(88, 478);
}
sleep(2000);
var yolo = new YoloV8();
var status = yolo.init('yolo_train/best-sim', ['chacha']);
console.log('yolo初始化结果:' + status);
var ret = yolo.detect(); // 会自动截屏,然后检测截图,识别目标
console.log('检测结果:' + ret);
if (ret && ret.length > 0) {
gestureClick(ret[0].left + ret[0].width / 2, ret[0].top + ret[0].height / 2);
}
// if (findView('txt:金币收益@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all'}).length) {
// scroll(null, 'up', {type: 1, distance: 0.5});
// }
//每日挑战
// if (findView('txt:去完成@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all'}).length){
// var ret = findView('txt:去完成@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all'});
// var result = extractBounds(ret.views);
// if (result) {
// gestureClick(result.left_num, result.top_num);
// sleep(2000);
// gestureClick(846, 951);
// }
// }
// //天天抽奖赢金币
// if (findView('txt:天天抽奖赢金币@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all'}).length) {
// var ret = findView('txt:去抽奖@cn:com.lynx.tasm.behavior.ui.LynxFlattenUI', {flag:'find_all'});
// var result = extractBounds(ret.views);
// if (result) {
// gestureClick(result.firstNum, result.secondNum);
// }
// }
// //预约领金币
// if (findView('txt:预约领金币@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all'}).length) {
// var ret = findView('txt:去领取@cn:com.lynx.tasm.behavior.ui.LynxFlattenUI', {flag:'find_all'});
// var result = extractBounds(ret.views);
// if (result) {
// gestureClick(result.firstNum, result.secondNum);
// }
// }
//时长赚金币
// if (findView('txt:时长赚金币@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all'}).length) {
// var sc_txt_ret = findView('txt:时长赚金币@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all'});
// var sc_txt_result = extractBounds(sc_txt_ret.views);
// if (sc_txt_result) {
// //gestureClick(sc_txt_result.left_num, sc_txt_result.top_num);
// //
// }
// if (findView('txt:去加倍@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all'}).length) {
// var jb_txt_ret = findView('txt:去加倍@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all'});
// var jb_txt_result = extractBounds(jb_txt_ret.views);
// if (jb_txt_result) {
// console.log('left:' + jb_txt_result.left_num);
// console.log('top:' + jb_txt_result.top_num);
// gestureClick(jb_txt_result.left_num - 200, jb_txt_result.top_num);
// while (1) {
// if (findView('txt:领取成功', {flag:'find_all'}).length) {
// console.log('领取成功');
// var yolo = new YoloV8();
// var status = yolo.init('yolo_train/best-sim', ['chacha']);
// console.log('yolo初始化结果:' + status);
// var ret = yolo.detect(); // 会自动截屏,然后检测截图,识别目标
// console.log('检测结果:' + ret);
// if (ret && ret.length > 0) {
// console.log('检测到chacha');
// console.log('left:' + ret[0].left);
// console.log('top:' + ret[0].top);
// gestureClick(ret[0].left + ret[0].width / 2, ret[0].top + ret[0].height / 2);
// if (findView('txt:坚持退出|txt:退出|txt:直接退出', {flag:'find_all'}).length) {
// var tc_txt_ret = findView('txt:坚持退出|txt:退出|txt:直接退出', {flag:'find_all'});
// var tc_txt_result = extractBounds(tc_txt_ret.views);
// if (tc_txt_result) {
// console.log('退出');
// console.log('left:' + tc_txt_result.left_num);
// console.log('top:' + tc_txt_result.top_num);
// gestureClick(tc_txt_result.left_num, tc_txt_result.top_num);
// break;
// }
// }
// break;
// }
// }
// }
// }
// }
// }
gesture([500, 1750, 500, 500]);
// if (findView('txt:签到@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all', beforeWait: 2000}).length){
// var qd_txt_ret = findView('txt:签到@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all'});
// var qd_txt_result = extractBounds(qd_txt_ret.views);
// if (qd_txt_result) {
// console.log('签到');
// console.log('left:' + qd_txt_result.left_num);
// console.log('top:' + qd_txt_result.top_num);
// gestureClick(qd_txt_result.left_num, qd_txt_result.top_num);
// if (findView('txt:立即签到@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all', beforeWait: 2000}).length) {
// var ljqd_txt_ret = findView('txt:立即签到@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all'});
// var ljqd_txt_result = extractBounds(ljqd_txt_ret.views);
// if (ljqd_txt_result) {
// console.log('签到成功');
// console.log('left:' + ljqd_txt_result.left_num);
// console.log('top:' + ljqd_txt_result.top_num);
// gestureClick(ljqd_txt_result.left_num + ljqd_txt_result.width_num / 2, ljqd_txt_result.top_num + ljqd_txt_result.height_num / 2);
// }
// }
// }
// }
if (findView('txt:今日签到可领@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all'}).length == 0) {
gesture([500, 1750, 500, 300]);
if (findView('txt:阅读赚金币@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all', beforeWait: 3000}).length) {
var yd_txt_ret = findView('txt:阅读赚金币@cn:com.lynx.tasm.behavior.ui.text.FlattenUIText', {flag:'find_all'});
var yd_txt_result = extractBounds(yd_txt_ret.views);
if (yd_txt_result) {
console.log('签到成功');
console.log('left:' + yd_txt_result.left_num);
console.log('top:' + yd_txt_result.top_num);
gestureClick(yd_txt_result.left_num, yd_txt_result.top_num);
if (findView('txt:看书@cn:android.widget.TextView', {flag:'find_all', beforeWait: 2000}).length) {
gestureClick(500, 581);
}
}
}
}
}
function main() {
requestScreenShot(); //请求截屏权限
startup(); //启动番茄小说
zhuanqian_page(); //开始番茄小说任务的逻辑
}
更多推荐
所有评论(0)