reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -0,0 +1,351 @@
|
||||
# Node.js 补环境调试循环
|
||||
|
||||
当前置阶段已经完成,并且用户确认进入补环境阶段时读取本文件。
|
||||
|
||||
## 目标
|
||||
|
||||
补环境阶段不是为了让目标 JS “勉强不报错”,而是为了让目标网页原始 JS 在 Node.js 中生成与浏览器样本一致的结果。
|
||||
|
||||
核心原则:
|
||||
|
||||
```text
|
||||
先记录,后补齐;先最小,后扩展;真实性保护和 addon-first 从第一版 env 骨架开始;先样本验证,后交付。
|
||||
```
|
||||
|
||||
对 Canvas / WebGL / WebGPU / Audio / 字体 / DOM 几何等浏览器指纹,额外遵循:
|
||||
|
||||
```text
|
||||
先采真实浏览器终端 API 返回值,再在 Node.js 中回放;不要强行复刻渲染管线,不要把最终流程改成自动化浏览器。
|
||||
```
|
||||
|
||||
真实性与 addon-first 额外遵循:
|
||||
|
||||
```text
|
||||
先加载 / 记录 addon,再编写 env;toString、属性描述符、访问器、原型链和实例对象保护是默认基线,不等待检测触发。
|
||||
```
|
||||
|
||||
如果本 case 的取证模式是 ruyiPage + RuyiTrace,或用户明确说“已经 trace 好日志 / 已提供 NDJSON”,补环境阶段再增加一条硬规则:
|
||||
|
||||
```text
|
||||
先看 RuyiTrace NDJSON,再跑 Node trace;先用浏览器内核日志定位环境依赖,再用 Node.js 复现和固化。
|
||||
```
|
||||
|
||||
## 进入条件
|
||||
|
||||
进入本阶段前必须确认:
|
||||
|
||||
- 目标属于网页端 JS。
|
||||
- 已有目标 API、请求方法、加密参数名和参数位置。
|
||||
- 至少有一份成功请求样本,最好有多组样本。
|
||||
- 已经定位或初步定位加密入口。
|
||||
- 相关 JS 文件已经保存到本地,或确认可以获取。
|
||||
- 已经整理 `source → entry → builder → writer` 四层链路,至少确认 writer。
|
||||
- 如用户选择 ruyiPage + RuyiTrace,已导入 NDJSON 日志并生成 `notes/ruyitrace-summary.md`;如果尚未导入,应先暂停要求用户提供或采集日志,除非用户明确确认无法提供。
|
||||
- 已经检查 Node 泄露阻断,不把 `process/Buffer/require/module/global` 暴露给目标 JS。
|
||||
- 已经在补环境初始化阶段加载 / 检测 addon,并决定 addon-first 或记录用户明确豁免 / addon 不可用降级原因。
|
||||
- 用户未明确要求关闭真实性保护;默认会对新增 WebAPI 执行属性描述符、访问器、原型链、函数 / 访问器 / 实例对象 toString 保护。
|
||||
- 已经执行六项纯计算预检,或明确该目标不依赖相关差异。
|
||||
- 如果目标访问 Canvas / WebGL / WebGPU / Audio / 字体 / DOM 几何等指纹 API,已经采集或计划采集真实浏览器终端 API 返回值;缺少样本时不得进入“静默伪造默认值”的交付模式。
|
||||
- 如果目标是验证码接口,已确认事件轨迹 fixture 或旧轨迹样本来源,并明确该轨迹只用于补环境生成加密参数,不代表最终验证码验证成功。
|
||||
- 用户已确认进入 Node.js 补环境阶段。
|
||||
|
||||
如果缺少任一关键条件,先回到 `workflow.md` 的前置流程,不要直接写 `env.js`。
|
||||
|
||||
## 验证码事件轨迹 fixture 门禁
|
||||
|
||||
验证码接口补环境时,如果加密参数依赖鼠标、点击、拖动、触摸、滚轮或键盘事件,先使用浏览器取证得到的旧轨迹 fixture 跑通参数生成。该阶段目标是让目标 JS 在 Node.js 中生成加密参数,不要求验证码最终验证通过。
|
||||
|
||||
硬性要求:
|
||||
|
||||
- 将轨迹设计为可替换入口,例如 `motionTrack`、`eventFixture`、`verifyContext`、`clickPoints`、`dragPath`。
|
||||
- 推荐保存到 `case/fixtures/motion.fixture.json` 或 `case/result/src/verify/motion-track.js`。
|
||||
- 代码中必须有 UTF-8 中文注释,说明旧轨迹来源、用途和后续由 `web-verify-patcher` 替换。
|
||||
- 不得把旧轨迹硬编码成不可替换逻辑,不得宣称旧轨迹能稳定通过验证码。
|
||||
- 生成验证码加密参数后,如需识别图片、生成真实轨迹、坐标换算或提交验证,先运行 `scripts/check_web_verify_patcher.js --require --markdown`,确认 `web-verify-patcher` 可用后再交接。
|
||||
|
||||
## RuyiTrace 优先诊断门禁
|
||||
|
||||
当取证模式为 ruyiPage + RuyiTrace 时,进入任何 `env.js` 编写、缺失对象补齐或环境问题排查前,先执行以下门禁:
|
||||
|
||||
1. 确认 `case/ruyi-trace/logs/*.ndjson` 或用户指定 NDJSON 存在。
|
||||
2. 如果尚未导入,先执行:
|
||||
|
||||
```bash
|
||||
node scripts/import_ruyitrace_log.js --input <trace.ndjson> --case-dir case --markdown
|
||||
```
|
||||
|
||||
3. 先阅读 `case/notes/ruyitrace-summary.md`,再按需过滤原始 NDJSON。
|
||||
4. 针对当前错误或不一致,优先搜索:
|
||||
- 缺失对象名:如 `navigator`、`document`、`screen`、`localStorage`。
|
||||
- 缺失方法名:如 `getItem`、`getContext`、`getParameter`、`toDataURL`。
|
||||
- 目标 JS 文件名、入口函数名、writer 附近调用栈。
|
||||
- 与目标请求发起时间邻近的 `api` 调用。
|
||||
5. 把命中证据写入 `notes/missing-env-priority.md`,至少包含 `api`、`stack.file`、`line`、`col`、所属环境模块、补齐优先级和“RuyiTrace 证据 / Node trace 补充 / 推断”分类,再决定 Level 1/2/3 补齐顺序。
|
||||
6. 只有 NDJSON 缺失、未覆盖该逻辑或结论不足时,才把 `run_with_trace.js` / Proxy trace 作为主要发现来源。
|
||||
|
||||
不要在已有可用 RuyiTrace 日志时,直接根据 Node.js 报错盲目补环境。
|
||||
|
||||
## 推荐 case 目录
|
||||
|
||||
```text
|
||||
case/
|
||||
├── js/
|
||||
│ ├── original/
|
||||
│ ├── pretty/
|
||||
│ └── extracted/
|
||||
├── requests/
|
||||
├── fixtures/
|
||||
├── notes/
|
||||
├── hooks/
|
||||
├── env/
|
||||
├── ruyi-trace/
|
||||
│ └── logs/
|
||||
├── browser/
|
||||
│ └── ruyipage/
|
||||
├── result/
|
||||
└── tmp/
|
||||
```
|
||||
|
||||
使用脚本创建:
|
||||
|
||||
```bash
|
||||
node scripts/init_env_case.js --case-dir case --target app.js --entry window.makeSign --param sign --api https://example.com/api/search
|
||||
```
|
||||
|
||||
目录含义:
|
||||
|
||||
| 目录 | 用途 |
|
||||
|---|---|
|
||||
| `js/original/` | 原始 JS、chunk、runtime、sourcemap |
|
||||
| `js/pretty/` | 格式化后的 JS |
|
||||
| `js/extracted/` | 抽取出的入口模块或片段 |
|
||||
| `requests/` | 脱敏后的 cURL、HAR、请求说明 |
|
||||
| `fixtures/` | 浏览器真实样本和期望输出 |
|
||||
| `notes/` | 分析笔记、入口定位、环境依赖说明 |
|
||||
| `hooks/` | 浏览器 Hook 模板和临时断点脚本;调用栈确认并写入 notes 后立即清理或归档 |
|
||||
| `env/` | 分层 env 模块草稿 |
|
||||
| `ruyi-trace/logs/` | 用户确认导入的 RuyiTrace NDJSON 原始日志 |
|
||||
| `browser/ruyipage/` | ruyiPage 取证配置、非敏感脚本和用户确认保留的材料 |
|
||||
| `result/` | 最终规范项目目录;唯一执行入口为 `final.js` 或 `final.py`,必要模块可放入 `src/`;不要放临时 runner、测试脚本或浏览器自动化代码 |
|
||||
| `tmp/` | trace、临时 runner、日志、失败产物;每次测试或阶段完成后立即清理 |
|
||||
|
||||
## 双模式策略
|
||||
|
||||
### 探测模式
|
||||
|
||||
探测模式用于发现目标 JS 实际访问了哪些浏览器环境。
|
||||
|
||||
允许使用:
|
||||
|
||||
- JS `Proxy`。
|
||||
- getter / setter hook。
|
||||
- 函数调用记录。
|
||||
- 构造调用记录。
|
||||
- trace 文件。
|
||||
|
||||
运行示例:
|
||||
|
||||
```bash
|
||||
node scripts/run_with_trace.js \
|
||||
--target case/js/original/app.js \
|
||||
--entry window.makeSign \
|
||||
--fixture case/fixtures/sample.fixture.json \
|
||||
--trace case/tmp/env-trace.jsonl \
|
||||
--summary case/tmp/missing-env.json
|
||||
```
|
||||
|
||||
探测模式允许对象“不完全像浏览器”,但必须明确标记其用途只是调试,不要把全量 Proxy 作为最终交付。
|
||||
|
||||
### 交付模式
|
||||
|
||||
交付模式用于最终稳定运行。
|
||||
|
||||
要求:
|
||||
|
||||
- 从第一版可交付 env 开始就启用真实性保护,不等检测命中后再补。
|
||||
- 进入本模式前已经加载 / 记录 addon;addon 可用时所有 native-like 函数、getter、setter、特殊对象和原型链 helper 都必须 addon-first。
|
||||
- 尽量不用全局 Proxy。
|
||||
- 将 trace 中发现的访问路径固化为真实对象结构。
|
||||
- 显式定义属性描述符。
|
||||
- 建立必要原型链。
|
||||
- 对构造函数、普通方法、getter、setter 做 native-like `toString` 保护;访问器函数也必须保护。
|
||||
- 对实例对象设置正确 `Object.prototype.toString` / `Symbol.toStringTag`,并对 `document.all` 等特殊对象优先使用可选 native addon。
|
||||
- 不输出调试 trace。
|
||||
- 用 fixtures 验证输出。
|
||||
|
||||
## 分层补齐策略
|
||||
|
||||
补齐顺序固定为:
|
||||
|
||||
1. **Level 1 基础运行层**:window/self/globalThis、location、URLSearchParams、Storage、Date、crypto、console、定时器。
|
||||
2. **Level 2 指纹与真实性层**:navigator、screen、document、plugins/mimeTypes、Canvas / WebGL / WebGPU / Audio / 字体 / DOM 几何终端 API 值回放、属性描述符、原型链、native-like toString。
|
||||
3. **Level 3 目标 SDK 专用层**:SDK init、动态 chunk、Worker、WASM、postMessage、站点私有缓存。
|
||||
|
||||
模块选择细节见 `env-module-levels.md`。输出不一致时先读取 `node-leakage-and-silent-failure.md`,不要盲目继续补对象。
|
||||
|
||||
## 运行顺序
|
||||
|
||||
```text
|
||||
1. 创建 case 目录和 fixtures。
|
||||
2. 如果取证模式为 ruyiPage + RuyiTrace,先导入 / 阅读 NDJSON 摘要,形成环境依赖优先级。
|
||||
3. 执行 Node 泄露阻断检查和六项纯计算预检。
|
||||
4. 运行 native addon 优先门禁:加载 / 检测随包 addon;可用时后续 native-like 函数、访问器、`document.all`、原型链等先走 addon,失败时记录降级状态。
|
||||
5. 用最小浏览器环境运行目标 JS。
|
||||
6. 捕获 ReferenceError / TypeError / 输出不一致。
|
||||
7. 如已选择 RuyiTrace,先用 NDJSON 证据解释缺失路径;解释不足时再用 Proxy 记录实际访问路径。
|
||||
8. 生成缺失环境报告,并用 `analyze_trace.js` 输出模块优先级。
|
||||
9. 如果 trace 或 NDJSON 显示 Canvas / WebGL / WebGPU / Audio / 字体 / DOM 几何指纹,先读取 `fingerprint-value-replay.md`,生成采样 Hook,采集 `fixtures/fingerprint.fixture.json`,再接入 `assets/env-modules/fingerprint-env.js` 做终端 API 值回放。
|
||||
10. 按 RuyiTrace 证据 + Node trace 补充结论,分 Level 1/2/3 补齐环境。
|
||||
11. 发现 Proxy、toString、descriptor、accessor、prototype、instanceof、constructor.name 或 `document.all` 检测信号时,迁移到真实对象 / addon-first 模式;addon 不可用时才使用 NativeProtect fallback。
|
||||
12. 如果是验证码接口,先注入可替换的 `motionTrack` / `eventFixture` 旧轨迹 fixture,仅用于生成验证码接口加密参数。
|
||||
13. 调用加密入口。
|
||||
14. 和浏览器样本对比;如果缺少指纹样本,补采样而不是改用自动化浏览器。
|
||||
15. 多样本通过后整理规范项目目录,把补环境、入口调用、参数生成和最终 Node.js / Python 请求逻辑串联到唯一入口 `result/final.js` 或 `result/final.py`;必要模块可放入 `result/src/`。
|
||||
16. 先运行 `check_env_realism.js --require-addon-first`,确认原型链、属性描述符、访问器、toString 保护、实例对象 toString 保护、addon-first/native fallback 记录、document.all、RuyiTrace 证据和指纹值回放证据;再运行 `check_fingerprint_fixture.js` 与 `check_final_artifact.js`,确认最终主文件不含 ruyiPage / Playwright / Puppeteer / Selenium / CloakBrowser 等自动化代码。
|
||||
17. 清理 trace、临时日志、失败 runner、测试脚本、指纹采样 Hook 和多余文件。
|
||||
```
|
||||
|
||||
## 错误分类
|
||||
|
||||
### ReferenceError
|
||||
|
||||
示例:
|
||||
|
||||
```text
|
||||
ReferenceError: XMLHttpRequest is not defined
|
||||
```
|
||||
|
||||
记录为:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "missing-global",
|
||||
"name": "XMLHttpRequest"
|
||||
}
|
||||
```
|
||||
|
||||
处理:如果选择 ruyiPage + RuyiTrace,先在 NDJSON 中确认浏览器真实调用栈、构造方式和相关属性,再补全 `globalThis.XMLHttpRequest`,必要时建立构造函数和原型。
|
||||
|
||||
### TypeError:不是函数
|
||||
|
||||
示例:
|
||||
|
||||
```text
|
||||
TypeError: localStorage.getItem is not a function
|
||||
```
|
||||
|
||||
记录为:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "missing-method",
|
||||
"path": "localStorage.getItem"
|
||||
}
|
||||
```
|
||||
|
||||
处理:如果选择 ruyiPage + RuyiTrace,先在 NDJSON 中确认该方法真实是否被调用、调用参数和调用栈,再补全对应方法。若 addon 可用,优先创建 native-like 函数。
|
||||
|
||||
### TypeError:读取 undefined 属性
|
||||
|
||||
示例:
|
||||
|
||||
```text
|
||||
Cannot read properties of undefined (reading 'userAgent')
|
||||
```
|
||||
|
||||
处理:优先结合 RuyiTrace NDJSON 判断浏览器真实路径;NDJSON 不足时再结合 Node trace,补齐缺失对象或属性。
|
||||
|
||||
### 输出不一致
|
||||
|
||||
如果不再报错但签名不一致,且已选择 ruyiPage + RuyiTrace,先回看目标请求前后的 NDJSON 调用,再检查:
|
||||
|
||||
- 请求 URL、Query、Body 是否完全一致。
|
||||
- `Date.now`、`performance.now`。
|
||||
- `Math.random`、`crypto.getRandomValues`。
|
||||
- `navigator.userAgent`、语言、时区、屏幕信息。
|
||||
- `document.cookie`、`localStorage`、`sessionStorage`。
|
||||
- `location.href`、`origin`、`pathname`。
|
||||
- 是否启用 native-like `toString`。
|
||||
- `document.all` 是否走了 native addon 路径。
|
||||
- `Object.getOwnPropertyDescriptor` 返回的 descriptor 是否与真实浏览器一致。
|
||||
- getter / setter / 构造函数 / 原型方法的 `Function.prototype.toString.call(...)` 是否为 native-like。
|
||||
- 实例对象的 `Object.prototype.toString.call(...)`、`constructor.name`、`instanceof` 是否一致。
|
||||
|
||||
如果 NDJSON 中没有覆盖目标参数生成时间段,明确标记“RuyiTrace 未覆盖”,再使用 Node trace / Hook / 断点补充。
|
||||
|
||||
## trace 输出
|
||||
|
||||
推荐临时文件:
|
||||
|
||||
```text
|
||||
case/tmp/
|
||||
├── env-trace.jsonl
|
||||
├── missing-env.json
|
||||
├── runtime-error.log
|
||||
└── env-access-summary.md
|
||||
```
|
||||
|
||||
`env-trace.jsonl` 示例:
|
||||
|
||||
```json
|
||||
{"type":"get","path":"navigator.userAgent"}
|
||||
{"type":"get","path":"document.cookie"}
|
||||
{"type":"call","path":"localStorage.getItem","args":["string"]}
|
||||
```
|
||||
|
||||
`missing-env.json` 示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"missingGlobals": ["XMLHttpRequest"],
|
||||
"missingMethods": ["localStorage.getItem"],
|
||||
"missingProperties": ["navigator.userAgent", "document.cookie"],
|
||||
"specialObjects": ["document.all"],
|
||||
"nativeAddon": {
|
||||
"available": true,
|
||||
"usedApis": ["createUndetectable", "createNativeFunction", "createGetter"]
|
||||
},
|
||||
"proxyRiskSignals": ["Object.getOwnPropertyDescriptor", "Function.prototype.toString"],
|
||||
"runtimeErrors": []
|
||||
}
|
||||
```
|
||||
|
||||
## 输出要求
|
||||
|
||||
阶段输出应包含:
|
||||
|
||||
```markdown
|
||||
## Node.js 补环境运行结果
|
||||
|
||||
- 目标 JS:
|
||||
- 入口函数:
|
||||
- fixtures:
|
||||
- native addon:可用 / 不可用 / 用户明确豁免;必须说明是否在补环境初始化阶段已加载 / 记录
|
||||
- 真实性检查:已运行 `check_env_realism.js`(默认 addon-first)/ 未运行(需说明原因)
|
||||
- RuyiTrace NDJSON:已优先分析 / 未提供 / 未覆盖当前问题
|
||||
- 运行状态:成功 / 失败
|
||||
|
||||
## 缺失环境摘要
|
||||
|
||||
- RuyiTrace 证据:api、stack.file、line、col、相关时间窗口
|
||||
- 缺失全局对象:
|
||||
- 缺失方法:
|
||||
- 缺失属性:
|
||||
- 特殊对象:
|
||||
- Proxy 检测风险:
|
||||
|
||||
## 下一轮补齐计划
|
||||
|
||||
1. ...
|
||||
2. ...
|
||||
|
||||
## 清理检查
|
||||
|
||||
- [ ] 已清理临时 trace。
|
||||
- [ ] 已清理失败 runner。
|
||||
- [ ] 已把关键结论写入 notes。
|
||||
- [ ] 已生成规范项目目录,且唯一执行入口为 `result/final.js` 或 `result/final.py`。
|
||||
- [ ] 已确认最终项目所有源码不包含浏览器自动化代码。
|
||||
- [ ] 已确认最终请求由 Node.js / Python HTTP 客户端实现。
|
||||
- [ ] 已生成 `result/最终项目总结.md`,除非用户明确要求不生成。
|
||||
```
|
||||
Reference in New Issue
Block a user