reverse-skills-max: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok609hecl1pq6qi
2026-10-20 02:17:15 +03:00
commit da24c2bd20
2227 changed files with 443931 additions and 0 deletions

View File

@@ -0,0 +1,218 @@
---
name: web-reverse-algorithm
description: 面向 Web/JS 逆向中的纯算、验证码纯算、复杂 header/cookie 签名、混合加密、JSVMP/VMP、Wasm、PoW、响应解密、指纹与 challenge 参数还原工作流。用于需要从最终请求、最终 cookie、最终 verify 或最终 WebSocket 帧倒推 writer、builder、entry、source,设计浏览器与本地对齐检查点,判断何时做 AST 解混、何时插桩、何时做最小补环境、何时拆图像线与参数线、以及如何把研究结果落成 solver、SDK、脚本或服务的场景。用户明确提到纯算、验证码纯算、滑块、点选、旋转、PoW、collect、w、x-s、a_bogus、encSecKey、captchaBody、X-Bogus、Wasm、国密、补环境、指纹、challenge、verify、header 签名、cookie 签名时使用。
---
# Web 逆向纯算
这项技能不是“给一个固定公式”,而是把资料库里的方法层、题型层、训练层、工程化层压成一套总入口。
先把任务压缩成这条闭环,再决定读哪份 references、走哪条路径、写哪种落地代码:
```text
最终请求 / 最终 cookie / 最终 verify / 最终 WS 帧
-> writer
-> builder
-> entry
-> source
```
## 核心原则
1. 先找最终写出点,不先读混淆大文件。
2. 先存中间值,不先猜算法名。
3. 先缩小执行范围,再补环境。
4. 先证明输入输出边界,再决定是否整体迁移。
5. 先把结果整理成可复用结构,再继续做版本适配。
## 使用顺序
### 1. 先判题型
把目标先归到下面之一:
- 标准签名 / 标准摘要题
- 混合加密 / 密钥包装题
- Cookie / Header / 多参数联动题
- JSVMP / VMP / 强混淆纯算题
- Wasm / Protobuf / WebSocket / 二进制协议题
- 验证码 / 风控 / challenge 题
如果还没分清,先读 [references/01-decision-tree.md](./references/01-decision-tree.md)。
### 2. 再判当前阻塞点
优先判断你卡在下面哪一类:
- 入口没找对
- 原始串或原始 payload 没对齐
- 中间数组 / 中间对象没采到
- 运行时依赖没补齐
- 图像线和参数线没拆开
- 协议边界没证明
遇到这一步拿不准时,优先读 [references/04-debug-env-playbook.md](./references/04-debug-env-playbook.md)。
### 3. 按题型选路线
#### 标准签名 / 混合加密 / Cookie / Header / 国密
适用信号:
- 输出长度规整
- `md5/sha1/hmac/aes/rsa/sm3/sm4`
- `token&t&appKey&data`
- `params + encSecKey`
- `document.cookie` 或 header 明显可追
优先读取 [references/02-algorithm-families.md](./references/02-algorithm-families.md)。
#### JSVMP / VMP / 小红书 / a_bogus / 多参数复杂纯算
适用信号:
- 大数组、解释器、`for(;;)+switch`
- 位运算密集、状态数组、寄存器式写法
- `window._webmsxyw`、`__TENCENT_CHAOS_VM`、`byted_acrawler` 一类入口
优先读取 [references/02-algorithm-families.md](./references/02-algorithm-families.md) 和 [references/04-debug-env-playbook.md](./references/04-debug-env-playbook.md)。
#### Wasm / Protobuf / WebSocket / challenge 协议
适用信号:
- `WebAssembly.instantiate`
- `application/x-protobuf`
- 二进制响应、导出函数、首包/验证包分段
优先读取 [references/02-algorithm-families.md](./references/02-algorithm-families.md) 和 [references/03-captcha-families.md](./references/03-captcha-families.md)。
#### 验证码 / 风控 / challenge / verify
永远先拆 5 条线:
1. 初始化 / challenge 线
2. 图像或题面识别线
3. 参数 builder 线
4. 环境 / 指纹 / collect 线
5. 最终 verify 线
优先读取 [references/03-captcha-families.md](./references/03-captcha-families.md)。
## 统一工作流
### 1. 锁定最终写出点
优先从这些位置切:
- `fetch`
- `XMLHttpRequest.send`
- `setRequestHeader`
- `document.cookie`
- `JSON.stringify`
- verify 提交点
- WebSocket 首包或验证包发送点
### 2. 记录 5 层检查点
至少保留:
1. writer 检查点:最终 URL / header / body / cookie / WS 帧
2. builder 输入:query、payload、token、challenge、distance、track、browser info
3. 原始串或原始 payload
4. 中间数组 / 中间对象 / 编码前字节流
5. 最终输出
### 3. 先恢复中间态,再恢复最终编码
这条规则在下面几类题里尤其重要:
- 小红书 `x-s / x-s-common`
- 抖音 `a_bogus / X-Bogus`
- 腾讯 `collect`
- 网易盾 `w`
- 各类 `payload -> encode` 的 header 家族
### 4. 只在必要时补环境
优先补到最小可运行边界:
1. `window/self/globalThis/document/navigator/location`
2. `cookie/storage/performance/Date/crypto`
3. `canvas/webgl/audio/plugins/mimeTypes/RTCPeerConnection`
如果目标已经被收缩成纯函数,就不要把任务升级成“大补环境题”。
### 5. 把结果收敛到工程接口
最终优先沉淀下面这些产物:
- 最小输入集合
- 中间检查点集合
- `build_context()` / `build_payload()` / `sign()` / `solve()` 这种分层接口
- 本地样本与浏览器样本对照
- 失败诊断点
## 你应该产出的结果
使用这项技能时,优先输出:
1. 题型判断
2. writer / builder / entry / source 分层
3. 当前阻塞点判断
4. 必要检查点列表
5. 是否需要 AST、插桩、补环境、图像识别或协议拆包
6. 推荐的落地结构:函数、solver、SDK、服务
7. 易错点与版本风险
## 资源导航
- [references/01-decision-tree.md](./references/01-decision-tree.md)
用途:先做题型判断、阻塞点判断、请求链定位。
- [references/02-algorithm-families.md](./references/02-algorithm-families.md)
用途:标准签名、混合加密、Cookie/Header、JSVMP、Wasm、国密、站点家族模式。
- [references/03-captcha-families.md](./references/03-captcha-families.md)
用途:腾讯、极验、网易盾、百度旋转、阿里 v2、V5、拼多多、hCaptcha 等验证码/风控路线。
- [references/04-debug-env-playbook.md](./references/04-debug-env-playbook.md)
用途:hook、logpoint、最小补环境、浏览器/本地对齐、反调试与证据管理。
- [references/05-training-routes.md](./references/05-training-routes.md)
用途:学习顺序、训练阶段、案例如何带新人、视频资料怎么吸收。
- [references/06-engineering-maintenance.md](./references/06-engineering-maintenance.md)
用途:GitHub 项目怎么吸收、接口如何设计、扩库时怎么记主落点/补充落点/标签。
- [scripts/new_case_scaffold.py](./scripts/new_case_scaffold.py)
用途:新站点或新 challenge 建标准化案例目录。
## 案例脚手架
要在工作区里快速起一套“可复盘、可扩展”的案例骨架,运行:
```powershell
python "<skill-dir>\\scripts\\new_case_scaffold.py" `
"case-name" `
--type captcha `
--family tencent `
--tags captcha,collect,pow `
--sources "https://example-a,https://example-b" `
--language py `
--output ".\\research"
```
脚手架会生成:
- `case-overview.md`
- `request-chain.md`
- `evidence-log.md`
- `checkpoints.json`
- `metadata.json`
- `solver_stub.js` 或 `solver_stub.py`
- `todo.md`
## 最后约束
始终偏向下面这些做法:
1. 从真实请求或真实 sink 进入。
2. 对浏览器值和本地值建立同构检查点。
3. 先拆算法层、环境层、协议层,再决定怎么迁移。
4. 同站点多文章时记录“思路差异”,不要只保留一个最终答案。
5. 每个案例都沉淀输入边界、检查点、代码骨架、易错点,而不是只留最终成品。

View File

@@ -0,0 +1,7 @@
interface:
display_name: "Web 逆向纯算"
short_description: "面向纯算、验证码与 JSVMP 的中文工作流技能"
default_prompt: "Use $web-reverse-algorithm to 规划目标站点的纯算路径、检查点、训练路线与工程化落地。"
policy:
allow_implicit_invocation: true

View File

@@ -0,0 +1,219 @@
# 决策树与路由
## 一、先问 4 个问题
1. 真正决定成败的是哪条请求、哪次 cookie 写入、哪次 verify、哪帧 WebSocket。
2. 目标字段长什么样:`sign / cookie / header / body / verify payload / track / collect / image result`。
3. 当前题型属于哪类:标准签名、混合加密、Cookie/Header、JSVMP/VMP、Wasm/协议、验证码。
4. 当前阻塞点属于哪类:入口、原始串、中间态、环境、图像线、协议线。
如果这 4 个问题答不清,就不要直接抄大文件。
## 二、题型判断
### 1. 标准签名题
信号:
- 输出长度规整
- `md5/sha1/hmac`
- 原始串可恢复
- 请求字段关系稳定
代表:
- 财联社
- 百度翻译
- 有道翻译
- 淘宝 H5
### 2. 混合加密题
信号:
- 对称加密和非对称包装并存
- `params + encSecKey`
- 返回包也可能要解密
代表:
- 网易云音乐
- 部分响应解密题
### 3. Cookie / Header / 多参数联动题
信号:
- 值写进 `document.cookie`
- 或多个字段共同收口成最终 header
- 中间字段承担不同角色
代表:
- 盼之 cookie
- 滴滴 `dd03/dd05/wsgsig`
- 某农网 `X-CLIENT-SIGN`
### 4. JSVMP / VMP 题
信号:
- 大数组
- `for(;;) + switch`
- 寄存器式状态机
- 值逐位、逐段、逐数组构造
代表:
- 抖音 `a_bogus`
- 小红书 `x-s`
- QQ 音 VMP
### 5. Wasm / 协议题
信号:
- `WebAssembly.instantiate`
- protobuf / 二进制 payload
- WebSocket 分段交互
代表:
- Wasm 签名题
- Spiderdemo T6
- V5 / hCaptcha 某些阶段
### 6. 验证码 / 风控题
信号:
- 至少两段请求
- 图像、参数、环境并存
- `collect/w/fs/pow_answer` 等字段
代表:
- 腾讯滑块
- 极验 3/4 代
- 网易盾
- 百度旋转
- 阿里 v2
## 三、阻塞点判断
### A. 入口没找对
信号:
- 说不清 writer 是谁
- 本地跑的是 wrapper,不是 builder
- 看了很多代码仍然找不到真实输入边界
优先动作:
1. 回到最终请求或最终 sink。
2. 重建 `writer <- builder <- entry <- source`。
3. 暂停做补环境和整体迁移。
### B. 原始串没对齐
信号:
- 最终长度对但值不对
- hash 前原文和浏览器不同
- JSON / query / path / cookie 顺序不对
优先动作:
1. 打印原始串。
2. 固定时间戳和随机数。
3. 检查 token、cookie、UA、序列化格式。
### C. 中间态没采到
信号:
- JSVMP 题只知道最终输出
- AST 做完仍然无法下手
- 复杂 builder 没有任何关键数组和对象
优先动作:
1. 对数组写入点插桩。
2. 对 builder 做输入输出 hook。
3. 用 logpoint 代替高频断点。
### D. 运行时依赖没补齐
信号:
- `window/document/navigator` 未定义
- 浏览器与本地中间态差异大
- `collect`、环境位串、指纹值明显不一致
优先动作:
1. 收缩到最小入口。
2. 记录真实访问属性。
3. 只补进入 builder 的必要对象。
### E. 图像线和参数线没拆开
信号:
- 一边调距离,一边调签名,一直不知道谁错
- verify 字段很多,却没有分线记录
优先动作:
1. 单独保存识别结果。
2. 单独保存 builder 输入对象。
3. 让识别结果作为 builder 显式输入。
### F. 协议边界没证明
信号:
- 二进制帧很多,但不知哪一段是真校验
- Wasm、protobuf、WS 全混在一起
优先动作:
1. 先数包或先列导出函数。
2. 证明输入输出关系。
3. 再决定是否反编译或迁移。
## 四、统一闭环
```text
目标字段
<- writer
<- builder
<- entry
<- source
```
然后固定这 5 层检查点:
1. writer 检查点
2. builder 输入
3. 原始串 / payload
4. 中间数组 / 中间对象
5. 最终输出
## 五、常用标签
- `header-sign`
- `cookie-sign`
- `response-decrypt`
- `captcha`
- `vmp`
- `jsvmp`
- `wasm`
- `protobuf`
- `websocket`
- `env`
- `fingerprint`
- `ast`
- `solver`
- `service`

View File

@@ -0,0 +1,176 @@
# 算法家族与站点模式
## 一、标准签名题
### 统一结构
```text
request params
-> normalize / stringify / sort
-> inject token / timestamp / cookie / ua
-> hash / encrypt
-> final sign
```
### 高频站点模式
#### 财联社
- 典型链:`query string -> SHA1 -> MD5`
- 真正难点:参数排序、URL 编码、query string 一致性
#### 百度翻译
- `token` 来自页面
- `sign` 来自前端函数
- 典型价值:页面态参数与 JS 纯算参数分离
#### 有道翻译
- 请求签名:`client + mysticTime + product + key -> MD5`
- 响应侧还存在固定 seed 派生的 `AES-CBC` 解密
- 典型价值:同题同时训练请求签名和响应解包
#### 淘宝 H5
- 典型链:`token&t&appKey&data -> MD5`
- 真正难点:token 提取、`t` 一致性、紧凑 JSON
## 二、混合加密题
### 统一结构
```text
明文
-> 对称加密
-> 对称加密或再次包装
-> 编码
-> params
随机 key
-> reverse / transform
-> RSA / SM2
-> encSecKey / signature
```
#### 网易云音乐
- 双层 AES-CBC + RSA
- 重点不是入口,而是“业务数据”和“密钥包装”分层
## 三、Cookie / Header / 多参数联动题
### Cookie 题
统一结构:
```text
环境采集
-> builder
-> hash / encrypt / encode
-> document.cookie 写入
```
最稳入口:
- Hook `document.cookie`
- 回栈看 builder
- 继续追环境采集层
#### 盼之 cookie
- 典型价值:从 cookie sink 反推 IIFE 和 builder
### 多参数联动题
#### 滴滴 `dd03 / dd05 / wsgsig`
- `dd03` 更偏纯算层
- `dd05` 更偏运行时或 webpack/VMP 层
- `wsgsig` 更像收口层
- 最稳打法:先拆组成件,再拆最终收口件
#### 某农网 `X-CLIENT-SIGN`
- 先盯最终缺的 header
- 再把真正返回它的混淆函数整段收缩
## 四、JSVMP / VMP 题
### 共同策略
1. 不从文件头正推。
2. 先找最终 writer 和最终返回值。
3. 先恢复中间数组 / 中间对象 / payload。
4. 再恢复最终编码层。
### 小红书 `X-s / X-t / X-S-Common`
- 第一入口是 `window._webmsxyw()`,不是最终 header 串。
- 必须把 `X-s` 和 `X-S-Common` 分开看。
- `X-S-Common` 体现的是 header 家族和环境/指纹字段联动。
- 高频中间结构:`x1 / x2 / x3 / x4 / payload`。
- 同站点多文章要分“入口定位”“AST 解混”“JSVMP 结构”“环境位串”“算法骨架”五种思路记录。
### 抖音 `a_bogus`
- 不要把它简化成 `SM3 + RC4 + Base64`。
- 真正难点是多段数组、状态推进、时间戳/随机数/UA/环境材料如何进入 96/128/136 位数组。
- 最该保存的检查点:双 SM3 输出、41 位浏览器数组、50 位主数组、96/128/136 位数组、最终 `a_bogus`。
### QQ 音 / Spiderdemo / 复杂 VMP
- 更适合当“标准题”和“超重型对抗题”之间的过渡训练。
- 优先练 webpack 入口定位、最终 writer 确认、协议/页面回填拆分。
## 五、Wasm / 协议题
### Wasm
优先顺序:
1. 找加载点
2. 找 Wasm URL
3. 看 `instance.exports`
4. 用固定输入验证输出
5. 再决定是否反编译
### Protobuf / WebSocket
- 先数包或先确认 message type
- 先拆协议线和页面线
- 不要一开始就把二进制题当“某个 sign 函数”
#### Spiderdemo T6
- 重点不是 sign,而是 protobuf + 页面占位回填
## 六、国密题
### SM3
- 经常作为最终签名层或中间摘要层出现
- 真正要对齐的是:原始明文、SM3 输入字节、SM3 输出、后续 builder 输入
### SM4
- 分析重点和 AES 类似:key、iv、模式、padding、编码层
### SM2
- 更适合作为“识别型知识”
- 先确认它是不是关键层,再决定是否优先迁移
## 七、最小落地接口
优先收敛成这类分层:
```text
build_context
-> build_raw_string / build_payload
-> crypto_or_vm_layer
-> validate_checkpoints
-> final_output
```
不要把所有逻辑塞进一个大函数里。

View File

@@ -0,0 +1,145 @@
# 验证码与 challenge 家族
## 一、验证码统一拆法
先拆 5 条线:
1. 初始化 / challenge 线
2. 图像或题面识别线
3. 参数 builder 线
4. 环境 / 指纹 / collect 线
5. 最终 verify 线
每条线都单独保存证据,不要混写。
## 二、高频字段
- `collect`
- `pow_answer`
- `pow_calc_time`
- `w`
- `fs`
- `ac_c`
- `Signature`
- `SignatureNonce`
- `captcha_collect`
- `behavior`
- `token`
- `challenge`
- `lot_number`
- `payload`
不要只看它像不像密文,要看:
1. 删除后是否失败
2. 伪造后是否失败
3. 是否与识别结果、时间戳、环境值绑定
## 三、站点家族
### 腾讯滑块 / TCaptcha
两条路线要分开:
1. `prehandle -> 图像 -> gap -> PoW -> collect -> verify` 的纯 HTTP 工程链
2. `tdc.js / VM / collect` 的补环境 + VMP 链
重点:
- `pow_answer` 与 `pow_calc_time`
- `collect`
- 轨迹与 gap 的一致性
- 不要把腾讯题误写成“只靠图像和轨迹”
### 极验 3/4 代
#### 三代
- 高价值入口:搜 `"\u0077"`
- 重点不是只盯最终 `w`,而是记录 `h + u`
#### 四代
- `captcha_id` 更像固定配置
- `challenge` 更像运行时生成值
- 必须记录 `load` 返回对象
### 网易盾
统一链:
```text
初始化
-> 图片接口
-> 距离识别
-> userAnswer
-> P1~P9
-> w
-> verify
```
重点:
- 图片接口返回对象要保留
- `userAnswer` 可能是距离、比例、固定分隔材料、时间戳的组合
- 不能只做图像,不做 `w`
### 百度旋转 / 阿里 v2 / 某多多
- 某度旋转:图像角度恢复 + `fs/ac_c/tk`
- 某里 v2:`SignatureNonce / Signature / 排序+编码` 更重
- 某多多:图片/标题解密 + 坐标 verify + `captcha_collect`
### V5 / WebSocket challenge
- 先数包,再分首包、图片包、验证包
- 不要在协议边界不清时直接猜算法
### hCaptcha / Cloudflare / PerimeterX 一类强对抗 challenge
- 需要从一开始就把 `WASM + 指纹 + 状态机 + challenge 请求链` 分层
- 这些题常常同时存在“纯算路线”和“环境拟合路线”
## 四、验证码统一检查点
每题至少保存:
1. 初始化请求参数
2. 图片或 challenge 资源返回值
3. 识别结果
4. 轨迹明文
5. builder 输入对象
6. builder 输出对象
7. 浏览器发送值
8. 本地生成值
## 五、何时先修图像,何时先修参数
### 先修图像线
适用:
- 参数层较薄
- verify 明显只校验距离/角度/坐标
### 先修参数线
适用:
- `collect/signature/w/fs` 明显更重
- token/challenge/load 返回对象没喂进去
- 环境值明显不一致
## 六、验证码 Solver 落地结构
推荐拆成:
```text
fetch_challenge
-> solve_image
-> build_track_or_answer
-> build_param_payload
-> verify
```
不要把图片识别、参数 builder、环境模拟写成一个大函数。

View File

@@ -0,0 +1,183 @@
# 调试、补环境与证据管理
## 一、优先级
优先采用:
1. Hook / logpoint
2. 调用栈回溯
3. 条件断点
4. 普通断点
原因:
- Hook 更适合持续采样
- Logpoint 更适合 JSVMP / 高频状态机
- 调用栈更适合区分 builder 和 wrapper
## 二、最值钱的 hook 点
### 请求链
- `fetch`
- `XMLHttpRequest.prototype.open`
- `XMLHttpRequest.prototype.send`
- `setRequestHeader`
- `JSON.stringify`
### 结果写出点
- `document.cookie`
- 目标对象字段写入
- 已知 builder 函数
### 运行时代码
- `eval`
- `Function`
- `Date.now`
- `Math.random`
- `crypto.getRandomValues`
## 三、最小补环境优先级
### P0:先让代码进入 builder
- `window`
- `self`
- `globalThis`
- `document`
- `navigator`
- `location`
### P1:再对齐 builder 输入
- `document.cookie`
- `localStorage`
- `sessionStorage`
- `performance`
- `Date`
- `crypto`
- `screen`
- `history`
### P2:最后才补拟真指纹层
- `canvas`
- `webgl`
- `audio`
- `plugins`
- `mimeTypes`
- `RTCPeerConnection`
- `indexedDB`
- `Intl`
默认只补到 P0 或 P1。
## 四、判断是不是环境问题
### 应先补环境的信号
- 入口直接报对象未定义
- 浏览器与本地中间态差异显著
- `collect`、环境位串、指纹对象明显不一致
### 不应先补环境的信号
- 已经收缩成纯函数
- 真实问题是入口没找对
- 真实问题是 token、cookie、challenge、load 返回对象没喂进去
## 五、四层证据
### 1. source 检查点
记录:
- cookie
- storage
- UA
- 页面配置
- challenge 初值
### 2. builder 输入检查点
记录真正喂给 builder 的对象。
### 3. builder 中间态检查点
记录:
- 原始串
- 中间数组
- payload
- 编码前字节流
### 4. 最终输出检查点
记录:
- sign
- token
- collect
- verify payload
## 六、浏览器与本地对齐
每次做本地复现时都执行:
1. builder 输入是否一致
2. 原始串是否一致
3. 中间数组 / payload 是否一致
4. 最终编码前数据是否一致
5. 最终结果是否一致
只比最终值通常不够。
## 七、AST 的边界
AST 最适合做:
- 字符串表还原
- 常量折叠
- 死代码删除
- 简单代理函数内联
- 局部控制流整理
AST 不适合代替:
- JSVMP 运行时取证
- 强环境依赖 builder
- 高频状态机调试
最稳的顺序是:
```text
先定 writer
-> 再做局部 AST 降噪
-> 再做 hook / logpoint
```
## 八、反调试与拟真问题
高频问题:
- `debugger` 死循环
- 时间差检测
- `toString` 检测
- 原型链检测
- Proxy 暴露问题
优先原则:
1. 先让观察成本下降。
2. 先保留证据,再决定是否深拟真。
3. 不要一上来把所有原型链和 native 外观都补掉。
## 九、常见误区
1. 先补环境,再找入口
2. 只追求不报错
3. 只在最终值处打点
4. 普通断点打太多,反而丢主线
5. 没有留下任何可复用工件

View File

@@ -0,0 +1,115 @@
# 训练路线与案例使用法
## 一、训练阶段
### 第一阶段:标准签名回溯能力
建议顺序:
1. 财联社
2. 淘宝 H5
3. 有道翻译
4. 百度翻译
目标:
- 会从最终字段回溯入口
- 会恢复原始串
- 会比对浏览器和本地值
### 第二阶段:加密分层能力
建议顺序:
1. 百度翻译
2. 网易云音乐
3. 响应解密类题
目标:
- 区分明文层、摘要层、加密层、编码层
- 不把所有步骤都混成一个 sign
### 第三阶段:复杂纯算能力
建议顺序:
1. 小红书 `x-s`
2. 抖音 `a_bogus`
3. 滴滴多参数题
4. Spiderdemo T5 / T6
目标:
- 从 writer 倒推中间结构
- 学会插桩和中间数组恢复
- 处理时间戳、随机数和环境依赖
### 第四阶段:验证码 / challenge / 风控
建议顺序:
1. 网易盾
2. 阿里 v2
3. 百度旋转 / 拼多多
4. 极验 3 / 4
5. 腾讯滑块
6. hCaptcha / Cloudflare / PerimeterX
目标:
- 拆 challenge、图像、参数、环境、verify 五条线
- 分清纯算问题、图像问题、环境问题
- 学会 solver 化组织
## 二、同站点多文章的正确读法
不要只保留一个“最终答案”,而要记录思路差异:
- 有的文章先讲入口定位
- 有的文章先讲 AST 解混
- 有的文章先讲 JSVMP 结构
- 有的文章先讲环境位串和补环境
- 有的文章先讲算法骨架和工程接口
这对小红书、a_bogus、腾讯滑块尤其重要。
## 三、案例最少应沉淀什么
每个案例至少留下:
1. 最终请求或最终 sink
2. 请求链闭环
3. 入口定位路径
4. 中间检查点
5. 本地代码骨架
6. 易错点
## 四、如何带新人
推荐讲法:
1. 标准签名题:讲最终字段、原始串、标准算法
2. 混合加密题:讲分层和输入边界
3. JSVMP 题:讲 writer、builder、中间结构恢复
4. 验证码题:讲 challenge、参数、环境、verify 分线
## 五、视频资料最该吸收什么
吸收的不是逐字内容,而是教学顺序:
- 先讲题型价值和目标字段
- 再讲入口定位
- 再讲标准算法层
- 再讲中间数组 / payload / builder
- 最后讲编码层、环境层或 verify 层
## 六、扩库时优先收哪些材料
优先收:
1. 明确写入口定位的
2. 明确写纯算插桩的
3. 明确写 VMP / JSVMP / 转序 / 魔改编码的
4. 明确写补环境 / 原型链 / 反混淆的
5. 明确把研究结果做成项目或 SDK 的

View File

@@ -0,0 +1,115 @@
# 工程化、GitHub 吸收与扩库维护
## 一、把逆向结果做成接口,而不是只做成笔记
优先把结果收敛为这些接口:
- `build_context(input)`
- `build_payload(ctx)`
- `sign_payload(payload, ctx)`
- `solve(ctx)`
- `validate(browser_checkpoints, local_checkpoints)`
## 二、GitHub 项目最值得学什么
真正值得吸收的不是“又一个能跑的脚本”,而是:
1. 最小输入集合怎么定义
2. 算法层、环境层、请求层怎么分模块
3. 哪些检查点要暴露给调用方
4. 失败如何分类成环境问题、参数问题、版本问题
## 三、国外工程化思路要补的 5 个意识
1. 模块化
2. 版本意识
3. 输入边界意识
4. 中间检查点意识
5. 失败诊断意识
## 四、推荐的项目层次
```text
context/
payload builder/
crypto or vm layer/
env patch/
validation/
service or sdk/
```
## 五、吸收来源时的记录模板
每条来源或每个仓库,至少记:
1. 主落点
2. 补充落点
3. 备注
4. 题型
5. 输入集合
6. 输出集合
7. 关键脚本文件
8. 最值得学习的结构
## 六、案例与来源的标签化
建议使用:
- `header-sign`
- `cookie-sign`
- `response-decrypt`
- `captcha`
- `vmp`
- `jsvmp`
- `wasm`
- `protobuf`
- `websocket`
- `env`
- `fingerprint`
- `ast`
- `solver`
- `sdk`
- `service`
## 七、扩库时的固定栏目
每篇新案例文档尽量保留:
1. 来源
2. 请求链
3. 关键字段
4. 入口定位
5. 代码骨架
6. 中间检查点
7. 易错点
## 八、推荐从 GitHub 项目抄的文件角色
- `sign.py / xbogus.js`:算法层
- `get_fingerprint.js`:环境采集层
- `deobfuscate.js`:前处理层
- `solve.py`:求解层
- `server.py / __main__.py`:服务封装层
## 九、版本变化时先改哪里
优先排查:
1. 输入边界有没有变化
2. 页面态参数或 load 返回对象有没有变化
3. 中间 payload 结构有没有变化
4. 只是编码层变了,还是 builder 逻辑变了
5. 环境字段是变成强校验了,还是仍然可写死
## 十、文档和代码的最终目标
目标不是“再多收集一篇文章”,而是让每次新增资料都能补到下面这条能力闭环:
```text
请求链定位
-> 算法或 builder 还原
-> 中间检查点对齐
-> 环境与协议边界确认
-> 本地复现
-> solver / SDK / 服务化
```

View File

@@ -0,0 +1,148 @@
# 验证码模式
## 适用目的
在目标涉及滑块、点选、旋转、行为校验、PoW 或 challenge/verify 协议时,用这份文档拆解线路。
## 一、先拆成 5 条线
不要把所有内容都写成“验证码逻辑”。先拆成:
1. 初始化 / challenge 线
2. 图像或题面识别线
3. 参数 builder 线
4. 环境 / 指纹 / collect 线
5. 最终 verify 线
## 二、验证码常见字段
高频字段示例:
- `collect`
- `pow_answer`
- `pow_calc_time`
- `w`
- `fs`
- `ac_c`
- `Signature`
- `SignatureNonce`
- `captcha_collect`
- `behavior`
- `token`
判断它们是否真的重要,不看“像不像密文”,而看:
1. 删除后是否失败
2. 改动后是否失败
3. 是否与识别结果、时间戳、环境值强绑定
## 三、5 类高频题型
### 1. 纯图像 + 轻参数
特征:
- 参数层较薄
- 识别结果最关键
推荐顺序:
1. 保存原图和小图
2. 先打通识别
3. 再看 verify 如何装入识别结果
### 2. 图像 + 中等参数混合
特征:
- 既要识别,也要还原 builder
- 常见角度、距离、坐标和参数共同参与校验
推荐顺序:
1. 先拆图像线
2. 再跟最终 verify
3. 对齐 builder 输入和中间 payload
### 3. 纯算 / 半纯算题
特征:
- 图像难度不高
- 轨迹、PoW、collect、signature 更重
推荐顺序:
1. 先拆请求顺序
2. 明确 token / challenge 来源
3. 再分析签名或 PoW
4. 最后微调轨迹或识别结果
### 4. JSVMP / 补环境题
特征:
- 大数组、解释器、环境读取多
- 入口在浏览器能跑,在本地容易报错
推荐顺序:
1. 先从 verify 参数赋值点倒推
2. 判断是值不对,还是入口直接报错
3. 前者先插桩,后者先补环境
### 5. WebSocket / 分段协议题
特征:
- 不再是单条 XHR
- 请求和响应分多段
- 首包和验证包职责不同
推荐顺序:
1. 先数包
2. 标记首包、图片包、验证包
3. 再拆 key 派生和加解密
## 四、验证码的统一检查点
每题至少保留这些检查点:
1. 初始化请求参数
2. 图片接口或题面返回值
3. 识别结果
4. 轨迹明文
5. builder 输入对象
6. builder 输出对象
7. 浏览器发送值
8. 本地生成值
## 五、轨迹和识别的通用提醒
### 轨迹
重点检查:
- 总时长是否合理
- 时间戳是否单调递增
- y 轴是否完全不动
- 末尾是否机械地精确对齐
### 识别
重点动作:
1. 先把识别结果单独保存成中间值
2. 不要把识别和网络请求死耦合
3. 让识别输出作为 builder 的独立输入
## 六、什么时候不要急着做图像
如果 verify 失败的主因是:
- token/challenge 不对
- collect/signature 不对
- 环境值不对
先修参数链和环境链,再修图像线;否则容易在错误链路上重复调参。

View File

@@ -0,0 +1,147 @@
# 调试、补环境与检查点
## 适用目的
在已经锁定目标字段后,用这份文档决定如何布断点、何时 hook、何时最小补环境,以及如何做浏览器/本地对齐。
## 一、优先用 hook 和检查点
优先级建议:
1. Hook / logpoint
2. 调用栈回溯
3. 条件断点
4. 普通断点
理由:
- hook 更适合持续采样
- logpoint 更适合高频状态机
- 调用栈更容易分清 builder 和 wrapper
## 二、最值钱的 hook 点
### 请求链
- `fetch`
- `XMLHttpRequest.prototype.open`
- `XMLHttpRequest.prototype.send`
- `setRequestHeader`
- `JSON.stringify`
### 结果写出点
- `document.cookie`
- 目标对象字段写入
- 已知 builder 函数
### 运行时代码
- `eval`
- `Function`
- `Date.now`
- `Math.random`
- `crypto.getRandomValues`
## 三、最小补环境优先级
### P0:先保证代码能进入 builder
- `window`
- `self`
- `globalThis`
- `document`
- `navigator`
- `location`
### P1:再保证 builder 输入正确
- `document.cookie`
- `localStorage`
- `sessionStorage`
- `performance`
- `Date`
- `crypto`
- `screen`
- `history`
### P2:最后才考虑拟真指纹层
- `canvas`
- `webgl`
- `audio`
- `plugins`
- `mimeTypes`
- `RTCPeerConnection`
- `indexedDB`
- `Intl`
默认只补到 P0 或 P1,除非证据明确指向指纹层。
## 四、判断是不是环境问题
### 先补环境的信号
- 入口直接报对象未定义
- 浏览器和本地中间态差异显著
- 关键结果显著依赖 `cookie/storage/ua/fingerprint`
### 不要先补环境的信号
- 已经收缩成纯函数
- 真实问题是入口没找对
- 真实问题是 token、cookie、challenge 没喂进去
## 五、四层检查点
### 1. source 检查点
记录:
- cookie
- storage
- UA
- 页面配置
- challenge 初值
### 2. builder 输入检查点
记录真正喂给 builder 的对象。
### 3. builder 中间态检查点
记录:
- 原始串
- 中间数组
- payload
- 编码前字节流
### 4. 最终输出检查点
记录:
- sign
- token
- collect
- verify payload
## 六、浏览器与本地对齐
每次做本地复现时都执行这套对比:
1. builder 输入是否一致
2. 原始串是否一致
3. 中间数组或 payload 是否一致
4. 最终编码前数据是否一致
5. 最终结果是否一致
只比较最终值,定位成本会非常高。
## 七、常见误区
1. 先补环境,再找入口
2. 只追求不报错
3. 一上来深拟真所有原型链
4. 只在最终值处打点
5. 没有保存任何中间工件

View File

@@ -0,0 +1,128 @@
# 纯算模式
## 适用目的
在确定目标不是纯验证码图片题之后,用这份文档选择更细的纯算路径。
## 一、标准签名题
### 核心结构
```text
request params
-> normalize / stringify / sort
-> inject token / timestamp / ua
-> hash / encrypt
-> final sign
```
### 高频模式
- `query_string -> sha1 -> md5`
- `token&t&appKey&data -> md5`
- `client + mysticTime + product + key -> md5`
- `params -> aes -> aes -> rsa`
### 必查点
1. 原始串字段顺序
2. URL 编码和 JSON 序列化格式
3. token、cookie、UA、时间戳来源
4. 是否还有响应解密链
## 二、Cookie / Header 题
### 核心结构
```text
source(cookie/storage/location)
-> builder
-> header/cookie writer
```
### 优先动作
1. Hook `document.cookie`
2. Hook `fetch` / `XMLHttpRequest.send`
3. 记录 header/body 最终长相
4. 回溯 writer 上游
### 常见坑
- 把初始化 cookie 当成业务 cookie
- 只记录最终值,不记录写入调用栈
- 漏掉页面状态和 location 参数
## 三、JSVMP / VMP 题
### 高危信号
- 数组很大
- 大量位运算
- switch 分发密集
- 值逐位拼接
### 推荐打法
1. 先找最终输出和中间数组
2. 先做低风险 AST:字符串表、常量折叠、死代码删除
3. 对数组写入点、对象取值点、位运算点做 logpoint
4. 先恢复中间 payload,再恢复最终编码
### 不要这样做
- 不要要求 AST 一次性完整还原 VM
- 不要用普通断点硬扛高频状态机
- 不要在没抓到中间态前整体迁移整段 VM
## 四、Wasm 题
### 高危信号
- `WebAssembly.instantiate`
- 导出函数直接影响 sign
- JS 中只看到薄封装
### 推荐打法
1. 找 wasm 加载点
2. 找导出函数名
3. 喂固定输入看输出
4. 能改写成 JS/Python 则优先改写
5. 只在必要时再做深度反编译
## 五、标准算法与自定义编码的分界
很多复杂题不是“整题都是自定义算法”,而是:
```text
标准参数归一化
-> 中间 payload
-> 自定义转序/位运算/编码
-> 标准 hash 或再次包装
```
优先把这 4 段拆开,不要整段一起抄。
## 六、固定不稳定输入
纯算落地前,优先固定这些值:
- `Date.now()`
- `Math.random()`
- `crypto.getRandomValues`
- cookie 中的动态 token
- `navigator.userAgent`
- challenge 初始化对象
如果不先固定这些输入,经常会出现“长度对、值不对”。
## 七、最小落地结果
完成一题后,至少沉淀这些内容:
1. `build_input(...)`
2. `build_raw_string(...)` 或 `build_payload(...)`
3. `sign(...)` / `encrypt(...)`
4. 一个浏览器对齐样本
5. 一个本地校验样本

View File

@@ -0,0 +1,222 @@
# 路由图
## 适用目的
在开始逆向之前,用这份文档快速判断题型、阻塞点和优先路线。
## 一、先做题型判断
把目标先放进下面 6 类之一:
### 1. 标准签名题
特征:
- 输出长度规整
- 常见 `md5/sha1/hmac`
- 原始串可以明确恢复
- 目标通常是 `sign/header/query`
典型问题:
- 原始串拼接顺序不对
- token / cookie 漏喂
- JSON 序列化格式和浏览器不一致
### 2. 混合加密题
特征:
- 同时存在对称加密和非对称包装
- 常见 `params + encSecKey`
- 目标字段可能不止一个
典型问题:
- 把业务密文和密钥包装混在一起看
- 只抄最终值,不拆中间明文
### 3. JSVMP / VMP 题
特征:
- 大数组
- `for(;;) + switch`
- 寄存器或状态机
- 位运算和分段构造很多
典型问题:
- 从文件头开始硬读
- 没有采中间数组
- 把静态噪音和运行时逻辑混在一起
### 4. Wasm / 协议题
特征:
- `WebAssembly.instantiate`
- protobuf / WebSocket / 二进制帧
- 校验逻辑不完全在 JS 明文层
典型问题:
- 没先证明输入输出边界
- 还没数清包段就开始反编译
### 5. Cookie / Header 题
特征:
- 最终结果写进 `document.cookie`
- 或写进 header / request options
- 常伴随会话态、UA、时间戳
典型问题:
- 没区分初始化值和业务值
- 只看最终值,不看 writer 上游
### 6. 验证码题
特征:
- 至少两段请求
- 同时存在图片线、参数线、环境线
- 常见 `collect/w/fs/pow_answer/Signature`
典型问题:
- 图像线和参数线混写
- 没拆 challenge 和 verify
- 只关注 sign,不关注协议顺序
## 二、再判断当前阻塞点
### A. 入口没找对
信号:
- 代码看了很多,还是说不清 writer 是谁
- 本地报错位置很外层
- 明显抄的是 wrapper,不是 builder
优先动作:
1. 回到最终请求或最终写出点
2. 重做 `writer <- builder <- entry <- source`
3. 暂停进一步补环境
### B. 原始串没对齐
信号:
- 最终长度对,但值不对
- 浏览器和本地的 hash 输入不同
- JSON / query / header 顺序对不上
优先动作:
1. 打印原始串
2. 固定时间戳和随机数
3. 检查 token、cookie、UA、storage
### C. 中间态没采到
信号:
- JSVMP 题完全看不清状态变化
- 只知道最终输出,不知道怎么构造
- AST 做完后仍然没法下手
优先动作:
1. 对数组写入点插桩
2. 对关键 builder 做输入输出 hook
3. 用 logpoint 替代高频断点
### D. 运行时依赖没补齐
信号:
- 报 `window/document/navigator` 未定义
- 本地和浏览器中间态差异明显
- 目标字段显著依赖 `cookie/storage/ua/fingerprint`
优先动作:
1. 收缩到最小入口
2. 记录真实访问属性
3. 只补进入 builder 所需的对象
## 三、推荐工作流
### 标准签名 / 混合加密
```text
抓最终请求
-> 找最后赋值点
-> 还原原始串或原始对象
-> 判断标准算法或加密层次
-> 本地复现
```
### JSVMP / VMP
```text
找最终输出
-> 找中间数组/中间对象
-> 插桩
-> 先恢复中间明文结构
-> 再恢复最终编码
```
### Wasm / 协议
```text
识别边界
-> 找导出函数或包段
-> 验证输入输出
-> 再决定是否反编译或移植
```
### 验证码
```text
拆 challenge / verify
-> 分离图像线、参数线、环境线
-> 锁定最终 verify builder
-> 对齐中间态
-> 再做 solver 落地
```
## 四、常用标签
后续整理案例时,优先使用下面这组标签,避免只按站点名归档:
- `header-sign`
- `cookie-sign`
- `response-decrypt`
- `captcha`
- `vmp`
- `jsvmp`
- `wasm`
- `protobuf`
- `websocket`
- `env`
- `fingerprint`
- `ast`
- `solver`
- `service`
## 五、结论
稳定的路线不是“先读大文件”,而是:
```text
题型判断
-> 最终写出点
-> builder
-> 中间检查点
-> 最小本地复现
```

View File

@@ -0,0 +1,370 @@
#!/usr/bin/env python3
"""Create a structured case scaffold for Web reverse pure-calc research."""
from __future__ import annotations
import argparse
import json
import re
from pathlib import Path
CASE_TYPES = {
"sign": {
"title": "标准签名 / Header 纯算",
"goal": "从最终请求倒推 builder,恢复原始串并本地复现。",
"fields": ["url", "method", "target_field", "raw_string", "token_sources"],
"risks": [
"重点核对 query/json/path 的规范化方式。",
"固定时间戳、token、cookie、UA 后再比最终值。",
"不要把标准算法问题误判成环境问题。",
],
},
"mixed": {
"title": "混合加密 / 密钥包装",
"goal": "分离业务明文、对称层、非对称包装层,再本地复现。",
"fields": ["url", "method", "target_fields", "plaintext", "encrypted_layers"],
"risks": [
"不要把业务密文和密钥包装混成一个 sign。",
"分别保存每层输入输出,不只比较最终值。",
"优先确认 key/iv/public key 的真实来源。",
],
},
"cookie": {
"title": "Cookie / 会话值纯算",
"goal": "从 document.cookie 写入点回溯 builder 与环境采集链。",
"fields": ["writer", "target_cookie", "upstream_sources", "raw_payload", "final_cookie"],
"risks": [
"区分初始化 cookie 和业务 cookie。",
"优先 hook sink,不要只盯网络请求。",
"先证明哪些环境值是真校验项。",
],
},
"jsvmp": {
"title": "JSVMP / VMP 纯算",
"goal": "从最终 writer 倒推中间数组或 payload,再恢复最终编码层。",
"fields": ["url", "method", "target_field", "entry", "builder", "state_objects"],
"risks": [
"不要从文件头正推整个 VM。",
"先做低风险 AST 降噪,再做 hook / logpoint。",
"中间数组和随机数/时间戳检查点要先固定。",
],
},
"captcha": {
"title": "验证码 / Challenge / Verify",
"goal": "拆 challenge、图像、参数、环境、verify 五条线,并收敛成 solver。",
"fields": ["init_url", "image_url", "verify_url", "target_fields", "recognition_result"],
"risks": [
"不要把图像线和参数线混写。",
"先确认真正失败的是 verify 哪个字段。",
"collect、w、fs、pow_answer 一类字段要单独建检查点。",
],
},
"wasm": {
"title": "Wasm / 协议纯算",
"goal": "先证明输入输出边界,再决定是否反编译或直接改写。",
"fields": ["loader", "exported_functions", "target_field", "protocol_frames", "io_samples"],
"risks": [
"先看导出函数和包段,不要一上来全量反编译。",
"协议题先数包,再拆首包和验证包。",
"保留 Wasm / protobuf / WS 的输入输出样本。",
],
},
}
FAMILY_HINTS = {
"generic": ["按题型模板拆 writer / builder / entry / source。"],
"xhs": ["重点记录 window._webmsxyw、x1/x2/x3/x4、payload、X-S-Common。"],
"douyin": ["重点记录双 SM3、41/50/96/128/136 位数组、最终编码层。"],
"tencent": ["重点记录 prehandle、pow_answer、pow_calc_time、collect、track、verify。"],
"geetest": ["区分三代和四代,分别记录 h/u 或 captcha_id/challenge/load 对象。"],
"netease-shield": ["重点记录 validateCodeObj、userAnswer、P1~P9、w。"],
"taobao": ["重点记录 token、t、appKey、紧凑 JSON data。"],
"youdao": ["同时记录请求 sign 与响应 AES-CBC 解密链。"],
"baidu": ["区分 token、固定 seed 与 sign 函数。"],
"cloudflare": ["拆 challenge 阶段、fingerprint 层、计算层。"],
}
OVERVIEW_TEMPLATE = """# {title}
## 案例目标
- 案例名:`{case_name}`
- 题型:`{case_type}`
- 站点家族:`{family}`
- 目标:{goal}
- 目标字段:
- 最终成功条件:
## 入口判断
- 最终请求 / 最终 sink:
- writer:
- builder:
- entry:
- source:
## 当前阻塞点
- 入口没找对 / 原始串没对齐 / 中间态没采到 / 环境没补齐 / 图像线没拆开 / 协议边界没证明:
## 家族提示
{family_lines}
## 风险点
{risk_lines}
"""
REQUEST_CHAIN_TEMPLATE = """# 请求链
## 闭环
```text
source
-> entry
-> builder
-> writer
-> final output
```
## 请求或写出顺序
1. 初始化 / 页面态:
2. 中间参数生成:
3. 最终请求 / verify / cookie / WS:
## 目标字段
- 字段名:
- 位置:header / body / cookie / payload / ws
- 当前样本值:
## 必要输入集合
- token / cookie:
- 时间戳 / 随机数:
- 页面态参数 / load 返回对象:
- 图像识别结果 / 轨迹:
- 环境值 / 指纹值:
"""
EVIDENCE_TEMPLATE = """# 证据日志
## 浏览器检查点
1. writer 检查点:
2. builder 输入:
3. 原始串 / payload:
4. 中间数组 / 中间对象:
5. 最终输出:
## 本地检查点
1. writer 检查点:
2. builder 输入:
3. 原始串 / payload:
4. 中间数组 / 中间对象:
5. 最终输出:
## 差异定位
- 从哪一步开始分叉:
- 猜测原因:
- 下一步验证:
"""
TODO_TEMPLATE = """# TODO
- [ ] 抓成功样本并保存最终请求或最终 sink
- [ ] 标出 writer / builder / entry / source
- [ ] 固定时间戳、随机数、cookie、token 等不稳定输入
- [ ] 保存浏览器端检查点
- [ ] 保存本地端检查点
- [ ] 比对差异并收敛到最小可复现函数
- [ ] 记录易错点和版本风险
"""
SOLVER_JS = """// {title}
// 最小本地复现骨架。建议把 context、payload、crypto/vm、validate 分层。
function buildContext() {{
return {{
source: {{}},
unstableInputs: {{}},
}};
}}
function buildPayload(ctx) {{
return {{
ctx,
raw: null,
intermediate: [],
}};
}}
function solve(ctx = buildContext()) {{
const payload = buildPayload(ctx);
return {{
ctx,
payload,
finalOutput: null,
checkpoints: {{
writer: null,
builderInput: null,
raw: null,
intermediate: [],
final: null,
}},
}};
}}
module.exports = {{
buildContext,
buildPayload,
solve,
}};
"""
SOLVER_PY = """# {title}
# 最小本地复现骨架。建议把 context、payload、crypto/vm、validate 分层。
def build_context():
return {{
"source": {{}},
"unstable_inputs": {{}},
}}
def build_payload(ctx):
return {{
"ctx": ctx,
"raw": None,
"intermediate": [],
}}
def solve(ctx=None):
if ctx is None:
ctx = build_context()
payload = build_payload(ctx)
return {{
"ctx": ctx,
"payload": payload,
"final_output": None,
"checkpoints": {{
"writer": None,
"builder_input": None,
"raw": None,
"intermediate": [],
"final": None,
}},
}}
"""
def slugify(value: str) -> str:
value = value.strip().lower()
value = re.sub(r"[^a-z0-9\u4e00-\u9fff._-]+", "-", value)
value = re.sub(r"-{2,}", "-", value).strip("-")
return value or "case"
def parse_csv(text: str) -> list[str]:
if not text:
return []
return [item.strip() for item in text.split(",") if item.strip()]
def checkpoints_for(case_type: str) -> dict:
return {
"meta": {
"case_type": case_type,
"target_fields": [],
},
"browser": {
"writer": None,
"builder_input": None,
"raw": None,
"intermediate": [],
"final": None,
},
"local": {
"writer": None,
"builder_input": None,
"raw": None,
"intermediate": [],
"final": None,
},
"field_hints": CASE_TYPES[case_type]["fields"],
}
def main() -> int:
parser = argparse.ArgumentParser(description="Create a structured case scaffold for Web reverse pure-calc tasks.")
parser.add_argument("case_name", help="Case name shown in generated files.")
parser.add_argument("--type", choices=sorted(CASE_TYPES), required=True, help="Case type.")
parser.add_argument("--family", default="generic", help="Site family such as xhs, douyin, tencent, geetest.")
parser.add_argument("--tags", default="", help="Comma-separated tags.")
parser.add_argument("--sources", default="", help="Comma-separated source URLs.")
parser.add_argument("--language", choices=["js", "py"], default="js", help="Solver stub language.")
parser.add_argument("--output", required=True, help="Directory where the case folder will be created.")
args = parser.parse_args()
case_slug = slugify(args.case_name)
base_dir = Path(args.output).expanduser().resolve() / case_slug
base_dir.mkdir(parents=True, exist_ok=True)
case_type = CASE_TYPES[args.type]
family_hints = FAMILY_HINTS.get(args.family, FAMILY_HINTS["generic"])
family_lines = "\n".join(f"- {line}" for line in family_hints)
risk_lines = "\n".join(f"- {line}" for line in case_type["risks"])
metadata = {
"case_name": args.case_name,
"case_slug": case_slug,
"case_type": args.type,
"family": args.family,
"tags": parse_csv(args.tags),
"sources": parse_csv(args.sources),
"solver_language": args.language,
}
(base_dir / "case-overview.md").write_text(
OVERVIEW_TEMPLATE.format(
title=case_type["title"],
case_name=args.case_name,
case_type=args.type,
family=args.family,
goal=case_type["goal"],
family_lines=family_lines,
risk_lines=risk_lines,
),
encoding="utf-8",
)
(base_dir / "request-chain.md").write_text(REQUEST_CHAIN_TEMPLATE, encoding="utf-8")
(base_dir / "evidence-log.md").write_text(EVIDENCE_TEMPLATE, encoding="utf-8")
(base_dir / "todo.md").write_text(TODO_TEMPLATE, encoding="utf-8")
(base_dir / "metadata.json").write_text(
json.dumps(metadata, ensure_ascii=False, indent=2) + "\n",
encoding="utf-8",
)
(base_dir / "checkpoints.json").write_text(
json.dumps(checkpoints_for(args.type), ensure_ascii=False, indent=2) + "\n",
encoding="utf-8",
)
solver_name = f"solver_stub.{args.language}"
solver_content = SOLVER_JS if args.language == "js" else SOLVER_PY
(base_dir / solver_name).write_text(solver_content.format(title=case_type["title"]), encoding="utf-8")
print(f"[OK] Created scaffold: {base_dir}")
print("[OK] Files: case-overview.md, request-chain.md, evidence-log.md, checkpoints.json, metadata.json, todo.md")
print(f"[OK] Solver stub: {solver_name}")
return 0
if __name__ == "__main__":
raise SystemExit(main())