dsh-js-reverse-plugin 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cordis.patch.yml +14 -0
- package/index.js +61 -0
- package/package.json +20 -0
- package/skills/iv8-env-runtime/SKILL.md +159 -0
- package/skills/iv8-env-runtime/assets/entry-report-template.txt +23 -0
- package/skills/iv8-env-runtime/assets/env_starter.py +100 -0
- package/skills/iv8-env-runtime/references/case-function-iwencai.md +96 -0
- package/skills/iv8-env-runtime/references/case-intercept-douyin.md +133 -0
- package/skills/iv8-env-runtime/references/config-defaults-cheatsheet.md +75 -0
- package/skills/iv8-env-runtime/references/cross-platform-install.md +108 -0
- package/skills/iv8-env-runtime/references/iv8-api-contract.md +97 -0
- package/skills/iv8-env-runtime/references/network-and-eventloop.md +113 -0
- package/skills/iv8-env-runtime/references/part1-entry-location.md +138 -0
- package/skills/iv8-env-runtime/references/part1-mcp-tool-map.md +77 -0
- package/skills/iv8-env-runtime/references/part2-discovery.md +80 -0
- package/skills/iv8-env-runtime/references/patching-principles.md +91 -0
- package/skills/iv8-env-runtime/references/trap-blacklist.md +60 -0
- package/skills/iv8-env-runtime/references/version-gotchas.md +128 -0
- package/skills/iv8-env-runtime/scripts/consistency_lint.py +211 -0
- package/skills/iv8-env-runtime/scripts/defaults_audit.py +143 -0
- package/skills/iv8-env-runtime/scripts/monitor_env.py +185 -0
- package/skills/iv8-env-runtime/scripts/network_bridge.py +147 -0
- package/skills/iv8-env-runtime/scripts/parity_check.py +175 -0
- package/skills/iv8-env-runtime/scripts/preflight.py +144 -0
- package/skills/iv8-env-runtime/scripts/reproduce_stub_error.py +165 -0
- package/skills/iv8-env-runtime/scripts/run_target.py +150 -0
- package/skills/iv8-jsvmp-recovery/SKILL.md +129 -0
- package/skills/iv8-jsvmp-recovery/agents/openai.yaml +4 -0
- package/skills/iv8-jsvmp-recovery/references/case-study-douyin-a-bogus.md +320 -0
- package/skills/iv8-jsvmp-recovery/references/controlled-oracle-and-equivalence.md +247 -0
- package/skills/iv8-jsvmp-recovery/references/static-trace-evidence.md +289 -0
- package/skills/iv8-jsvmp-recovery/references/vmp-domain-model.md +212 -0
- package/skills/iv8-jsvmp-recovery/scripts/verify-equivalence.py +281 -0
- package/skills/js-ast-deobfuscation/SKILL.md +140 -0
- package/skills/js-ast-deobfuscation/agents/openai.yaml +4 -0
- package/skills/js-ast-deobfuscation/references/anti-patterns.md +325 -0
- package/skills/js-ast-deobfuscation/references/first-pass.md +255 -0
- package/skills/js-ast-deobfuscation/references/interaction-and-stopping.md +758 -0
- package/skills/js-ast-deobfuscation/references/iv8-runtime-observation.md +773 -0
- package/skills/js-ast-deobfuscation/references/jsvmp-identification.md +328 -0
- package/skills/js-ast-deobfuscation/references/methods-and-evidence.md +460 -0
- package/skills/js-ast-deobfuscation/references/patterns-and-priority.md +516 -0
- package/skills/js-ast-deobfuscation/references/validation-contract.md +604 -0
- package/skills/js-ast-deobfuscation/scripts/prepare-source.mjs +921 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# 案例:抖音 JSVMP `a_bogus` 独立精确复现
|
|
2
|
+
|
|
3
|
+
本文只记录课程中 `bdms_1.0.1.19.js` 的已验证事实。它展示主线如何落地:以受控 iv8 中的原始程序作为 Oracle,结合静态 Bytecode 反编译和动态 Handler Trace,让纯 Python 从声明的原始输入逐字符生成相同 `a_bogus`。
|
|
4
|
+
|
|
5
|
+
不把本案例的 Record ID、字段布局、算法顺序或阈值当作其他 VMP 的通用结构。
|
|
6
|
+
|
|
7
|
+
## 目录
|
|
8
|
+
|
|
9
|
+
1. 样本和目标
|
|
10
|
+
2. 受控 Oracle
|
|
11
|
+
3. 静态程序容器
|
|
12
|
+
4. 动态 Trace
|
|
13
|
+
5. Trace 阶段的成果与边界
|
|
14
|
+
6. 五个未知点的静态闭合
|
|
15
|
+
7. 完整原始输入
|
|
16
|
+
8. 从原始输入到 `a_bogus`
|
|
17
|
+
9. 独立 Python 实现
|
|
18
|
+
10. 精确验收
|
|
19
|
+
11. 本案例教训
|
|
20
|
+
|
|
21
|
+
## 1. 样本和目标
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
sample bdms_1.0.1.19.js
|
|
25
|
+
source SHA-256 2728891a2506a544b48d591bca6c021886478dbf8197a61862a36d894ebfca51
|
|
26
|
+
final field a_bogus
|
|
27
|
+
baseline length 192 characters
|
|
28
|
+
baseline hash 78b0663c770f9596d9f8b2366db3f008ddda826f4ffae431363e9233c8b1ad8d
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
最终目标不是恢复作者原变量名,也不是为全部 Record 生成高语义源码。唯一完成命题是:
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
同一组原始输入
|
|
35
|
+
Python a_bogus === 固定 iv8 a_bogus
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 2. 受控 Oracle
|
|
39
|
+
|
|
40
|
+
基线执行固定:
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
random seed 439041101 / 0x1a2b3c4d
|
|
44
|
+
fixed epoch ms 1786003200123
|
|
45
|
+
performance start 1000.0
|
|
46
|
+
performance step 0.125
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
确定性实验表明:
|
|
50
|
+
|
|
51
|
+
- 只固定随机源时,最终输出仍然变化;
|
|
52
|
+
- 同时固定随机和时间后,连续 3 次输出完全相同。
|
|
53
|
+
|
|
54
|
+
这个实验证明受控环境是反编译的前提:如果 Oracle 还在漂移,最终差异无法可靠地归因于恢复实现。
|
|
55
|
+
|
|
56
|
+
## 3. 静态程序容器
|
|
57
|
+
|
|
58
|
+
当前可审计的正式静态口径是:
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
Opcode schema entries 77,编号 0..76
|
|
62
|
+
string-pool entries 1001
|
|
63
|
+
raw VM records 796
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
796 条 Record 直接来自静态恢复的原始 VM 程序容器,不依赖 Trace。每条是当前样本中的四元结构:
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
bytecode
|
|
70
|
+
parameter-binding count
|
|
71
|
+
strict-mode flag
|
|
72
|
+
exception table
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
已完成:
|
|
76
|
+
|
|
77
|
+
- 796 条 Record 的全量线性反汇编;
|
|
78
|
+
- 单一总反汇编和按 Record 拆分的文件;
|
|
79
|
+
- 第一版低语义伪代码;
|
|
80
|
+
- 普通 CFG 和不可达代码;
|
|
81
|
+
- Opcode 名称、操作数宽度、栈效应和下一 PC 规则。
|
|
82
|
+
|
|
83
|
+
报告 Handler 数量时不要把“最大 Opcode ID 是 76”说成“只有 76 个 Opcode”。本案例当前的 Schema 是 77 项;如果另外按 JavaScript Handler 实现体数量计数,必须单独声明口径和共用/辅助函数的处理。
|
|
84
|
+
|
|
85
|
+
## 4. 动态 Trace
|
|
86
|
+
|
|
87
|
+
matched-request Trace 于固定输入下捕获:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
total events 65,390
|
|
91
|
+
handler events 65,094
|
|
92
|
+
frame events 296
|
|
93
|
+
unique records reached 103
|
|
94
|
+
unique opcode kinds reached 61
|
|
95
|
+
unique (recordId, PC, opcode) 3,603
|
|
96
|
+
dropped events 0
|
|
97
|
+
handler events without after 0
|
|
98
|
+
trace internal errors 0
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Trace 证明了当前输入的真实动态路径,不证明只有 103 个 Record,也不证明只有 61 种 Opcode。静态容器是 796 条 Record,当前 Trace 只覆盖其中 103 条。
|
|
102
|
+
|
|
103
|
+
Trace 还确认:
|
|
104
|
+
|
|
105
|
+
- `record130` 生成最终编码字符串;
|
|
106
|
+
- `record107` 执行 `searchParams.append("a_bogus", signature)`;
|
|
107
|
+
- 主链包含 SM3、随机化 3→4 打包、Modified RC4 和自定义 6-bit 编码;
|
|
108
|
+
- Focus Trace 捕获了五次 SM3、99→132 打包、两次 Modified RC4、header/prefix 和 s3/s4 输入输出。
|
|
109
|
+
|
|
110
|
+
## 5. Trace 阶段的成果与边界
|
|
111
|
+
|
|
112
|
+
Trace 阶段先恢复了:
|
|
113
|
+
|
|
114
|
+
- 加密和编码链;
|
|
115
|
+
- 50 字节 core、环境文本、时间尾串和 XOR checksum 的材料布局;
|
|
116
|
+
- 变长材料长度 `50 + len(environmentText) + len(timeText) + 1`;
|
|
117
|
+
- 原始 JS 现场生成的新密文可被独立解密并语义解析;
|
|
118
|
+
- 只接收请求、环境、时间和 seed 的早期完整生成链。
|
|
119
|
+
|
|
120
|
+
但 Trace 中的基线值仍存在同值歧义和未执行分支,以下五项当时只知道基线值和大致消费位置,不知道全部公式和业务语义:
|
|
121
|
+
|
|
122
|
+
```text
|
|
123
|
+
record149
|
|
124
|
+
record699
|
|
125
|
+
record277
|
|
126
|
+
record697
|
|
127
|
+
record150 descriptor branch
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
因此转入 Bytecode、CFG、Scope 和定向原 VM 变体,而不仅继续观察同一基线 Trace。
|
|
131
|
+
|
|
132
|
+
## 6. 五个未知点的静态闭合
|
|
133
|
+
|
|
134
|
+
五项都使用同一证据结构:
|
|
135
|
+
|
|
136
|
+
```text
|
|
137
|
+
Bytecode / CFG / Scope 静态恢复
|
|
138
|
+
→ 原 VM 定向单变量执行
|
|
139
|
+
→ Record 返回值与 50 字节 core 偏移对账
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
28/28 组原 VM 变体全部通过。最终语义是:
|
|
143
|
+
|
|
144
|
+
| Record | 早期占位名 | 最终语义 | 基线 |
|
|
145
|
+
|---:|---|---|---:|
|
|
146
|
+
| 149 | `environmentCode` | 当前 VM 生命周期内签名累计调用次数分桶 | `6` |
|
|
147
|
+
| 699 | `platformCode` | 运行环境/自动化异常位集 `runtimeRiskBits` | `1` |
|
|
148
|
+
| 277 | `trackCode` | 交互行为异常位集 `behaviorBits` | `14` |
|
|
149
|
+
| 697 | 五项特征向量 | 四个行为队列变更计数 + 一组环境异常位集 | `[0,0,0,0,1]` |
|
|
150
|
+
| 150 | `descriptorFlag` | `window.onwheelx._Ax` own descriptor 的 `writable` 检查 | `3` |
|
|
151
|
+
|
|
152
|
+
关键纠正:
|
|
153
|
+
|
|
154
|
+
```text
|
|
155
|
+
platformCode → runtimeRiskBits
|
|
156
|
+
trackCode → behaviorBits
|
|
157
|
+
environmentCode → signatureInvocationBucket
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
这些不是浏览器平台枚举。这个纠正说明中性占位名应保留到输入来源、全分支公式和下游消费者都明确。
|
|
161
|
+
|
|
162
|
+
### `record149`
|
|
163
|
+
|
|
164
|
+
`record132` 创建 `record149` 和 `record150`,两者共享计数器。`record150` 开始执行时自增,`record149` 返回四档分桶:
|
|
165
|
+
|
|
166
|
+
```text
|
|
167
|
+
0..139 → 6
|
|
168
|
+
140..1283 → 5
|
|
169
|
+
1284..10745 → 4
|
|
170
|
+
10746+ → 3
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### `record699`
|
|
174
|
+
|
|
175
|
+
从固定 bit0 开始,检查原生函数表面/canvas/plugins、Headless/WebDriver、自动化全局、Node/CommonJS、localhost/IP URL、UA/platform 矛盾和核心浏览器对象完整性。
|
|
176
|
+
|
|
177
|
+
### `record277`
|
|
178
|
+
|
|
179
|
+
将 Move、ClickStart 和 KeyDown 三个队列的空值、移动速度和按键间隔异常按位聚合。基线三队列为空,得到 `2 | 4 | 8 = 14`。
|
|
180
|
+
|
|
181
|
+
### `record697`
|
|
182
|
+
|
|
183
|
+
前四项是 Move、ClickStart、ClickEnd、KeyDown 环形队列变更计数的低字节,不是队列长度或布尔状态。第五项检查 `document.all`、Error stack、screen 对象形状、嵌入式浏览器桥、storage/quota/私密模式、frame 身份和 DevTools 窗口差。
|
|
184
|
+
|
|
185
|
+
### `record150`
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
if (!window.onwheelx || !window.onwheelx._Ax) return 11;
|
|
189
|
+
descriptor = Object.getOwnPropertyDescriptor(window.onwheelx, "_Ax");
|
|
190
|
+
return descriptor?.writable === false ? 3 : 12;
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
基线 iv8 中 `_Ax` 为 truthy,且 own descriptor 的 `writable === false`,所以返回 `3`。这是对特定宿主表面/完整性哨兵的检查,不是通用业务属性。
|
|
194
|
+
|
|
195
|
+
## 7. 完整原始输入
|
|
196
|
+
|
|
197
|
+
纯 Python 公开入口允许接收:
|
|
198
|
+
|
|
199
|
+
```text
|
|
200
|
+
请求 query、body
|
|
201
|
+
环境 window/document/navigator/screen/location 等原始宿主事实
|
|
202
|
+
行为 Move、ClickStart、ClickEnd、KeyDown 原始队列/事件
|
|
203
|
+
时间 Date.now/new Date/performance 的固定序列
|
|
204
|
+
随机源 Math.random 初始状态和调用序列
|
|
205
|
+
配置 pageId、aid、track.mode、SDK 版本
|
|
206
|
+
初始状态 签名共享计数器等 VM 生命周期输入
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
公开入口禁止接收:
|
|
210
|
+
|
|
211
|
+
```text
|
|
212
|
+
runtimeRiskBits
|
|
213
|
+
behaviorBits
|
|
214
|
+
featureVector
|
|
215
|
+
descriptorFlag
|
|
216
|
+
invocationBucket
|
|
217
|
+
environmentBytes
|
|
218
|
+
timeBytes
|
|
219
|
+
header8
|
|
220
|
+
prefix4
|
|
221
|
+
checksum
|
|
222
|
+
material
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
这些都必须由 Python 从原始输入自己计算。
|
|
226
|
+
|
|
227
|
+
## 8. 从原始输入到 `a_bogus`
|
|
228
|
+
|
|
229
|
+
已恢复的当前样本主线是:
|
|
230
|
+
|
|
231
|
+
```text
|
|
232
|
+
原始请求、环境、行为、时间、随机源、配置
|
|
233
|
+
→ runtimeRiskBits / behaviorBits / featureVector
|
|
234
|
+
→ Query / Body / UA 三组摘要
|
|
235
|
+
→ environmentBytes / timeBytes
|
|
236
|
+
→ header8
|
|
237
|
+
→ 50 字节 core
|
|
238
|
+
→ checksum
|
|
239
|
+
→ material = core || environmentBytes || timeBytes || checksum
|
|
240
|
+
→ prefix4
|
|
241
|
+
→ record148 随机打包
|
|
242
|
+
→ Modified RC4(header8 || packedMaterial)
|
|
243
|
+
→ prefix4 || ciphertext
|
|
244
|
+
→ s4
|
|
245
|
+
→ a_bogus
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
当前基线 `material` 长度为 99,但 99 不是协议定长。已验证 97、98、99 字节材料和 188/192 字符最终输出。
|
|
249
|
+
|
|
250
|
+
## 9. 独立 Python 实现
|
|
251
|
+
|
|
252
|
+
独立实现:
|
|
253
|
+
|
|
254
|
+
- 不加载原始 `bdms` JavaScript;
|
|
255
|
+
- 不依赖 iv8;
|
|
256
|
+
- 入口只接收 `FixedIv8RawInput`;
|
|
257
|
+
- 从原始环境、行为和共享状态计算五个早期未知字段;
|
|
258
|
+
- 自行计算摘要、core、材料、随机序列、header/prefix、Modified RC4 和 s4;
|
|
259
|
+
- 拒绝在环境、行为或配置中传入预计算协议字段。
|
|
260
|
+
|
|
261
|
+
原始课程工作区曾按以下路径组织实现与证据。这些路径仅用于说明案例来源,不随插件分发,也不是 skill 的运行依赖:
|
|
262
|
+
|
|
263
|
+
```text
|
|
264
|
+
课程案例demo/douyin-jsvmp/vm-analysis/trace/recovered/
|
|
265
|
+
课程案例demo/douyin-jsvmp/vm-analysis/trace/derived/fixed-iv8-raw-input.json
|
|
266
|
+
课程案例demo/douyin-jsvmp/vm-analysis/trace/derived/full-generation-l3.json
|
|
267
|
+
课程案例demo/douyin-jsvmp/vm-analysis/decompiler/
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## 10. 精确验收
|
|
271
|
+
|
|
272
|
+
完成证据:
|
|
273
|
+
|
|
274
|
+
```text
|
|
275
|
+
45 组材料单变量差分
|
|
276
|
+
28/28 组原 VM 定向语义变体
|
|
277
|
+
8/8 组同 RawInput 的 Python 与原 JS + iv8 端到端对账
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
8/8 用例中以下项目全部一致:
|
|
281
|
+
|
|
282
|
+
```text
|
|
283
|
+
探针字段
|
|
284
|
+
material
|
|
285
|
+
header8
|
|
286
|
+
prefix4
|
|
287
|
+
随机调用序列
|
|
288
|
+
最终 a_bogus
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
固定基线最终输出为 192 字符,SHA-256 为:
|
|
292
|
+
|
|
293
|
+
```text
|
|
294
|
+
78b0663c770f9596d9f8b2366db3f008ddda826f4ffae431363e9233c8b1ad8d
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
该结论的范围是固定 iv8 原始输入合同和已列变体。不要扩大为“支持任意真实浏览器”。
|
|
298
|
+
|
|
299
|
+
## 11. 本案例教训
|
|
300
|
+
|
|
301
|
+
可迁移的是判断原则,不是样本工作流:
|
|
302
|
+
|
|
303
|
+
1. 先建立可重复 Oracle,否则差异无法归因。
|
|
304
|
+
2. Trace 快速恢复了当前路径的算法和材料,但不能单独消除基线同值歧义和未执行分支。
|
|
305
|
+
3. 静态 Bytecode/CFG/Scope 补全公式,原 VM 单变量实验反驳或验证语义。
|
|
306
|
+
4. 全量反汇编和 CFG 在该案例中是有价值的基础,但完整高语义全库 CFG 不是最终验收前提。
|
|
307
|
+
5. 中间值对账帮助定位,最终仍以同 `RawInput` 下的精确输出一致验收。
|
|
308
|
+
6. 删除公开入口中的预计算辅助字段,才使“从原始输入恢复完整映射”成为真命题。
|
|
309
|
+
7. 完成范围由可验证命题决定,不由 Handler、Record 或 CFG 的形式完整度决定。
|
|
310
|
+
|
|
311
|
+
不可迁移的是:
|
|
312
|
+
|
|
313
|
+
- 77 个 Opcode Schema 和 796 条 Record;
|
|
314
|
+
- `record149/699/277/697/150` 的 ID 与语义;
|
|
315
|
+
- 50 字节 core 布局;
|
|
316
|
+
- SM3、Modified RC4、s4 和当前随机打包顺序;
|
|
317
|
+
- `window.onwheelx._Ax` 等当前版本哨兵;
|
|
318
|
+
- 基线输出长度、Hash 和所有阈值。
|
|
319
|
+
|
|
320
|
+
分析新 VMP 时,重用“受控 Oracle + 静态全分支 + 动态实例 + 独立精确复现”的证据模型,不重用本案例的字段和顺序。
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# 受控 iv8 Oracle 与精确等价
|
|
2
|
+
|
|
3
|
+
本文定义 VMP 语义恢复中“参考实现”、“原始输入”和“正确”的可量化含义。主线始终是:让独立实现从与受控 iv8 完全相同的原始输入出发,得到精确相同的最终输出。
|
|
4
|
+
|
|
5
|
+
## 目录
|
|
6
|
+
|
|
7
|
+
1. Oracle 命题
|
|
8
|
+
2. 为什么使用 iv8
|
|
9
|
+
3. RawInput 合同
|
|
10
|
+
4. 受控性维度
|
|
11
|
+
5. 原始值与派生值
|
|
12
|
+
6. Oracle 完整性
|
|
13
|
+
7. 精确比较
|
|
14
|
+
8. 受控变体
|
|
15
|
+
9. 中间对账
|
|
16
|
+
10. 服务器判决
|
|
17
|
+
11. 完成声明
|
|
18
|
+
|
|
19
|
+
## 1. Oracle 命题
|
|
20
|
+
|
|
21
|
+
把未修改的原始程序在声明的受控 iv8 条件下的输出定义为 Oracle:
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
O(x) = OriginalVMP_in_Controlled_iv8(x)
|
|
25
|
+
R(x) = IndependentRecoveredImplementation(x)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
对某个固定输入 `x0` 的基线命题是:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
R(x0) === O(x0)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
对一组受控变体 `X` 的扩展命题是:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
对每个 x in X,R(x) === O(x)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
静态全分支恢复可以继续扩大可信范围,但不要在没有证据时声称对无限输入空间完全等价。
|
|
41
|
+
|
|
42
|
+
## 2. 为什么使用 iv8
|
|
43
|
+
|
|
44
|
+
把 iv8 视为受控参考执行环境,而不是分析目标本身。
|
|
45
|
+
|
|
46
|
+
```text
|
|
47
|
+
纯 Node
|
|
48
|
+
优点:轻量、可控、方便断点和脚本化
|
|
49
|
+
缺点:浏览器对象形状和原生语义需要大量手工补齐
|
|
50
|
+
|
|
51
|
+
真实浏览器
|
|
52
|
+
优点:DOM、渲染、网络和对象形状更真实
|
|
53
|
+
缺点:Cookie、LocalStorage、缓存、网络、时间、调度和页面生命周期难以完全固定
|
|
54
|
+
|
|
55
|
+
iv8
|
|
56
|
+
优点:比纯 Node 更接近浏览器形状,比真实浏览器轻量且易于固定输入和运行状态
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
目标依赖布局、字体、GPU、真实网络栈或浏览器内部状态时,使用可定制浏览器或受控 CDP 环境。保留同一 Oracle 原则:先声明可控状态,再比较独立实现。
|
|
60
|
+
|
|
61
|
+
安装、版本、iv8 API、补环境、网络桥接和 event loop 操作使用 `iv8-env-runtime`,不在本 reference 重复。
|
|
62
|
+
|
|
63
|
+
## 3. RawInput 合同
|
|
64
|
+
|
|
65
|
+
在分析算法之前,先声明独立实现允许接收的输入层。通用类别是:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
request URL、query、body、method、headers 中确实被读取的原始值
|
|
69
|
+
environment window/document/navigator/screen/location 等宿主可观测事实
|
|
70
|
+
behavior 原始事件、事件序列或已声明的初始队列状态
|
|
71
|
+
time Date/performance/timer 的初始状态和调用序列
|
|
72
|
+
randomness Math.random/crypto 等随机源的初始状态与调用序列
|
|
73
|
+
configuration SDK 版本、aid、page id、mode 等原始配置
|
|
74
|
+
initialState Cookie、storage、cache、共享计数器、队列和初始化阶段
|
|
75
|
+
network 程序确实消费的响应字节、头和返回顺序
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
不要为了统一 Schema 强制每个样本都具有全部字段。记录当前程序真正读取的输入和没有读取的候选值。
|
|
79
|
+
|
|
80
|
+
对可变序列同时记录值和消费顺序。仅固定随机 seed 不代表随机流一致;调用次数或时序不同也会改变结果。
|
|
81
|
+
|
|
82
|
+
## 4. 受控性维度
|
|
83
|
+
|
|
84
|
+
对以下影响源作出显式声明:
|
|
85
|
+
|
|
86
|
+
| 维度 | 需要记录的事实 |
|
|
87
|
+
|---|---|
|
|
88
|
+
| 原始程序 | 路径、SHA-256、是否为原始文件或派生执行目标 |
|
|
89
|
+
| 运行时 | iv8/Python/V8 版本、平台、关键选项 |
|
|
90
|
+
| 环境 | 可观测属性、descriptor、prototype、对象身份和原生函数表面 |
|
|
91
|
+
| 时间 | epoch、performance 起点/步长、timer 执行顺序 |
|
|
92
|
+
| 随机 | 算法、seed、初始状态、每次调用序号 |
|
|
93
|
+
| 存储 | Cookie、LocalStorage、SessionStorage、IndexedDB、quota 的初始值 |
|
|
94
|
+
| 网络 | 请求匹配、响应内容、注入时机、错误和重试 |
|
|
95
|
+
| 行为 | 事件内容、时间戳、注入顺序、去抖/采样前后的边界 |
|
|
96
|
+
| 生命周期 | 初始化次数、签名调用次数、event loop 排空点和异步共享状态 |
|
|
97
|
+
| 观测 | 断点、Hook、Trace、wrapper、补丁和派生插桩文件 |
|
|
98
|
+
|
|
99
|
+
这些条件不是形式文档,而是 `O(x)` 定义的一部分。未记录的可变状态可能使同一输入看似不确定。
|
|
100
|
+
|
|
101
|
+
## 5. 原始值与派生值
|
|
102
|
+
|
|
103
|
+
使用一个简单问题判断字段边界:
|
|
104
|
+
|
|
105
|
+
> 这个值是由宿主、用户、配置或初始状态直接提供,还是原 VM 已经根据这些事实计算得出?
|
|
106
|
+
|
|
107
|
+
原始值示例:
|
|
108
|
+
|
|
109
|
+
```text
|
|
110
|
+
navigator.userAgent
|
|
111
|
+
screen.width
|
|
112
|
+
mousemove event list
|
|
113
|
+
Date.now sequence
|
|
114
|
+
Math.random initial state
|
|
115
|
+
SDK aid
|
|
116
|
+
signature invocation count before this call
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
派生值示例:
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
UA digest
|
|
123
|
+
behavior bit field
|
|
124
|
+
environment feature vector
|
|
125
|
+
50-byte core
|
|
126
|
+
checksum
|
|
127
|
+
packed material
|
|
128
|
+
RC4 ciphertext
|
|
129
|
+
final encoded token
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
派生值可以作为调试断言和中间对账点,但不能作为对外公开的恢复实现输入。
|
|
133
|
+
|
|
134
|
+
如果一个值是原程序在更早生命周期生成并持久化的,明确选择它是本次调用的 `initialState` 还是必须恢复的上游计算。该选择决定完成声明的起点,不能隐藏。
|
|
135
|
+
|
|
136
|
+
## 6. Oracle 完整性
|
|
137
|
+
|
|
138
|
+
用以下证据确认 Oracle 可作为参考:
|
|
139
|
+
|
|
140
|
+
1. 固定原始文件 Hash,保留原始入口。
|
|
141
|
+
2. 分开原始运行目标和 Trace/插桩派生目标。
|
|
142
|
+
3. 在同一 `RawInput` 和同一运行条件下至少重复执行,确认最终输出稳定。
|
|
143
|
+
4. 输出不稳定时,按时间、随机、存储、网络、异步、共享计数器和运行时补丁查找可变量。
|
|
144
|
+
5. 保存无 Trace 与有 Trace 的 A/B,确认观测没有改变最终输出或明确降低证据等级。
|
|
145
|
+
|
|
146
|
+
只固定一个可变源后输出仍变化,是还有其他状态未受控的证据,不是算法无法恢复的证据。
|
|
147
|
+
|
|
148
|
+
## 7. 精确比较
|
|
149
|
+
|
|
150
|
+
先按实际协议定义比较单位:
|
|
151
|
+
|
|
152
|
+
- 字符串协议:声明字符编码,再比较编码后字节;
|
|
153
|
+
- 原始密文:直接比较字节;
|
|
154
|
+
- JSON 或对象:只在协议不定义文本序列化时才比较解析结构;如果字符顺序就是签名输入,保留原始文本。
|
|
155
|
+
|
|
156
|
+
报告:
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
raw input hash
|
|
160
|
+
source/bytecode hash
|
|
161
|
+
oracle length and hash
|
|
162
|
+
recovered length and hash
|
|
163
|
+
exact equality
|
|
164
|
+
first differing byte offset, when any
|
|
165
|
+
comparison encoding or raw-byte mode
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
使用 `scripts/verify-equivalence.py` 完成这个机械事实。不让比较脚本删除空白、规范化 Unicode、解码 Base64 或改写换行,除非协议和用户明确把这些转换定义为比较前处理。
|
|
169
|
+
|
|
170
|
+
## 8. 受控变体
|
|
171
|
+
|
|
172
|
+
固定基线是主要锚点。当需要确认某个原始字段、分支或中间语义时,设计只改变一个因素的变体:
|
|
173
|
+
|
|
174
|
+
```text
|
|
175
|
+
x0 = baseline raw input
|
|
176
|
+
x1 = x0 with exactly one declared change
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
同时执行 Oracle 和独立实现:
|
|
180
|
+
|
|
181
|
+
```text
|
|
182
|
+
O(x0), R(x0)
|
|
183
|
+
O(x1), R(x1)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
检查:
|
|
187
|
+
|
|
188
|
+
- 变体是否真的只改变一个宿主事实;
|
|
189
|
+
- 原 VM 是否实际读取该变化;
|
|
190
|
+
- 两套实现的最终输出是否继续精确一致;
|
|
191
|
+
- 预期中间字段和下游消费者是否一起改变;
|
|
192
|
+
- 时间或随机调用次数是否因分支改变。
|
|
193
|
+
|
|
194
|
+
变体不是为了堆数量。优先构造能区分竞争性解释、触发关键分支或验证边界的用例。
|
|
195
|
+
|
|
196
|
+
## 9. 中间对账
|
|
197
|
+
|
|
198
|
+
最终输出是验收标准,中间值是定位工具。当 `R(x) !== O(x)` 时,沿共同坐标对账:
|
|
199
|
+
|
|
200
|
+
```text
|
|
201
|
+
raw input read
|
|
202
|
+
→ probe/feature result
|
|
203
|
+
→ digest or material
|
|
204
|
+
→ packing/header/checksum
|
|
205
|
+
→ cipher state or ciphertext
|
|
206
|
+
→ final encoding
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
寻找首个分歧,不只比较最后的密文。首个分歧之后的大量差异通常是下游扩散,不代表多个独立错误。
|
|
210
|
+
|
|
211
|
+
中间对账通过后仍要比较最终输出;最终输出通过后仍要检查独立实现没有从外部读取这些中间值。
|
|
212
|
+
|
|
213
|
+
## 10. 服务器判决
|
|
214
|
+
|
|
215
|
+
区分两个问题:
|
|
216
|
+
|
|
217
|
+
```text
|
|
218
|
+
服务器接受:
|
|
219
|
+
证明请求在当前 Cookie、IP、时间窗口、参数和服务端策略下可用
|
|
220
|
+
|
|
221
|
+
本地精确等价:
|
|
222
|
+
证明独立实现复现了受控原 VM 的计算结果
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
服务器成功可以是产品或补环境任务的最终验收,但不能替代 VMP 语义恢复的对照实验。服务器可能容忍多个等价表示、忽略某些字段,也可能因非算法因素拒绝正确输出。
|
|
226
|
+
|
|
227
|
+
## 11. 完成声明
|
|
228
|
+
|
|
229
|
+
声明完成时写清:
|
|
230
|
+
|
|
231
|
+
```text
|
|
232
|
+
Oracle source and hash
|
|
233
|
+
controlled runtime and mutable-state contract
|
|
234
|
+
RawInput schema and concrete baseline hash
|
|
235
|
+
independent implementation entry point
|
|
236
|
+
forbidden precomputed fields absent from its public input
|
|
237
|
+
oracle/recovered output lengths and hashes
|
|
238
|
+
exact comparison result
|
|
239
|
+
tested variants and static coverage
|
|
240
|
+
known untested or out-of-scope paths
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
允许作出范围清晰的完成声明:
|
|
244
|
+
|
|
245
|
+
> 固定 iv8 基线和已列出变体已完成从原始输入到最终输出的独立精确复现;未覆盖的真实浏览器、异常分支或其他生命周期不在本声明范围。
|
|
246
|
+
|
|
247
|
+
不要因为仍有与该范围无关的 Handler、Record 或 CFG 未高语义化而拒绝收束;也不要因为一个基线成功而隐藏未验证范围。
|