市面上最全的瑞数 (Rivers Security) 动态安全防护突破方案合集。不仅包含 Cookie T 纯算生成、URL 后缀 AST 深度逆向、JsRpc 通杀、sdenv 补环境四种实战方案, 还从真实逆向经验中蒸馏出一份可复制的顶级 Agent Skill — 让任何 AI Agent 读完即可独立完成瑞数逆向。
瑞数于 2026-04-07 进行了服务端改版, 导致纯算方案返回 412。已修复。
瑞数服务端更新了 basearr 中的 type=2 环境检测值, 这是导致 412 的唯一原因:
| 参数 | 旧值 (v1.0) | 新值 (v2.0) |
|---|---|---|
| type=2 检测值 | [103, 101, 224, 181] |
[225, 203, 100, 181] |
| cp1 索引映射 | {11:103, 5:101, 23:224, 8:181} |
{22:225, 21:203, 30:100, 3:181} |
纯靠数据对比定位, 过程:
1. sdenv 采集真实 basearr — 跑 3 组配套数据 (同一 session 中采集 nsd + cd + Cookie T + 解密出 basearr)
2. 逐字节对比 — 把真实 basearr 和纯算生成的逐字节比, 立刻发现 type=2 全是 0:
type=2: ref=[225,203,100,181] gen=[0,0,0,0] ← 旧映射表查不到, 全返回 0
3. 顺带发现 UA/Platform 也不一致 — type=3 中的 CRC32(UA) 和 platform 字段:
ref UA CRC: 0x9fad00ee ← CRC32(Mac UA) 匹配
gen UA CRC: 0x11469713 ← CRC32(Win UA)
ref platform: "MacIntel" ← sdenv 的 jsdom 默认值
gen platform: "Win32" ← 我们写的
本质是 sdenv 的 jsdom 环境中 navigator.platform 默认为 "MacIntel", VM 收集到的指纹就是 Mac 的。
4. 验证 UA 是否必须改 — 测试了 4 种 UA 组合 (Mac/Win basearr × Mac/Win HTTP), 全部 200。结论: 服务端不校验 UA CRC32, type=2 才是唯一失效原因。UA/Platform 改为 Mac 只是为了与 sdenv 真实数据对齐。
没有猜, 全是数据对出来的 — 这就是
agentskill/SKILL.md中的「数据驱动方法论」。
| 文件 | 改了什么 | 是否必须 |
|---|---|---|
reverse/scripts/basearr.js |
buildType2() 中的 indexToValue 映射表 |
必须 — 这是 412 的唯一原因 |
reverse/scripts/run.js |
UA 字符串 + platform 参数 |
可选 — 与 sdenv 真实数据对齐 |
reverse/scripts/client.js |
UA 字符串 + platform 默认值 |
可选 — 与 sdenv 真实数据对齐 |
纯算不是一劳永逸的。 type=2 的环境检测值是服务端动态配置的, 瑞数可以随时更新。下次失效时, 用同样的方法修复:
- 用 sdenv 采集 3 组真实数据 (在同一 session 中配套采集 nsd + cd + Cookie T)
- 用纯算解密 Cookie T → 提取真实 basearr
- 和纯算生成的 basearr 逐字节对比, 找到哪些字段变了
- 更新
basearr.js中的对应值
完整方法论见 agentskill/SKILL.md 中的「方法论」章节。参考采集脚本见 agentskill/scripts/collect_session.js。
| 方案 | 稳定性 | 效率 | 适用场景 |
|---|---|---|---|
| JsRpc | 高 (不受改版影响) | 中 (需要浏览器实例) | 生产环境首选, 通杀所有瑞数站点 |
| sdenv | 高 (跟随瑞数逻辑) | 中 | 不方便开浏览器时, 或 CI/CD 场景 |
| 纯算 | 低 (改版即失效) | 极高 (毫秒级) | 高频采集 + 愿意定期维护的场景 |
注意: 新一代瑞数 (如国家药监局使用的瑞数 6) 增加了更复杂的环境检测, 纯算几乎不可能完全还原, 建议直接使用 JsRpc 或 sdenv。
| 方案 | 原理 | 适用场景 | 状态 |
|---|---|---|---|
| 纯算 Cookie T | 纯 JS 实现加密链, 零浏览器依赖 | GET/POST (不需要后缀的站点, 99%) | 已完成, HTTP 200 |
| JsRpc 通杀 | WebSocket 调用浏览器中的瑞数 VM | 所有站点, 包括需要后缀的 | 已完成, 通杀验证 |
| sdenv 补环境 | 魔改 jsdom 模拟浏览器环境 | Cookie + 后缀, 单实例 | 已完成, 可用 |
| URL 后缀 AST 逆向 | AST 反编译 eval code + VM 字节码 | 深度逆向研究 | 已完成 80%, 卡在 VM 层 |
| 顶级逆向 Skill | 工程化 skill 体系: 主文档 + 7 篇参考 + 5 个脚本 + 2 个 lib | AI Agent 自动化逆向 | 已完成, 可直接复制使用 |
中国知识产权海关备案查询系统
http://202.127.48.145:8888/
该站点使用瑞数 4/5 代动态安全防护, 对所有请求进行加密 Cookie 验证。
cd reverse/scripts
node client.jsconst { RuishuPureClient } = require('./reverse/scripts/client.js');
const client = new RuishuPureClient();
await client.init();
// GET 页面
const page = await client.get('/zscq/search/jsp/vBrandSearchIndex.jsp');
// POST 查询商标
const result = await client.post(
'/searchUser/searchAction!getVRecordListPage.do',
'page=1&rows=10&sidx=RECORD_NUM&sord=desc&_search=false&nd=' + Date.now()
);
// 搜索 (支持中文)
const search = await client.post(
'/searchUser/searchAction!getVRecordListPage.do',
'page=1&rows=10&RECORD_NAME=' + encodeURIComponent('华为') + '&nd=' + Date.now()
);Cookie 过期自动刷新, 无需手动处理。
cd jsrpc && npm install
# 1. 启动服务端
node server.js
# 2. 浏览器打开目标站点 → F12 → Console → 粘贴 inject.js
# 3. 调用
node client.js # 自动测试
node client.js get /path # GET
node client.js post /api "key=value" # POST (自动带后缀)浏览器首次访问
↓
服务器返回 HTTP 412 + 混淆 JS
├── Cookie S (HttpOnly, 服务端标识)
├── <meta> 标签 (加密 content)
├── <script> $_ts = { nsd, cd, cp, aebi } (配置数据)
└── <script src="mainjs.js"> (205KB 混淆代码)
↓
mainjs 执行:
1. 解密 $_ts.cd → 提取 45 组密钥
2. 用 nsd 种子生成 918 个随机变量名
3. 动态生成 296KB eval 代码
4. eval() → 启动三层嵌套 VM
↓
VM 执行:
1. 收集浏览器指纹 (Canvas, WebGL, UA, 屏幕...)
2. 组装 basearr (154B TLV 结构)
3. basearr → Huffman → XOR → AES-CBC → CRC32 → AES-CBC → Base64
4. 写入 Cookie T = "0" + Base64 结果
5. 劫持 XHR.open (给请求加 URL 后缀)
↓
浏览器带 Cookie S + Cookie T 再次访问 → 200
Layer 1: mainjs 字节码解释器 (~100 opcodes)
└─ 解析配置, 生成 eval 代码
Layer 2: eval code 外层 VM — _$$o (741 state codes)
└─ Cookie T 生成, XHR 劫持, DOM 遍历, 事件监听
Layer 3: 内层 VM — r2mKa (114 opcodes, 407 函数, 43925B 字节码)
└─ AES/CRC32/Huffman/Base64, 环境指纹收集
rs_reverse/
│
├── reverse/ ★ 纯算实现 (核心成果)
│ ├── scripts/
│ │ ├── client.js 纯算客户端 (233行, 一键使用)
│ │ ├── run.js Cookie T 全流程脚本
│ │ ├── coder.js 外层 VM 重写 (362行)
│ │ ├── basearr.js 明文数据构建 (304行)
│ │ └── pure_e2e.js 端到端验证
│ ├── captured/
│ │ └── mainjs.js 缓存的 mainjs
│ ├── test/
│ │ └── api_test.js API 接口测试
│ └── REVERSE_ARCHIVE.md 完整逆向过程记录
│
├── houzhui/ ★ URL 后缀 AST 深度逆向
│ ├── ast/ 14 个 AST 分析工具
│ │ ├── ast_trace_rt239.js 定位后缀核心函数 rt[239] (15KB)
│ │ ├── ast_deep_bs.js 拆解 56 个子函数
│ │ ├── ast_extract_opcodes.js 提取 409 个 VM opcodes
│ │ ├── ast_r2mka_disasm.js 自动反汇编 (6328行输出)
│ │ ├── ast_bytecode_to_js.js 栈模拟翻译 (字节码→伪JS)
│ │ ├── ast_suffix_structure.js 后缀 88B/120B 结构分析
│ │ ├── ast_find_xtea_huffman.js 定位加密函数 (SHA-1/XTEA)
│ │ ├── ast_verify_all.js 440 个 rt[N] 完整映射
│ │ ├── ast_session_chain.js AES 解密链提取
│ │ ├── ast_cookie_s_decrypt.js Cookie S 解密路径
│ │ ├── ast_cookie_s_complete.js 核心函数翻译
│ │ ├── ast_translate_child40.js TLV 解析器翻译
│ │ ├── ast_trace_session49.js 49B session 追踪
│ │ └── ast_trace_49b.js 纯 AST 完整 49B 路径
│ └── SUFFIX_REVERSE.md 后缀逆向完整记录
│
├── jsrpc/ ★ JsRpc 通杀方案
│ ├── server.js WebSocket RPC 服务端
│ ├── inject.js 浏览器注入脚本
│ ├── client.js Node.js 客户端
│ └── README.md 使用说明
│
├── sdenv/ 补环境方案 (魔改 jsdom)
│ ├── client.js sdenv 客户端
│ └── README.md 技术总结
│
├── agentskill/ ★ 顶级逆向 Skill (可复制给任何 AI Agent)
│ ├── SKILL.md 主入口 (362行, 决策树+方法论+排错指南)
│ ├── references/ 按需加载的详细参考 (7 篇)
│ │ ├── encryption_chain.md 阶段1: 加密链 (Huffman/AES/CRC32/Base64)
│ │ ├── key_extraction.md 阶段2: 密钥提取
│ │ ├── coder_rewrite.md 阶段3: 外层VM重写 + 调试6个坑
│ │ ├── basearr_adaptation.md 阶段4: basearr数据驱动适配
│ │ ├── ast_methodology.md AST反编译4步流水线
│ │ ├── suffix_analysis.md URL后缀结构+SHA-1签名
│ │ └── vm_hook_cookbook.md 7种VM注入技术
│ ├── scripts/ 可直接执行的脚本 (5 个)
│ │ ├── collect_session.js 配套数据一次性采集
│ │ ├── hybrid_verify.js 混合验证 (证明加密链正确)
│ │ ├── pure_run.js 纯算全流程模板
│ │ ├── collect_type2.js type=2多session采集
│ │ └── sdenv_client.js sdenv客户端
│ └── lib/ 格式化的参考实现
│ ├── coder.js 外层VM重写器 (508行, 验证100%字节一致)
│ └── basearr.js basearr生成器 (282行, 验证HTTP 200)
│
├── rs-reverse-src/ pysunday/rs-reverse 开源参考 (纯算借鉴来源)
│ ├── src/handler/Coder.js 外层 VM 重写 (我们 coder.js 的参照)
│ ├── src/handler/Cookie.js 加密链实现 (Huffman/AES/CRC32)
│ ├── src/handler/basearr/ 7 个站点的 basearr 适配器
│ ├── src/handler/parser/ 密钥提取/r2mka 解析
│ └── src/handler/grenKeys.js 变量名生成 (PRNG + Fisher-Yates)
│
└── captured/ 抓包数据 (本地保留, 不上传 GitHub)
完全不依赖浏览器, 纯 Node.js 实现整条加密链。
本方案借鉴了 pysunday/rs-reverse 开源项目 (已收录在 rs-reverse-src/), 该项目已在 9+ 个瑞数站点验证通过。我们在其基础上:
- 参照其
Coder.js的模块结构, 重写了外层 VM 解释器 (coder.js) - 参照其
basearr/len157.js的逐字段分析方法, 用数据驱动适配了我们的站点 (basearr.js) - 参照其加密链 (
Cookie.js) 实现了 Huffman → XOR → AES-CBC → CRC32 → AES-CBC → Base64 - 密钥提取 (
extractKeys) 参照其tscd.js的 XOR offset 推导思路, 简化为已知 keys[0]="64" 的硬编码方式
$_ts.cd → extractKeys() → 45 组密钥
mainjs + nsd → Coder 重写 → eval 代码 + codeUid
已知参数 → buildBasearr() → 154B TLV 明文
basearr → Huffman → XOR → AES-CBC → CRC32 → AES-CBC → Base64 → Cookie T
核心文件:
coder.js— 外层 VM 重写 (362行), 从 mainjs 生成 eval 代码, 逐字节与原始一致basearr.js— 明文数据构建 (304行), 8 种 TLV type 全覆盖client.js— 完整客户端 (233行), Cookie 自动更新
与 rs-reverse 的主要差异:
| rs-reverse | 本项目 | |
|---|---|---|
| XOR offset | 从任务树动态计算 | 硬编码推导 (keys[0]="64") |
| basearr 适配 | 7 个站点适配器, 手工逆向 | 数据驱动: sdenv 采集 5 组 → 逐字节对比 |
| r2mka 解析 | 完整任务树 → fixedValue20 | 未实现 (数据驱动替代) |
| type=2 | r2mka 查找 | cp1 索引映射 (5 session 采集) |
通过 WebSocket 调用浏览器中真实运行的瑞数 VM, Cookie + 后缀全自动:
Node.js ←HTTP→ JsRpc Server ←WebSocket→ 浏览器中的瑞数 VM
已验证: 商标查询站点 + 国家药品监督管理局 (瑞数6, 最严格)
魔改 jsdom 模拟浏览器环境, 让瑞数 JS 在 Node.js 中真实执行:
- 优点: 自动生成 Cookie, 所有瑞数站点通用
- 注意: sdenv 本身不生成 URL 后缀, 需要后缀的站点建议用 JsRpc
对 URL 后缀进行深度逆向研究, 使用 AST 作为核心分析工具。
"0" + URLSafeBase64([
[0-3] 4B nonce 随机
[4-5] flag + marker
[6-54] 49B session Cookie S 解密 (VM 内部)
[55] 0x20(无search) / 0x40(有search)
[56-87] 32B signature SHA-1(行为数据 + URL)
])
eval_code.js (296KB)
↓ acorn.parse() → AST
↓ 遍历 _$_I 的 if(op===N) 分支
opcode 语义映射 (409 条)
↓ 反汇编器逐条翻译字节码
汇编代码 (6328 行)
↓ 栈模拟翻译 (自动)
可读伪 JS 代码 (1653 行)
↓ 人工语义标注
带注释的可执行代码
关键发现:
- 后缀签名使用 SHA-1 (不是 XTEA/AES)
- 32B signature = 鼠标/键盘行为统计编码 (不是加密)
- URL 数据通过 createElement('a') 解析 后 XOR 编码进后缀
- 当前卡在: 49B session 在 VM 字节码内部计算, AST 无法触及
| 方法 | 效率 | 说明 |
|---|---|---|
| AST 静态分析 | ★★★★★ | 20h → 52 个函数, ~400B/h, opcode 100% 精确 |
| 运行时栈追踪 | ★★ | 2天 → 1 个函数, ~80B/天, 需要猜 opcode 语义 |
| 手工阅读混淆代码 | ★ | 296KB 混淆代码, 不现实 |
从真实逆向经验中蒸馏出的工程化 AI Agent Skill, 不是一份笔记, 而是一套可以直接复制给任何 AI Agent 执行的完整知识体系。
市面上的瑞数资料要么是零散的博客文章, 要么是开源项目的源码 (如 rs-reverse)。没有人把完整的逆向方法论 + 踩坑经验 + 排错指南 + 可执行代码打包成一个 AI 可以直接消费的 skill。 这是第一个。
agentskill/
├── SKILL.md (362行) ← AI 首先加载这个, 就能决策和执行
│ ├── YAML frontmatter Agent 自动发现 (Claude Code / Codex / Cursor)
│ ├── 决策树 拿到 URL → 5 步判断走哪条路
│ ├── 6 阶段总览表 每阶段: 输入→输出→验证标准 (3行搞定)
│ ├── 方法论 数据驱动 + AST (各写一次, 不重复)
│ ├── 弯路警告 6 个真实踩坑 (省你 5+ 天)
│ ├── 排错指南 412/400/Coder不匹配/keys失败/type=2
│ └── 站点适配 Checklist 11 项打勾即可
│
├── references/ (7篇) ← 按需加载, 不污染 context window
│ 加密链 / 密钥提取 / Coder重写 / basearr适配
│ AST方法论 / 后缀分析 / VM注入手册
│
├── scripts/ (5个) ← 可直接 node 执行
│ 数据采集 / 混合验证 / 纯算全流程 / type=2采集 / sdenv客户端
│
└── lib/ (2个) ← 格式化的参考实现
coder.js (508行) + basearr.js (282行)
对比原来的单文件方案: 主文档从 3300 行 / 53K tokens 压缩到 362 行 / ~6K tokens (缩减 89%), AI 首次加载成本降低一个数量级, 同时通过 references/ 保留了所有深度内容。
- 数据驱动 (Cookie T / basearr): 采集 3-5 组真实数据 → 逐字节对比 → 找来源。不读 VM 代码。
- AST 分析 (后缀 / eval code): acorn 解析 → rt[N] 函数映射 → 调用链追踪。几小时完成手工数周的量。
- 弯路警告: 2 天读 VM 代码 = 浪费; 1 天照搬 rs-reverse 公式 = 浪费; 数据驱动 10 分钟解决。
给 AI Agent: 把 agentskill/ 目录放到项目中, Agent 读 SKILL.md 即可开始工作。
给人类: 读 SKILL.md 的决策树和排错指南, 按 Checklist 适配新站点。
数据驱动 → 回答 "改什么" (basearr 每个字节的来源)
AST 分析 → 回答 "怎么理解代码" (eval code 函数定位 + 调用链)
VM Hook → 回答 "怎么拿到真实数据" (为数据驱动提供采集手段)
遇到不理解的字节 → 多采几组真实数据 → 逐字节对比 → 找规律
不要读 VM 代码, 用 sdenv 采集 3-5 组真实数据, 逐字节对比找到每个字段的来源。 我们花了 2 天读 VM 代码理解 basearr — 完全浪费。转向数据驱动后 1 天内解决。
VM Hook — 数据驱动的采集手段:
数据驱动的前提是能拿到真实数据。通过 sdenv + vm.runInContext 拦截, 可以在瑞数 VM 执行过程中注入 hook, 捕获中间数据:
| Hook 技术 | 用途 | 示例 |
|---|---|---|
vm.runInContext 拦截 |
捕获 eval 代码、提取 cd/nsd | 按 code.length > 250000 识别 eval 代码 |
Object.defineProperty 劫持 |
捕获 Cookie 写入时刻 | 劫持 Document.prototype.cookie setter |
| IIFE 函数包装 | 追踪特定函数的输入输出 | 包装加密入口函数, 记录 basearr → cipher |
| 逗号表达式注入 | 不改变控制流的中间值记录 | (console.log(x), originalCall(x)) |
| Phase 标记 | 区分不同执行阶段 | 只在加密阶段记录, 避免噪音 |
完整的 22 步 hook 进化过程见 reverse/REVERSE_ARCHIVE.md。
eval code 是合法 JS → acorn 解析 → 函数映射 → 调用链追踪 → 自动反汇编
VM 解释器 _$_I 的源码就在 eval code 里, AST 直接读出 409 个 opcode 的 JS 实现。
14 个 AST 工具, ~20h, 产出 6328 行反汇编 + 1653 行伪代码。
当你能打开黑盒读电路图时, 永远不要从外面猜。
POST /searchUser/searchAction!getVRecordListPage.do
Content-Type: application/x-www-form-urlencoded
page=1&rows=10&sidx=RECORD_NUM&sord=desc&_search=false&nd=<timestamp>
可选: RECORD_NAME=<商标名>&COUNTRY=<国家代码>
响应: { total, page, records, rows: [{ RECORD_NUM, REGISTER_NUM, APPLY_USER_NAME, ... }] }
POST /param/paramAction!getParamTypeList.do
ns=<timestamp>&code=Country
响应: [{ value: "142", name: "中国" }, { value: "502", name: "美国" }, ...]
- Node.js 18+ — 运行环境
- acorn + acorn-walk — AST 解析 (后缀逆向)
- crypto (Node.js 内置) — AES-128-CBC, CRC32
- 无外部依赖 — 纯算方案零第三方库
- pysunday/rs-reverse — 纯算开源参考实现, 9+ 站点验证
- pysunday/sdenv — 补环境框架, 数据驱动采集的核心依赖
- anthropic/claude-code — AI 辅助逆向分析
本项目仅供安全研究与学习交流使用, 严禁用于任何非法用途。滥用本项目逆向成果所造成的一切法律责任和后果, 与本作者无关。
MIT