Files
hello_js_reverse_skill/tcaptcha/TOOLCHAIN_REPORT.md
T
yml2213 47ce74b160 refactor(纯算): 移除全部补环境后端,收敛为纯算单一路径 + 修复两处红灯
做了什么:
- 删除 generate_telemetry_node/browser/probe 三个伪造环境后端, 以及 apply_real_environment、
  4 段拼接旧结构、human_dt_ms、generate_collect_pure (crypto.py 955 -> 389 行)
- 遥测只剩纯算: python_keyed = Node 仅提取 XTEA 密钥字 + Python 模板回填 + 教科书 XTEA
- 修复 crypto.py 重复的 xtea_encrypt_block (内置自测从失败到通过), 并并入 selftest
- 修复 glyph_solver 强校验: 改用集成得分矩阵行 argmax 自洽校验, 回归 5/8 -> 8/8
- 移除注释里无证据的 errorCode=12 归因; 移除 12 自动换 IP 重试
- extract_eks 不再写死变量名; UA 常量统一为 Chrome/155
- 文档对齐: ANALYSIS §8 修订 / PROGRESS 重写 / TOOLCHAIN_REPORT §三 更正

为什么:
- 本项目证据账本已证: 12 与遥测后端/出口 IP/静默时长均无关, 补环境无收益且引入脆弱面
- 强校验用单引擎 ocr_text 会误杀正确解 (实测 簿->垂 / 笆->芭 / 筹->努)

怎么验证:
- .venv/bin/python -m tcaptcha.selftest 全绿 (crypto_core + glyph 8/8 + xtea_key)
- 端到端纯算: python / python_keyed 均可解回 '{"cd":[' 开头明文, probe 模式被拒绝
2026-10-11 21:30:26 +08:00

117 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 腾讯验证码 (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,151 条指令流 | 彻底透明化 TDC 字节码调度器 (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"`)
---
## 三、关于 errorCode=12 的诚实结论(**已更正**)
> 本报告早期版本曾把 12 归因于"`re.sub` 破坏校验和 / 时间戳错位 / 机械假轨迹 / CDP 特征泄露"。
> 这 4 条**均与本项目自己的证据账本冲突**(见 `har/1ms_dianxuan/ANALYSIS.md` §7 与 `PROGRESS.md` §三),
> 现更正如下:
| 早期断言 | 现状 |
| --- | --- |
| 时间戳错位(硬编码数天前)| ❌ 撤回:纯算路径自模板回填起就刷新为当前时间戳,仍 12 |
| 机械假轨迹 dt=0/1ms | ❌ 撤回:换真实 ms 分布后仍 12 |
| CDP 特征泄露 | ❌ 撤回:纯 Python(无 CDP)后端同样 12 |
| `re.sub` 破坏内部校验和 | ⚠️ 仅为假设,无对照实验 |
**已确证**:12 与遥测后端 / 出口 IP / 静默时长均无关。真正的自变量
(登录态 / 真实验证码页面上下文)尚未由单变量实验区分 —— 见 `ANALYSIS.md` §7.5。
### 关于深度 Proxy 探针(`tools/tdc_probe.js`)的定位
探针是**分析工具**(用于枚举 tdc.js 真实读取了哪些环境属性),**已不在遥测生成路径上**
(`crypto.generate_telemetry` 只保留纯算)。它注入的 Canvas / WebGL / 屏幕取值来自
**单份成功样本**,属于"复刻一份画像"而非"真实环境",因此不作为交付依据。
---
## 四、一键复验入口
```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"))
'
```