做了什么: - 新增 tools/tdc_trace.js: 给分发器 M=G[z[H++]]() 打补丁, dump 真实执行 PC 序列 - tdc_vm_run.py: 新增 TRACE_FULL 全量 PC 轨迹; 子 VM 共享 pcs/events(轨迹是全局的) - 修复 CALL_FUNC 的 this 绑定: 真实语义 fn.apply(c, B) -> this = c (原来传 None) - DBGCALL 调试输出(callee 类型/closure 异常/ref 与栈尾) 为什么: - 单靠读语义会无限试错; PC 轨迹对拍能一步定位首个分歧 怎么验证: - node tools/tdc_trace.js tcaptcha/core_js/tdc_sample.js -> 真实 19266 步 - 我们的解释器 739 步; 逐条 diff 后:**前 713 步完全一致** - 首个分歧 @step714: real 进入 @1544, 我们 fall-through 到 @208 对应指令 @206 CALL_METHOD [4]; 我们的 ref=[None,'call'] (base 为 None), 真实应为一个可调用对象 -> 说明某个寄存器在我们这边是 None
49 lines
2.2 KiB
JavaScript
49 lines
2.2 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* 真值 PC 轨迹器 —— 给 tdc.js 的分发器打补丁, dump 真实执行的 PC 序列。
|
|
*
|
|
* 补丁点(源码实测): `for(var M=!1;!M;)M=G[z[H++]]();`
|
|
* -> 记录 H(即将执行的 PC), 再正常分发。
|
|
*
|
|
* 用途: 与 tools/tdc_vm_run.py (纯 Python 解释器) 的 PC 序列**逐条对拍**,
|
|
* 第一个不同的 PC 即执行流分歧点。
|
|
*
|
|
* 用法: node tools/tdc_trace.js <tdc.js> [最大记录数] > /tmp/real_pcs.json
|
|
*/
|
|
const fs = require("fs");
|
|
|
|
const file = process.argv[2] || "tcaptcha/core_js/tdc_sample.js";
|
|
const limit = parseInt(process.argv[3] || "200000", 10);
|
|
|
|
let src = fs.readFileSync(file, "utf8");
|
|
const needle = "M=G[z[H++]]()";
|
|
if (!src.includes(needle)) {
|
|
console.error("[!] 未找到分发器文本: " + needle);
|
|
process.exit(2);
|
|
}
|
|
src = src.replace(needle, "M=(globalThis.__PC.push(H),G[z[H++]]())");
|
|
|
|
globalThis.__PC = [];
|
|
globalThis.window = globalThis;
|
|
// 顶层引导阶段不需要真环境; 给最小桩以防早退
|
|
globalThis.document = { cookie: "", referrer: "", createElement: () => ({ getContext: () => null, toDataURL: () => "", style: {} }), getElementById: () => null };
|
|
globalThis.navigator = { userAgent: "Mozilla/5.0", platform: "MacIntel", languages: ["zh-CN", "zh"], language: "zh-CN", hardwareConcurrency: 10, cookieEnabled: true };
|
|
globalThis.screen = { width: 2560, height: 1440, availWidth: 2560, availHeight: 1345, colorDepth: 24, pixelDepth: 24 };
|
|
globalThis.location = { href: "https://turing.captcha.gtimg.com/1/template/drag_ele.html", hostname: "turing.captcha.gtimg.com", protocol: "https:" };
|
|
globalThis.localStorage = { getItem: () => null, setItem: () => {} };
|
|
globalThis.sessionStorage = { getItem: () => null, setItem: () => {} };
|
|
globalThis.requestAnimationFrame = (f) => setTimeout(f, 0);
|
|
globalThis.addEventListener = () => {};
|
|
globalThis.removeEventListener = () => {};
|
|
globalThis.__TENCENT_CHAOS_STACK = {};
|
|
|
|
let err = null;
|
|
try {
|
|
eval(src);
|
|
} catch (e) {
|
|
err = String(e && e.stack || e);
|
|
}
|
|
const pcs = globalThis.__PC.slice(0, limit);
|
|
process.stderr.write(`[trace] 执行 PC 数=${globalThis.__PC.length}${err ? " 顶层抛错: " + err.slice(0, 160) : ""}\n`);
|
|
process.stdout.write(JSON.stringify(pcs));
|