feat(slider): 滑块 (2401/2402) 端到端打通 —— errorCode=0

做了什么:
- solvers/slider.py: 新增 SliderChallenge(把课题 JSON 解析成解题参数)+ piece_from_sprite
  (按 sprite_pos/size_2d 裁拼图块)+ track_limit 解析 / clamp_x / answer(按 data_type 组答案)
- telemetry/values.py: 新增 drag_trajectory_points(拖动轨迹:按下->横移->松手,
  首点绝对、其余增量、尾点固定 [1,1,12]);_sample_dt 抽成模块级供两条轨迹复用
- telemetry/{values,crypto}.py: generate_collect / generate_telemetry 接受 trajectory=
- protocol/client.py: 新增滑块分支(拉底图 + 精灵图 -> 裁块 -> ZNCC -> 组答案 -> 拖动轨迹),
  accept_kinds 默认扩为 文字点选 + 图标点选 + 滑块
- scripts/verify/send_test.py: 加 --kind text|slider|icon|any

关键结论(账本 #60~#63):
- 滑块答案是 DynAnswerType_POS,但坐标用**背景图原始像素**(不是页面显示像素):
  所以解题用 scale=1.0 直接提交 target_x_image;elem_id / data_type 均取自 move_cfg
- 拼图块可从课题配置直接裁,与旧 DOM 换算结果**逐像素相同**(测试已加交叉断言)
- **ddddocr 的滑块距离识别不可用**:fixture 偏 59px、实时偏 60px。判定手段是把拼图块
  alpha 轮廓叠到背景上目视 —— 本项目 ZNCC 与缺口描边严丝合缝,ddddocr 整体右偏
- 低置信度(margin=0.024 < 0.08)那次被正确拒答并换题,换题后立刻成功,安全网有效

怎么验证:
- .venv/bin/python -m tcaptcha.tests.test_slider_solver   全绿(新增 [6]/[7] 两组断言)
- .venv/bin/python -m tcaptcha.selftest                   全绿
- .venv/bin/python scripts/verify/send_test.py --kind slider   3/3 errorCode=0
- 文字点选回归不受影响:--kind text 仍为 errorCode=0
This commit is contained in:
yml2213
2026-10-12 12:46:35 +08:00
parent 344eea2194
commit 6a8b3b3ce4
7 changed files with 294 additions and 33 deletions
+16 -7
View File
@@ -169,6 +169,10 @@ crypto.build_collect(c1,traj,c2,sd,key) -> 4 段独立加密后拼接
| 57 | **纯离线闭环已打通**(本任务的核心阻塞点) | `scripts/verify/verify_offline.py`:tdc.js → 37 语义名 → 38 槽取值 → 4 段明文 → 4 段加密拼接 → 解密/切段/解析 → **逐槽全等 + 分段几何一致**;产物末尾 `==` 只来自未 pad 的 sd 段 | 确证 |
| 58 | **纯离线生成的 collect 在 1ms aid=195672344 上端到端拿到 `errorCode=0` + 真 ticket**(3/3) | 2026-10-12 实测 `scripts/verify/send_test.py --mode python_values`(aid 195672344 / 签到页 / 2404 文字点选 / 零 Node)。三次分别拿到 `tr03tgI-J732…`、`tr03RLpt4OTMy…`、`tr03n_V7CXAFI…`。每颗 collect 都由**本次会话同一份 tdc.js** 纯离线生成:段几何 461/625/147/16、460/640/148/16、81/708/529/16(每份构建清单序不同 → 分界点不同),轨迹 61/63/71 点、尾点一律 `[1,1,12]` | 确证 |
| 59 | **A/B 隔离出真正自变量:collect 必须「用本次会话的构建」生成** | 同 aid / 同一天 / 同客户端 / 同求解器、答案都正确,只换 collect 构造方式:<br>`python_values`(本次会话构建 → 槽序与取值都对)→ **0**(3/3);<br>`python_keyed`(仓库里那份 **2026-10-11** 成功样本模板回填:槽序来自**另一份构建**,屏串还是**另一台设备**的 `2560-1440-1345-24`)→ **12**(2/2)。<br>→ **推翻已知 #40**("谁在发 HTTP");同时把 #31/#32 的"槽序/取值必须与本次会话构建同源"从假设升级为确证 | 确证(含推翻 #40) |
| 60 | **滑块答案格式 = `DynAnswerType_POS`,坐标用「背景图原始像素」** | 真机课题 JSON:拼图块元素(id=1)的 `move_cfg = {track_limit:"x>=50&&x<=552", move_factor:[1,0], data_type:["DynAnswerType_POS"]}`;`init_pos=[50,128]` 与提交答案的 data 是**同一坐标系**(`bg_elem_cfg.size_2d = 672x480`)。所以解题时用 `scale=1.0`,直接把 `target_x_image` 当答案,不要换成页面显示像素 | 确证 |
| 61 | **滑块的拼图块可直接从课题配置裁剪,不必解析 DOM** | 拼图块元素自带 `sprite_pos=[140,490]` + `size_2d=[120,120]`;与早先从 CSS `background-position/size` 反算出的 `sprite_region() == (140,490,120,120)` **逐像素相同**(测试里已加交叉断言) | 确证 |
| 62 | **ddddocr 的滑块距离识别在腾讯滑块上不可用** | fixture(真值 target_x=343 / dx=293):`slide_match` 给 402/352(**偏 59px**),`simple_target=True` 同样 402,`slide_comparison` 直接报尺寸不匹配;实时样本(真值 236)给 296(**偏 60px**)。判定手段:把拼图块 alpha 轮廓按候选位置叠到背景图上目视 —— 本项目 ZNCC 的 236 与缺口描边**严丝合缝**,ddddocr 的 296 整体右偏 | 确证(负结果,别再试) |
| 63 | **滑块端到端已打通**(纯离线 collect + ZNCC 定位) | `send_test.py --kind slider` **3/3 拿到 errorCode=0 + 真 ticket**;轨迹为拖动型(~34 点、尾点 `[1,1,12]`)。其中一次 `margin=0.024 < 阈值 0.08` 被**正确拒答并换题**,换题后立刻成功 —— 置信度安全网有效 | 确证 |
---
@@ -342,7 +346,10 @@ TencentCaptchaClient(telemetry_mode="python_keyed") # 默认
已知 #30 的真机明文基本对齐;**关键是每份构建的槽位序**(已知 #31)——
见上面 1(b)。分析入口:`scripts/analyze_collect_layout.py`。
4. **实现 2408 图标点选**:按 1ms 图标类别重训 `yolo_detector` + `icon_classifier`。
5. **实现滑块 (2401/2402)**:模板匹配找缺口 + 生成滑动轨迹(1ms 大幅下发滑块,见抓包)。
5. ✅ **已完成(2026-10-12)—— 滑块 (2401/2402)**:不用模板匹配,改用**拼图块内容与缺口做 ZNCC**
(缺口 = 同一块内容被压暗,真缺口相关性最高、干扰缺口次之)。答案格式从课题 JSON 的
`move_cfg.data_type` 取(`DynAnswerType_POS`,坐标=背景图原始像素),轨迹走`drag_trajectory_points`。
实测 3/3 拿到 `errorCode=0`。**ddddocr 的滑块距离识别已验证不可用**(偏 59~60px,见已知 #62)。
---
@@ -389,10 +396,12 @@ TencentCaptchaClient(telemetry_mode="python_keyed") # 默认
.venv/bin/python scripts/verify/verify_offline.py /tmp/1ms_bridge/session_build.js
# 期望: 逐槽全等=是、分段几何=一致
# ⑩ 真实发送测试(**只打 1ms 签到页的文字点选**;会真的 POST verify)
.venv/bin/python scripts/verify/send_test.py --mode python_values # 期望 errorCode=0
.venv/bin/python scripts/verify/send_test.py --mode python_keyed # 对照:期望 12
# 脚本会 hook generate_telemetry,打印这一颗 collect 的段几何 + 轨迹点数,
# 用来证明发出去的确实是"本次会话构建"生成的包。注意 prehandle 会混发滑块,
# 脚本按 accept_kinds 自动刷新到 2404 文字点选为止(刷新耗尽则退出、不提交)。
# ⑩ 真实发送测试(1ms 签到页;会真的 POST verify)
.venv/bin/python scripts/verify/send_test.py --kind text --mode python_values # 文字点选,期望 0
.venv/bin/python scripts/verify/send_test.py --kind slider --mode python_values # 滑块,期望 0
.venv/bin/python scripts/verify/send_test.py --kind icon --mode python_values # 图标点选
# --kind any 表示三种都接。脚本会 hook generate_telemetry 打印这一颗 collect 的
# 段几何 + 轨迹点数,用来证明发出去的确实是"本次会话构建"生成的包。
# 注意 prehandle 三种题型混发,脚本会按 accept_kinds 自动刷新到目标题型
# (刷新耗尽就退出、不提交 —— 那是没抽到题,不是求解失败)。
```