Files
hello_js_reverse_skill/har/1ms_dianxuan/PROGRESS.md
T
yml2213 be7a6ee97b chore(git): har/ 下只忽略抓包产物,放行分析文档入库
做了什么
- .gitignore 的 `har/` 改为 `har/**` + `!har/**/` + `!har/**/*.md`
  —— 仍忽略 har/ 下的 jpg/js/json 抓包产物,但 *.md 分析文档正常入库
- 首次纳入两份文本证据资产:
  har/1ms_dianxuan/ANALYSIS.md  (330+ 行协议分析报告)
  har/1ms_dianxuan/PROGRESS.md  (已知/未知/已排除假设/下一步)

为什么
- 原规则是整目录忽略,把「证据文档」和「大文件抓包」一起挡在版本控制外;
  按 AGENTS.md §1.3,进度与证据必须落盘可追溯,文档应随代码版本化

怎么验证的
- git check-ignore 逐项确认: PROGRESS.md/ANALYSIS.md 入库,
  bg_3.jpg/tdc.js/live/session.json 仍忽略
- git add 预演仅 3 个文本文件, 无二进制混入
- 已检查文档内无 API key 等凭据 (仅几个已过期住宅代理 IP)
2026-10-11 18:10:15 +08:00

5.0 KiB
Raw Blame History

反 VM 密钥还原 & 纯算交付 进度文档

目标: 算法 100% 纯 Python,Node 仅用于"跑出密钥 + 一次性标定明文模板"。 依据: AGENTS.md §2.4 分层交付 / §3.3 字节码 VM 还原 / §4.3 运行时捕获 / §5.8 标定式交付。 最后更新: 2026-10-11


一、已知(附证据 + 确信度)

# 结论 证据 确信度
1 collect 的加密算法 = 教科书 XTEA(32 轮,delta=0x9E3779B9,sum 取 mod 2³²) 用提取密钥做纯 Python 加密,与真实 tdc.js 产物前 48 字节逐字节一致(f6a24e3e4fb5dd2b...) 确证
2 原 crypto.py 里带加盐的写法与该算法等价,只是把两个密钥字折叠了:K' = [k0, k1+salt1, k2+salt2, k3] 标准 XTEA + K'=[1448563793,1850559083,1733513813,1364613714] 解密样本 collect 得到 {"cd":[[],"1920-1080..." 确证
3 密钥按构建固定,不随运行变化 同一 tdc.js 连续 3 次运行,密文首块均为 f6a24e3e4fb5dd2b(首段明文是常量) 确证
4 密钥不在脚本字面量里(全脚本只 3 个数 >1e9,无一个是密钥字) 正则清点全部 ≥7 位数字 确证
5 密钥由 VM 在运行时通过 ADD 算出:(sum + K[j]) 的两操作数必有一个等于 r*DELTA 插桩 ADD opcode 后,样本 Top4 候选恰好是 K';实时构建同样只出现 4 个高频道候选 确证
6 opcode 表的栈变量名每份构建都不同(样本 g / 雨云实时 j / 1ms M) 同一正则在三份脚本上分别命中,写死 g 时实时脚本匹配数为 0 确证
7 tdc.js 至少两代明文布局,新版字段序还随构建变化 旧版首段 {"cd":[[],"1920-1080...";雨云实时 {"cd":[1,[],"Apple M1",24,...;1ms 实时 {"cd":[1791712995,0,... 确证
8 服务端不校验 collect 与 eks 的同源性(宽松 aid) 雨云 aid + 硬编码旧密钥 + 旧版明文 → errorCode=0 + 真实 ticket 确证
9 「Node 跑密钥 + Python 全算法」端到端可用 雨云 aid 纯 Python 出包 → errorCode=0,ticket=tr03IsAVmQyixMlGay--3wugC_... 确证

二、未知(附假设 + 确信度)

# 未知 当前假设 确信度
1 1ms aid=195672344 为何在答案正确时返回 errorCode=12 该 aid 启用了更严格风控,要求会话具备真实验证码页面上下文 中
2 新版明文字段语义(哪一位是时间戳/指纹/轨迹) 时间戳是 1[6-9]\d{8} 形态的大整数;轨迹是 [x,y,t] 三元组数组 中高
3 明文里 [360,360]、`"1920-1080-1055-24--- -*"` 的作用 后者是屏幕/窗口指纹串,在新版被移到了 cd 数组末尾

三、已排除的假设(负结果也是资产,§5.7)

假设 否定证据
密钥每次运行随机 同一脚本 3 次运行首块完全一致
密钥可从 eks 推导(MD5/SHA/切片) 34 种推导 + 40 种偏移切片全部解密失败
密钥是脚本里的字面量 全脚本 >1e9 的数只有 3 个
用 Array.prototype.push 打桩能抓到密钥 VM 算术 opcode 用 g[g.length-2]=... 直接下标赋值,push 桩只记录到 5783 个值且无信号
实时构建复用旧版明文布局 旧版校验器对两份实时脚本全部失败;解密后首部格式完全不同
换出口 IP 能解决 1ms 的 12 4 个不同省份住宅 IP(含代理)全部 12
换遥测引擎能解决 1ms 的 12 python / python_keyed / node / browser(真实 Chrome)全部 12
长静默窗口能解决 1ms 的 12 静默 9 分钟 + 单发一次 → 仍 12

四、本轮目标(已完成)

  • 识别 collect 加密算法为教科书 XTEA 并逐字节验证
  • 实现版本无关的 opcode 插桩(反向引用自动识别栈变量名)
  • 从任意 tdc.js 无歧义复原 4 个密钥字(含索引歧义处理)
  • 实现模板标定 + 纯 Python 回填,端到端拿到真实 ticket
  • 固化回归测试(tcaptcha/tests/test_xtea_key.py,11 项断言)

五、下一步(可被下一轮直接执行)

  1. 拿下 1ms 的 12:用 CDP 打开真实验证码页面,让原生 SDK 自己跑 tdc.js, 复用本仓库视觉求解器算坐标、Input.dispatchMouseEvent 在 iframe 内真实点击。 骨架在 tcaptcha/tdc_browser.js。
  2. 补齐新版明文字段语义:对照 10+ 份实时模板做差分,把时间戳/指纹/轨迹位点名。
  3. 实现 2408 图标点选:用 1ms 的图标类别重训 yolo_detector + icon_classifier。
  4. 实现滑块 (2401/2402):模板匹配找缺口 + 生成滑动轨迹。

六、复验入口

.venv/bin/python -m tcaptcha.tests.test_xtea_key     # XTEA + 密钥提取 (11 项)
.venv/bin/python -m tcaptcha.tests.test_glyph_solver # 文字点选求解 (8 张真实样本)
.venv/bin/python -m tcaptcha.selftest                # 全部