iv8:一键秒杀瑞数6、__zp_stoken__、abogus、h5st
iv8 是基于 V8 引擎的高性能 Python 原生扩展在 C 层实现浏览器 API提供高可控、高保真的 BOM/DOM/CSSOM 模拟内置 API 调用链监控与 Chrome DevTools 远程调试可在 Python 中直接运行依赖 Web 环境的 JavaScript无需启动浏览器。项目地址github.com/HanZzzzz000/iv8PyPIpypi.org/project/iv8安装pip install iv8abogus、h5st、__zp_stoken__、瑞数6仓库examples/里都给了使用示例。觉得有用欢迎到 GitHub 点个 Star。本文仅供学习研究、安全测试与合法自动化场景使用不构成攻击或未授权访问指引。完整免责声明见文末。一、先说为什么要造这个轮子补环境这事最常见的是node 补环境大多数jsdom 打底自己再用 Proxy /Object.defineProperty一通修补。这条路理论上什么检测点都能补难点在成本 —— 像document.all的[[IsHTMLDDA]]内部 slot、跨 Context 对象身份、Object.keys(window)的枚举顺序每一处都能写出来但要写到对方任何角度都识别不出来每个站还得单独调一套补丁零零散散既不通用、维护起来也累。况且 Python 项目里再背一个 Node 进程做异语言桥接本身就不优雅。另一条路是自动化Puppeteer / Playwright / DrissionPage 直接开真浏览器。问题也明显1000 并发就要 1000 个 Chrome 实例内存先爆CDP 协议又粗又慢连接动不动还断想批量跑就得堆机器、堆 worker整体成本高。iv8 走的是第三条路把 V8 拉出来在 V8 之上用 C 做一套浏览器运行时。它不是 JS Proxy 模拟而是在 C 层实现HTMLDivElement、document.cookie、navigator.webdriver、crypto.subtle.digest这些 JS 能观察到的浏览器对象、访问器、原型链与关键边界语义。底层尽量沿着 Chromium / Blink 的绑定模型走内部参考ScriptWrappable/WrapperTypeInfo的对象组织方式。直白讲以前补环境是在 JS 层打补丁iv8 是在 C 层建宿主。二、iv8 长什么样图注本文几张架构 / 时序 / 网络流程图来自 iv8 最新版内部文档用来解释整体设计方向。社区版保留核心运行模型但真实网络栈、布局 / 动画等能力仍以本文“社区版能干什么”章节为准。一句话importiv8withiv8.JSContext()asctx:print(ctx.eval(navigator.userAgent))print(ctx.eval(navigator.webdriver))print(ctx.eval(typeof document.all))输出是这样的Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...Chrome/124.0.0.0 Safari/537.36 False undefineddocument.all那一行不是字符串拼接出来的是 V8 层做了[[IsHTMLDDA]]的语义 ——typeof document.all undefined但document.all ! undefined。纯 JS 层模拟不出这种语言层 引擎层联动的语义只能上 native addon而 iv8 直接在 V8 层做掉JS 看到的就是真实的[[IsHTMLDDA]]行为。每个JSContext内部独占一个 V8 Isolate挂载完整的 window 域覆盖 70 HTML 元素接口、25 CSS 规则类型、80 事件类型、30 WebGL 扩展以及完整的 SubtleCryptoAES-GCM / RSA-OAEP / ECDH / ECDSA / HMAC / HKDF / PBKDF2。iv8.JSContext.get_defaults()一打印出来 200 多行全是可以通过environment参数覆盖的指纹字段。三、30 秒上手跑一个最简单的页面加载importiv8withiv8.JSContext()asctx:ctx.eval( window.__iv8__.page.load({ baseURL: https://example.com/, html: htmlheadscriptwindow.x navigator.userAgent.length;/script/headbodydiv idappHello/div/body/html }); )print(ctx.eval(window.x))# UA 长度print(ctx.eval(document.getElementById(app).textContent))# Helloprint(ctx.eval(document.URL))# https://example.com/page.load是流式解析 脚本执行 事件派发不是innerHTML那种把字符串塞进去就完事。HTML 解析到script会暂停把脚本拉出来执行外联脚本从离线 bundle 匹配然后继续解析、派发DOMContentLoaded/load、同步document.URL和location.href。时序对齐细到 Chrome 的内部 feature。比如 Chrome 111 默认启用的kTimedHTMLParserBudgetHTML parser 不再只按 token 数让出执行权而是引入默认 10ms 的 elapsed-time budget解析过程中如果被 parser-blocking 脚本拖过预算parser 会 yield让setTimeout(fn, 0)这种到期宏任务有机会先跑一轮再续解析。iv8 会根据 UA 解析 Chrome 主版本号按这个版本边界决定是否启用类似行为 —— UA 写 Chrome 110 和 Chrome 124同一段页面的脚本执行顺序可能就不一样。图注该图来自最新版事件时序图用来说明 iv8 对页面加载阶段的设计目标社区版已实现核心page.load/ 事件循环 / 逻辑时间能力。如果只需要把 HTML 解析成 DOM 树比如做数据提取可以走另一条路 ——document.documentElement.innerHTML ...开销低很多但脚本不会执行、生命周期事件也不派发。两条路都能用看场景。四、社区版能干什么社区版的重点不是把完整 Chrome 搬进 Python而是把“跑风控 JS”最常见、最影响成败的几块先做稳环境画像、可调试性、API 访问链路、可控时间、函数伪装以及离线资源模型。4.1 指纹配置200 字段一份 profile 切换不传environment也能跑内置一套 Chrome / Windows 桌面端的兜底指纹。要切换画像直接传字典没传到的字段保留默认值withiv8.JSContext(environment{navigator:{userAgent:Mozilla/5.0 ... Chrome/124.0.0.0 Safari/537.36,platform:Win32,language:zh-CN,languages:[zh-CN,en-US],hardwareConcurrency:8,deviceMemory:8,},screen:{width:1920,height:1080},webgl:{vendor:Google Inc. (NVIDIA),renderer:ANGLE (NVIDIA, NVIDIA GeForce RTX 3060),},location:{href:https://example.com/page},})asctx:...时区 / 权限 / Canvas 噪声等行为类配置走config参数跟指纹解耦iv8.JSContext(config{timezone:Asia/Shanghai})4.2 DevTools 调试能看见才能补准modedebug启用监控能力with_devtools(port9229)拉起 Chrome DevTools Protocol 服务。然后用 Chrome 打开devtools://devtools/bundled/inspector.html?wslocalhost:9229就能 attach 到 iv8 里的 JSContextwithiv8.JSContext(modedebug).with_devtools(port9229,watch_apis[navigator.userAgent])asctx:ctx.eval(vdebugger;)# 在 Chrome DevTools 中暂停ctx.eval(navigator.userAgent;)# 在 Chrome DevTools 中暂停几个细节debugger;被禁了。很多反爬 JS 喜欢丢setInterval(() debugger, 100)这种死循环搞反调试iv8 在 V8 层把原生debugger;改成空操作。需要断点时用vdebugger;行为跟原生 debugger 一致。console→vconsole。with_devtools(enable_consoleFalse)之后标准console不再转发到 DevTools Console如果你需要在 DevTools 里看自己的调试输出用vconsole.log()。watch_apis把关心的 API 列进去被读写时自动断点。在重度混淆的代码里追“谁动了navigator.userAgent/document.cookie”比手工找断点稳得多。4.3 API 访问调用监控先知道对方在探什么debug 模式下iv8 会记录浏览器 API 的读 / 写 / 方法调用 / 构造调用还会监控常见反射入口比如Object.keys、Object.getOwnPropertyDescriptor、Reflect.ownKeys、Function.prototype.toString、JSON.stringify等。这对补环境很实用目标 JS 不报错、不提示它只是在某个分支里默默判断“环境不对”。API 监控能把这条链路打出来它先读了哪个字段、枚举了哪个对象、调用了哪个原生函数后面才知道该补指纹、补枚举顺序还是补时序。4.4 逻辑时间与事件循环不等待真实时钟事件循环按宏任务 / 微任务两阶段推进setTimeout、setInterval、requestAnimationFrame、XHR 回调属于宏任务Promise 回调、queueMicrotask、MutationObserver 属于微任务。框架的重点是逻辑时间主动推进。time_modelogical默认下__iv8__.eventLoop.advance(250)表示把虚拟时钟推进 250ms并按事件循环规则处理到期任务这不是“加速真实时间”而是不需要等待真实墙钟自然流逝withiv8.JSContext(time_modelogical)asctx:ctx.eval( var log []; setTimeout(() log.push(macro-100), 100); setTimeout(() log.push(macro-200), 200); Promise.resolve().then(() log.push(micro)); )ctx.eval(window.__iv8__.eventLoop.advance(250))# 推进 250msprint(ctx.eval(log))# [micro, macro-100, macro-200]如果目标逻辑真的依赖真实耗时比如 POW 或时间差校验可以切到time_modesystem让 JS 可见时间跟系统时间锚定。更多API用法参考项目README。4.5 wrapNative临时补丁也要像原生函数wrapNative把任意 JS 函数伪装成[native code]Function.prototype.toString.call(fn)也假不了ctx.eval( var myFunc window.__iv8__.wrapNative(function(x) { return x * 2; }, myFunc); )print(ctx.eval(myFunc.toString()))# function myFunc() { [native code] }它适合做一些局部 polyfill 或目标站点临时补丁比如MessageChannel这类目标 SDK 只用到很小一部分语义的对象。普通 JS 函数一旦被Function.prototype.toString打开就露馅wrapNative至少能把这类临时函数伪装成浏览器原生函数降低补丁本身的可观测差异。它也可以用来替换某些 JS 入口做业务侧补丁比如把自定义函数挂回Object.keys、MessageChannel这类位置时至少让toString()看起来仍然像原生函数。社区版暂时不宣传 C 层原地 hook 能力后续这块和最新版完全对齐后再单独展开。五、实战两个代表性目标开发过程中精力有限仅挑选部分有代表性的站点进行过测试。示例脚本可在 GitHub 仓库examples/目录查看。请在合法授权场景下复现相关法律边界见文末免责声明。如有站点方认为某条示例不合适可到仓库提 issue会及时删除。5.1 瑞数 6用requests发第一次请求拿 HTML JSiv8 里page.load加载 HTML内联资源喂进resources等事件循环跑完从document.cookie读到种好的 cookie在 iv8 里发起 XHR这一步不真发请求只是触发瑞数对 XHR 的 hook从__iv8__.netLog.entries读最后一条记录里面的url是被瑞数加过后缀的真实 URLcookieHeader是最终 cookiePython 侧用这个 URL cookie 走requests真实请求核心代码三十多行节选自examples/海关.pywithiv8.JSContext()asctx:resp1requests.get(page_url,headersheaders)js_coderequests.get(js_url,...).text ctx.expose({baseURL:page_url,html:resp1.text,headers:[[k,v]fork,vinresp1.raw.headers.items()],resources:{js_url:js_code},},s1)ctx.eval(window.__iv8__.page.load(window.__iv8__.data.s1))ctx.eval(window.__iv8__.eventLoop.sleep(100))cookies_strctx.eval(window.__iv8__.netLog.entries[window.__iv8__.netLog.entries.length - 1].cookieHeader)...# 生成带后缀URLctx.eval(f var xhr new XMLHttpRequest(); xhr.open(POST, {url}); xhr.send({body_str}); )entryctx.eval(window.__iv8__.netLog.entries[window.__iv8__.netLog.entries.length - 1])api_urlentry[url]# 带签名后缀final_cookieentry[cookieHeader]responserequests.post(api_url,jsondata,headers{**headers,Cookie:final_cookie})社区版对于瑞数6.5版本如某信营业厅需要结合日志针对性的做些补充5.2__zp_stoken__examples/zp_stoken.py。接口第一次返回code37带回seed / name / ts需要拉一段 JS 计算出__zp_stoken__才能正常请求。签名计算就一行tokenctx.eval(fencodeURIComponent((new window.ABC).z({seed},{ts}));)最后session.cookies.set(__zp_stoken__, token)重发请求code0返回职位列表。六、性能数据实测环境 Intel Core i7-14700 / Windows 10 / Python 3.11维度指标数据速度JSContext 创建 eval 销毁~3.3 ms / 次简单 eval 吞吐11~950,000 ops/s浏览器 API 调用navigator / DOM / crypto340,000 – 570,000 ops/s维基百科 JavaScript 条目440 KB~7 ms / 页含 Context 创建销毁 ~11.5 ms串行 ~86 页/s内存首次加载import iv8 首个 Context15 MB单轮峰值增量~9 MB100 轮长跑累计漂移2 MB多线程加速比2 / 4 / 8 线程1.86x / 3.26x / 4.71x几个值得说的点JSContext 创建 ~3.3ms。意味着可以一个请求一个 Context不必复用每次干净环境。复用 Context 的节流收益其实不大反而要担心副作用累积。8 线程 4.71x 加速。V8 执行期释放 GIL多线程已经接近多进程效果不需要进程池 序列化通信的复杂度。100 轮长跑漂移 2MB。这是用v8::Global强引用 显式释放换来的没引入cppgc那套复杂度长期跑批量任务很关键。七、最新版还在路上的东西社区版主打够用、稳、能上 prod。最新版不会靠堆 API 名字凑清单主要攻的是社区版暂时不适合免费放出来的几块硬能力真实网络栈基于 Chromium net 模块QUIC / HTTP3 / WebSocket / proxy chain的深度裁剪不是 cronet 封装。JS 侧可以直接发起真实网络请求TLS 指纹、ALPN 协商、HTTP/2 / HTTP/3 行为与 Chromium net 栈保持一致。布局与几何闭环级联、继承、盒模型布局、虚拟字体度量、getBoundingClientRect()/offsetWidth/getClientRects()等几何读数保持内部一致。重点不是做渲染而是解决滑块 / 拼图验证码里常见的读几何 → 走分支 → 校验输入更完整的类 Chromium 布局树模型也在继续推进中。Worker 多 Isolate 并行每个 Worker 独占一个 v8 Isolate 跑在独立线程上不再是单 Isolate 模拟的伪并发。可观测语义闭环反爬检测不只看“有没有这个 API”还会看属性描述符、枚举顺序、异常类型、任务调度、回调批处理时机这些边界行为。最新版会继续把这些 JS 可观测细节收敛到同一套 Chromium 语义里让目标脚本从反射、异常、时序多个角度看过去都更一致。热路径性能与内存治理补环境不是单次跑通就完事真正上量时瓶颈在 CSS selector 匹配、属性枚举、样式同步、Wrapper 生命周期这些热路径。最新版会继续做缓存、惰性同步和对象生命周期治理让大批量 Context / 多线程任务跑得更久、更稳、更省内存。内部验证场景里最新版已经跑通过阿里 v2 / v3 / 234含 _rand以及保利威视频下载解密这类更贴近真实生产链路的目标。最新版的方向不是做几个 demo而是继续把 iv8 往“能承接复杂站点完整执行链路”的运行时推进。八、安装、跑起来pipinstalliv8支持 Python 3.8 – 3.14Windows x64 / Linux x64manylinux 标准。仓库github.com/HanZzzzz000/iv8PyPIpypi.org/project/iv8本文涉及的所有实战脚本在examples/目录下clone 之后直接python examples/zp_stoken.py就能跑部分脚本依赖额外的 JS 文件看脚本顶部的注释。九、写在最后补环境这事走到今天已经不是塞几个 navigator 字段就完事的阶段了。现代风控系统从指纹一致性、跨 Context 身份、堆栈资源名、API 时序到几何度量每一层都在打。JS 层的方案不是不能用是覆盖面已经追不上了。iv8 的思路其实很朴素 —— 既然 Chromium 已经把浏览器宿主这个抽象做得很完整那就在 V8 之上把 Chromium 在 Web 平台层的工作复刻一遍但只做补环境真正需要的部分。不做渲染、不做 GPU 合成、不做 IPC把省下来的复杂度全部砸在JS 看见的浏览器表面上。社区版以编译产物形式免费提供允许个人学习与研究。近期内不会开放源码—— 反爬场景里源码一暴露对方下检测点的成本几乎归零特征字符串、内部结构、函数签名全成了抓手。编译产物多一道逆向门槛对补环境项目来说算是必要的对抗护城河不是封闭姿态。等社区版自身的对抗能力进一步沉淀会重新评估开源策略。实际站点跑通了欢迎提 issue 分享跑不通更欢迎反馈 —— 真实目标的回馈是 iv8 迭代最重要的输入。pipinstalliv8去试试看。十、免责声明iv8 仅供学习研究、安全测试与合法的自动化场景使用。本项目及示例代码用于演示 iv8 的 API 设计与补环境思路不构成对任何网站的攻击、绕过身份验证或未授权访问的指引或工具。使用者应自行评估使用场景的合规性遵守目标网站的服务条款、robots.txt与所在地区的法律法规。作者对任何滥用行为不承担责任。涉及绕过身份验证、抓取受保护的个人信息、对明确禁止采集的接口进行大规模请求等场景可能触及《网络安全法》《数据安全法》《个人信息保护法》及刑法第 285、286 条等法律法规请审慎评估自负其责。如果你是文中所涉站点或 SDK 的所有者认为示例代码涉及不当披露或侵权请到 GitHub 仓库提 issue将在评估后及时删除相关内容。请优先在自己拥有授权、或目标方明确同意的场景下使用 iv8。本项目及示例代码用于演示 iv8 的 API 设计与补环境思路不构成对任何网站的攻击、绕过身份验证或未授权访问的指引或工具。使用者应自行评估使用场景的合规性遵守目标网站的服务条款、robots.txt与所在地区的法律法规。作者对任何滥用行为不承担责任。涉及绕过身份验证、抓取受保护的个人信息、对明确禁止采集的接口进行大规模请求等场景可能触及《网络安全法》《数据安全法》《个人信息保护法》及刑法第 285、286 条等法律法规请审慎评估自负其责。如果你是文中所涉站点或 SDK 的所有者认为示例代码涉及不当披露或侵权请到 GitHub 仓库提 issue将在评估后及时删除相关内容。请优先在自己拥有授权、或目标方明确同意的场景下使用 iv8。