console.log不可用解决
这是因为bot-score-v1.js劫持了console对象下的["log", "warn", "info", "error", "exception", "table", "trace"]方法,并绑定到了一个空函数上
这个可以通过在控制台输入console.dir(console.log),会发现:
正常的应该是:
顺着[[BoundThis]]下的方法点进去,这是一个典型的ob混淆,可以在 https://obf-io.deobfuscate.io/ 里面解混淆
让我们来看看做了什么(AI生成):
这是一个经过高度混淆的脚本,主要用于设备指纹采集、机器人检测以及数据上报。从请求路径/cdn_cgi_bs_bot/可以判断,它属于Cloudflare Bot Management(Cloudflare 的机器人管理服务)的一部分。
下面按执行顺序和功能模块,详细解释代码做了什么。
1. 自保护与反调试机制(开头两个闭包)
const _0x260d53 = function () { ... }(); const _0x4703da = _0x260d53(this, function () { return _0x4703da.toString().search("(((.+)+)+)+$") ... }); _0x4703da();_0x260d53是一个单次执行封装器,它会返回一个函数,但内部函数只能被调用一次(通过闭包标志位_0x18bbbe控制)。这通常用于防止外部重复调用或调试器干扰。_0x4703da调用自身toString()并执行正则(((.+)+)+)+$搜索。这个正则是一个经典的ReDoS(正则拒绝服务)攻击模式,同时也可以用于检测代码是否被格式化或篡改——如果函数体被改动,search结果会不同,可能直接抛出异常,起到防逆向作用。
类似的第二个闭包_0x228bed和_0x4c84d5功能更具体,见下一条。
2. 劫持控制台方法(_0x4c84d5)
const _0x228bed = function () { ... }(); const _0x4c84d5 = _0x228bed(this, function () { const _0x17b582 = function () { // 获取全局对象 (window) }; const _0x23f78c = _0x17b582().console; const _0x37fa34 = ["log", "warn", "info", "error", "exception", "table", "trace"]; for (...) { const _0x219b17 = _0x228bed.constructor.prototype.bind(_0x228bed); _0x219b17.__proto__ = _0x228bed.bind(_0x228bed); _0x219b17.toString = _0x16e0f1.toString.bind(_0x16e0f1); _0x23f78c[methodName] = _0x219b17; } }); _0x4c84d5();- 它通过
Function("return (function() {}.constructor(\"return this\")( ));")()来获取全局对象window(此方式可避开严格模式的限制)。 - 遍历
console.log、warn、info、error等方法,将它们全部替换成一个绑定了_0x228bed的空白函数。 - 同时把替换函数的
__proto__和toString也做了重定向,让它在开发者工具中看起来像是原生的 console 方法,但实际上禁止了所有控制台输出,防止调试信息泄露或被人从控制台观察脚本行为。
3. Cookie 读取函数(_0x4a7a78)
function _0x4a7a78(cookieName) { var cookies = document.cookie.split("; "); for (var i = 0; i < cookies.length; i++) { var parts = cookies[i].split('='); if (cookieName == parts[0]) return unescape(parts[1]); } return ''; }简单地从document.cookie中解析并返回指定名称的 cookie 值。在后续流程中用于读取名为"bc_bot_session"的 cookie。
4. 加密函数(_0x26f755)
function _0x26f755(plaintext, keyStr) { var keyMd5 = CryptoJS.MD5(keyStr).toString(); var key = CryptoJS.enc.Utf8.parse(keyMd5.substring(0, 16)); var iv = CryptoJS.enc.Utf8.parse(keyMd5.substring(16)); return CryptoJS.AES.encrypt(plaintext, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }).toString(); }- 依赖全局的
CryptoJS库(AES 加密,CBC 模式,Pkcs7 填充)。 - 先将密钥字符串进行MD5 哈希,取结果的前 16 个字符作为 AES 密钥,后 16 个字符作为 IV(初始化向量)。
- 返回加密后的密文(通常是 Base64 编码字符串)。
5. 指纹数据整理(_0x44786b)
function _0x44786b(fingerprintResult) { let data = { visitorId: fingerprintResult.visitorId, confidence: fingerprintResult.confidence.score }; // 提取 FingerprintJS 组件信息 let components = fingerprintResult.components; if (components) { data.fontsLength = ...; data.audio = ...; data.colorGamut = ...; data.canvas = ...; // winding 等 data.touchSupport = ...; data.cookiesEnabled = ...; data.videoCard = ...; data.pdfViewerEnabled = ...; data.platform = ...; // 等等 } // 提取 Botd 机器人检测信息 let botd = fingerprintResult.botd; let botdComps = botd.components; if (botdComps) { data.userAgent = ...; data.windowSize = ...; data.pluginsLength = ...; data.webGL = ...; data.webDriver = ...; // 是否启用自动化工具(如 Selenium) data.android = ...; data.distinctiveProps = ...; data.browserKind = ...; // ... } data.bot = botd.bot; // 如果 botd 组件不存在且 bot 标志不为 true,则强制标记为机器人 if (botd.bot != true && (botdComps == undefined)) { data.bot = true; } return data; }- 将 FingerprintJS v3 生成的庞大指纹对象精简成一个只包含关键字段的平面对象。
- 同时合并 Botd (Bot Detection) 模块的检测结果。
- 特别关注
webDriver(自动化驱动检测)、bot标记等字段,用于判断访问者是否为机器人。
6. 加密并上报数据(_0x4f90d3)
function _0x4f90d3(processedFp) { let sessionCookie = _0x4a7a78("bc_bot_session"); let visitorId = processedFp.visitorId; let encrypted = _0x26f755(JSON.stringify(processedFp), sessionCookie + visitorId); const payload = { fp: visitorId, enc: encrypted }; fetch("/cdn_cgi_bs_bot/api", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }) .then(res => res.json()) .then(data => data.status == 1) .catch(err => console.error('Error:', err)); }- 从 cookie 读取
bc_bot_session作为会话标识。 - 用
bc_bot_session+visitorId拼接后作为加密密钥,对精简后的指纹数据进行 AES 加密。 - 将
visitorId(明文)和密文一起通过POST发送到/cdn_cgi_bs_bot/api。 - 期望响应 JSON 中
status为 1 表示成功。
7. 主执行流程
let botdResult; const botdPromise = import("/cdn_cgi_bs_bot/static/fingerprintjs-botd-v1.js") .then(module => module.load()); botdPromise .then(loaded => { let result = loaded.detect(); result.components = loaded.components; result.detections = loaded.detections; return result; }) .then(res => { botdResult = res; }) .catch(err => console.error(err)); const fpPromise = import("/cdn_cgi_bs_bot/static/fingerprintjs-v3.js") .then(module => module.load()); fpPromise .then(fp => fp.get()) .then(fpData => { fpData.botd = botdResult; // 将 botd 检测结果挂到指纹对象上 let processed = _0x44786b(fpData); // 精简数据 _0x4f90d3(processed); // 加密并上报 });- 使用动态
import()加载两个外部脚本:- fingerprintjs-botd-v1.js:机器人检测库,提供浏览器特征检测(如 WebDriver、headless chrome 痕迹等)。
- fingerprintjs-v3.js:FingerprintJS v3,生成浏览器指纹(Visitor ID)。
- Botd 先执行
load()和detect(),结果暂存到变量botdResult。 - FingerprintJS 调用
get()获取完整的浏览器指纹对象。 - 将 Botd 结果合并进指纹对象,再经过
_0x44786b提取关键字段,最后调用_0x4f90d3加密上报。
整体目的
这段脚本是Cloudflare 的反机器人/安全防护系统在客户端埋下的检测代码,其主要功能为:
- 收集多维度的浏览器指纹(Canvas、WebGL、字体、音频、硬件并发、插件、屏幕尺寸等)。
- 识别自动化工具与机器人(如 Selenium WebDriver、Headless Chrome、Android 模拟器等)。
- 将收集到的数据用动态密钥加密(密钥来自 Cookie 和指纹 ID)后回传到 Cloudflare 的接口。
- 抑制开发者工具的控制台输出,增加逆向分析的难度。
- 采用混淆和反调试技巧,防止篡改和静态分析。
最终,服务端根据这些加密的指纹数据判断访问者是否为正常用户,从而决定放行、拦截或提出人机验证挑战。
再让我们看看fingerprintjs-botd-v1.js和fingerprintjs-v3.js是干什么的(AI生成):
这两个脚本是Cloudflare机器人管理系统(Bot Management)中使用的客户端检测模块。fingerprintjs-v3.js负责生成浏览器指纹,而fingerprintjs-botd-v1.js则用于检测自动化工具和机器人。
fingerprintjs-v3.js:浏览器指纹识别
脚本fingerprintjs-v3.js是FingerprintJS v3.4.2开源库,主要功能是生成一个独特的"访问者ID"(Visitor ID)。
- 技术原理:它通过收集浏览器的多种"信号"(如Canvas渲染、WebGL、音频处理、字体列表、屏幕色深等),利用MurmurHash3哈希算法生成一个紧凑的标识符。后续分析中提到的"Picasso"技术,也是其指纹采集的一部分,被用于生成信号。该ID在隐身模式下也能保持稳定,但纯客户端版本准确率有限,约为40%-60%。
fingerprintjs-botd-v1.js:机器人检测
脚本fingerprintjs-botd-v1.js是Fingerprint BotD v1.9.1库,专门用于识别访问者是否为自动化程序。
- 检测机制:它不仅检测通用的无头浏览器和自动化框架(如Selenium、Playwright),还会根据
navigator.userAgent来判断浏览器内核(如Chromium/Blink、WebKit、Gecko)。 - 高级检测:它还会检查设备是否开启WebDriver模式,并检查
navigator.plugins等属性,以区分真实浏览器和模拟浏览器的机器人。
与Cloudflare的协同工作
这两个脚本会被Cloudflare动态注入到HTML页面中。其生成的信号(如JA3/JA4指纹)会被纳入后台的机器人评分(Bot Score)系统,用于区分人类与自动流量。默认情况下,脚本每30分钟才执行一次。
总结
总的来说,这两个脚本共同构建了一个双层检测体系:第一个脚本用于识别"谁在访问"(即生成设备指纹),第二个脚本用于判断"是不是真人"(即检测机器人)。它们是Cloudflare机器人管理系统中不可或缺的一环。
未登录无法复制解决
这个就需要下断点跟踪了,我们现在元素中找到所有的事件绑定,这里面没有copy的绑定,所以就只好看keydown了,其实也可以全局搜索copy的,但用前者却无意间发现了一个关键区别,这个等会再说。
