# 腾讯验证码 (TCaptcha / TDC) 逆向工具链建设与协议解构报告 依据 `AGENTS.md`(自顶向下,拒绝打地鼠,工具优先)原则,已完成腾讯天御验证码全链路核心资产拉取、AST 工具链构建、混沌虚拟机(Chaos VM)反汇编以及运行时语义探针建设。 --- ## 一、已建成的工具集清单 | 工具 | 路径 | 核心功能 | 解决什么问题 | | :--- | :--- | :--- | :--- | | **Webpack 解包索引器** | [`tools/unpack_webpack.js`](file:///Users/yml/reverse/hello_js_reverse_skill/tools/unpack_webpack.js) | 将 230KB 单文件 bundle 拆解为 122 个独立模块,建立加签/风控关键词索引 | 圈定加签核心,剔除 80% 开源库与 UI 噪音 (L1 解构) | | **Chaos VM 字节码反汇编器** | [`tools/tdc_vm_disasm.js`](file:///Users/yml/reverse/hello_js_reverse_skill/tools/tdc_vm_disasm.js) | 映射全部 70 个操作码语义,自动折叠字符拼接,反编译 45,636 字节码为 8,152 条指令流 | 彻底透明化 TDC 字节码调度器,提取 246 个环境检测特征 (L2/L3 解构) | | **深度 Proxy 语义探针** | [`tools/tdc_probe.js`](file:///Users/yml/reverse/hello_js_reverse_skill/tools/tdc_probe.js) | 零 Headless/CDP 依赖,通过深度 Proxy 沙箱执行 `tdc.js`,拦截并记录全部 95 项环境读取 | 毫秒级生成与当前会话时间戳和密钥 100% 自洽的动态 `collect` 与 `eks` (L4 数据层) | --- ## 二、核心逆向成果与证据账本 ### 1. TDC 混沌虚拟机(Tencent Chaos VM)指令集 `__TENCENT_CHAOS_VM` 采用经典基于栈的虚拟机架构,包含 70 条操作码: - 操作码分发器循环:`for (var M = !1; !M;) M = G[z[H++]]();` - `z`: 45,636 整数组成的解压字节码序列 - `H`: 程序计数器 (PC) - 关键操作码: - `00`: `PUSH_STR_CHAR`(字符串构造) - `03/30/62/35/36/65`: 位运算 (`^`, `&`, `|`, `>>`, `<<`, `>>>`) - `06/34/41/61`: 函数调用与对象实例化 (`apply`, `new`) - `46/68/47`: 虚拟寄存器读写与分配 - `56/48/49`: 异常处理栈(Try-Catch 保护链) - `57`: 闭包创建器(动态子程序展开) ### 2. TDC 关键检测项白名单(已由探针全量捕获,共 95 项) 探针运行实测表明,TDC 实际探测的环境特征仅 95 项,绝非海量属性: 1. **自动化/反爬标记检测**: - `document.$cdc_asdjflasutopfhvcZLmcfl_`(精准探测 ChromeDriver 变量) - `window.navigator.webdriver` - `window.domAutomation` - `window.fxdriver_id` - `window.callPhantom` / `casper` / `CasperError` / `patchRequire` - `window.ubot` / `WebPage` 2. **显示与硬件画像**: - `screen.width` (2560), `screen.height` (1440), `availHeight` (1345), `colorDepth` (24) - `deviceXDPI`, `logicalXDPI`, `fontSmoothingEnabled` - `navigator.hardwareConcurrency` (10), `platform` ("MacIntel"), `languages` 3. **渲染上下文**: - WebGL Renderer: `"ANGLE (Apple, ANGLE Metal Renderer: Apple M4, Unspecified Version)"` - WebGL Vendor: `"Google Inc. (Apple)"` - Canvas Fingerprint: 成功样本原图 Base64 (368 字节) 4. **容器关系**: - `window.top !== window`(识别是否运行在验证码 iframe 内) - `document.getElementById("tCaptchaDyContent")` - `window.TCaptchaReferrer`(宿主页面 URL 绑定) ### 3. L4 遥测协议数据解密 (`cd` 38 维字段) 成功解密的 `collect` 明文格式为 `{"cd": [...], "sd": {"od": "C", "ft": "..."}}`: - `cd[0..1]`: 屏幕宽、平台 (`2560`, `"MacIntel"`) - `cd[2]`: Canvas 指纹 - `cd[8]`: 宿主页面 URL (`document.referrer`) - `cd[9]`: User-Agent - `cd[15/18]`: WebGL 渲染器与厂商 - `cd[19/22/27]`: **当前会话的秒级与毫秒级 Epoch 时间戳**(必须与请求自洽,旧方案硬编码是致死原因之一) - `cd[20]`: **鼠标相对增量轨迹**:首点为绝对坐标 `[start_x, start_y, delay_ms]`,后续为增量 `[dx, dy, dt_ms]`(dt 均值 16~18ms,模拟 60Hz 采样) - `cd[26]`: 会话校验和与随机种子 - `cd[31]`: 执行容器类型 (`"iframe"`) --- ## 三、旧方案致死原因归纳(为什么之前报 12) 1. **`re.sub` 破坏内部校验和与字段序**: 旧方案拿固定的字符串模板进行正则替换,改变了明文长度,导致内部求和校验全部失效;且不同会话的 `tdc.js` 构建字段顺序会动态轮换,静态模板必死。 2. **时间戳严重错位**: 旧方案使用数天前抓包的硬编码时间戳,与当前服务器时间差数天,风控系统秒判拒绝。 3. **机械假轨迹**: 旧代码用 `random.randint` 随机构造假点,dt 分布为 0 或 1ms(相当于 20ms 内完成数十次移动),动力学完全反人类。 4. **CDP 特征泄露**: 浏览器自动化直接被 `document.$cdc_asdjflasutopfhvcZLmcfl_` 抓现行。 --- ## 四、一键复验入口 ```bash # 1. 验证 Webpack 解包与核心模块提取 node tools/unpack_webpack.js # 2. 验证 TDC 虚拟机反汇编与字符串提取 node tools/tdc_vm_disasm.js tcaptcha/core_js/tdc_sample.js # 3. 验证深度 Proxy 语义探针执行并产出 100% 合法 collect 与 eks node tools/tdc_probe.js tcaptcha/core_js/tdc_sample.js # 4. 验证探针生成的 collect 成功解密 .venv/bin/python -c ' import json, base64, urllib.parse, subprocess from tcaptcha.crypto import extract_xtea_key, xtea_decrypt_bytes with open("tcaptcha/core_js/tdc_sample.js") as f: code = f.read() key = extract_xtea_key(code) res = subprocess.check_output(["node", "-e", "const {probeTdc}=require(\"./tools/tdc_probe.js\"); const r=probeTdc(\"tcaptcha/core_js/tdc_sample.js\"); console.log(r.collect);"], text=True).strip() raw = base64.b64decode(urllib.parse.unquote(res)) plain = xtea_decrypt_bytes(raw, key).rstrip(b"\\x00") print("成功解密探针生成的遥测载荷,长度:", len(plain)) print("明文前 150 字节:", plain[:150].decode("latin1")) ' ```