# Wasm Reverse

> WebAssembly (WASM) 逆向分析（提取→反汇编→动态分析→算法还原/直接调用）。 TRIGGER when: 用户遇到 WASM 加密/保护、需要分析 .wasm 文件、网页中有 WebAssembly.instantiate 调用、加密逻辑在 WASM 模块中。包括但不限于"WASM逆向"、"WebAssembly分析"、"加密在wasm里"、"wasm怎么分析"、"反编译wasm"。 DO NOT TRIGGER when: 只是普通 JS 混淆（用 ast-deobfuscate）、或 Native SO 层分析（用 android-app-reverse）。

- Skill: `zxzvsdcj/wasm-reverse` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add zxzvsdcj/wasm-reverse`
- Raw SKILL.md: https://api.skillmd.com/api/skills/zxzvsdcj/wasm-reverse/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: zxzvsdcj (https://skillmd.com/u/zxzvsdcj)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/zxzvsdcj/wasm-reverse

---


# wasm-reverse

对 **$ARGUMENTS** 执行 WASM 逆向分析。

**工具链**:
- `wasm2wat` / `wasm-objdump` / `wasm-decompile` (WABT 工具集)
- `ghidra-mcp`（反编译，可选）
- `js-reverse-mcp`（动态分析 JS↔WASM 交互）

---

## 分析流程

### Step 1: 提取 WASM 模块

```
方式 A: 从网页提取
  1. list_network_requests → 筛选 .wasm 文件请求
  2. 或 search_in_sources("WebAssembly") → 找到 instantiate/compile 调用
  3. save_script_source 保存 WASM 文件（如果是通过脚本加载）
  4. 或直接 curl 下载 .wasm URL

方式 B: 从 JS bundle 中提取
  某些打包工具将 WASM 编码为 Base64 嵌入 JS 中:
  1. search_in_sources("data:application/wasm") → 找到嵌入的 WASM
  2. 提取 Base64 字符串 → 解码保存为 .wasm

方式 C: 本地文件
  直接分析用户提供的 .wasm 文件
```

### Step 2: 静态分析

#### 2.1 基础信息

```bash
# 查看 WASM 模块信息
wasm-objdump -h module.wasm      # 段信息
wasm-objdump -x module.wasm      # 导入/导出详情
wasm-objdump -d module.wasm      # 反汇编

# 转为文本格式 (WAT)
wasm2wat module.wasm -o module.wat

# 反编译为伪 C 代码
wasm-decompile module.wasm -o module.dcmp
```

#### 2.2 关键信息提取

```
导出函数 (exports):
  - 这些是 JS 可以直接调用的函数
  - 通常加密函数会在这里暴露
  - wasm-objdump -j Export -x module.wasm

导入函数 (imports):
  - WASM 需要宿主(JS)提供的函数
  - 通常包含内存操作、环境 API
  - 需要在 instantiate 时提供

内存 (Memory):
  - WASM 的线性内存
  - 输入/输出数据通过内存传递

字符串:
  - wasm-objdump -j Data -x module.wasm
  - 数据段中可能包含密钥、算法常量
```

#### 2.3 识别加密算法

在 WASM 反编译/反汇编中搜索特征常量：

| 常量 | 算法 |
|------|------|
| `0x67452301`, `0xEFCDAB89` | MD5 初始值 |
| `0x6A09E667`, `0xBB67AE85` | SHA-256 初始值 |
| `0x5A827999`, `0x6ED9EBA1` | SHA-1 K 值 |
| `0x63`, `0x7C`, `0x77`, `0x7B` | AES S-Box |
| `0x428A2F98`, `0x71374491` | SHA-256 K 值 |

### Step 3: 动态分析（JS ↔ WASM 交互）

用 js-reverse-mcp 追踪 JS 如何调用 WASM：

```
1. search_in_sources("WebAssembly.instantiate")
   → 找到 WASM 加载和初始化代码

2. 分析 imports 对象:
   WebAssembly.instantiate(wasmBytes, {
     env: {
       memory: new WebAssembly.Memory(...),
       __memory_base: 0,
       // ... JS 提供给 WASM 的函数
     }
   })

3. 在 JS 调用 WASM 导出函数处设断点:
   set_breakpoint_on_text("instance.exports.encrypt")
   → 观察输入参数如何写入 WASM 内存
   → 观察输出如何从 WASM 内存读取

4. trace_function 追踪导出函数调用:
   trace_function(scriptId, lineNumber)
   → 监控每次调用的参数
```

#### 3.1 内存交互分析

JS 和 WASM 通过线性内存通信：

```javascript
// 典型模式: JS 写入输入 → 调用 WASM → 读取输出

// 写入字符串到 WASM 内存
var inputPtr = instance.exports.malloc(input.length);
var mem = new Uint8Array(instance.exports.memory.buffer);
for (var i = 0; i < input.length; i++) {
    mem[inputPtr + i] = input.charCodeAt(i);
}

// 调用 WASM 加密函数
var outputPtr = instance.exports.encrypt(inputPtr, input.length);

// 读取输出
var output = '';
for (var i = 0; outputPtr + i < mem.length && mem[outputPtr + i] !== 0; i++) {
    output += String.fromCharCode(mem[outputPtr + i]);
}
```

**在断点处**用 `evaluate_script` 检查：
```javascript
// 查看 WASM 内存中的数据
new Uint8Array(instance.exports.memory.buffer, ptr, length)
```

### Step 4: 算法还原或直接调用

#### 方案 A: 还原算法（适用于标准加密）

如果识别出标准算法（MD5/SHA/AES），直接用 Python 标准库实现：

```python
# 如果是 SHA-256
import hashlib
result = hashlib.sha256(data).hexdigest()
```

#### 方案 B: 直接调用 WASM（推荐，适用于复杂/自定义算法）

##### Python (wasmer)

```python
from wasmer import engine, Store, Module, Instance, ImportObject, Function, Memory, MemoryType
import ctypes

store = Store()
module = Module(store, open("module.wasm", "rb").read())

# 构建 imports（如果 WASM 需要）
import_object = ImportObject()
# import_object.register("env", {"log": Function(store, log_func)})

instance = Instance(module, import_object)
memory = instance.exports.memory

# 写入输入
input_data = b"data_to_encrypt"
ptr = instance.exports.malloc(len(input_data))
mem_view = memory.uint8_view(offset=ptr)
for i, b in enumerate(input_data):
    mem_view[i] = b

# 调用加密
result_ptr = instance.exports.encrypt(ptr, len(input_data))

# 读取输出
output = bytes(memory.uint8_view(offset=result_ptr)[:32])
print(output.hex())
```

##### Node.js

```javascript
const fs = require('fs');
const wasmBuffer = fs.readFileSync('module.wasm');

(async () => {
    const module = await WebAssembly.compile(wasmBuffer);
    const instance = await WebAssembly.instantiate(module, {
        env: {
            memory: new WebAssembly.Memory({ initial: 256 }),
            // ... 其他 imports
        }
    });

    const { encrypt, memory, malloc } = instance.exports;
    
    const input = new TextEncoder().encode("data_to_encrypt");
    const ptr = malloc(input.length);
    new Uint8Array(memory.buffer, ptr, input.length).set(input);
    
    const resultPtr = encrypt(ptr, input.length);
    const result = new Uint8Array(memory.buffer, resultPtr, 32);
    console.log(Buffer.from(result).toString('hex'));
})();
```

---

## 反模式

- **不要忽略 imports** — 很多 WASM 模块依赖宿主提供的函数（如内存分配、环境 API），直接调用会失败。
- **不要假设内存布局** — 不同编译器（Emscripten/Rust/Go）的内存管理方式不同，需要分析 JS glue code 理解约定。
- **不要直接修改 WASM 字节码** — 除非非常了解 WASM 二进制格式，否则用 WAT 文本格式修改后再编译回来。
- **优先直接调用而非还原** — WASM 中的自定义算法还原成本高，直接用 Python/Node.js 加载 WASM 模块调用更高效。

---

## 完成标准

```
WASM 分析结果：
- 文件：module.wasm (XX KB)
- 导出函数：encrypt(ptr, len) → ptr
- 算法类型：[标准算法 | 自定义算法]
- 调用方案：[Python 还原 | Python/Node.js 直接调用 WASM]
- 验证：相同输入 → 相同输出
```

## References

| 文件 | 何时读取 |
|------|---------|
| `references/wasm-tools.md` | WABT 工具集安装和详细用法 |
| `references/wasm-js-bridge.md` | JS ↔ WASM 通信模式和内存管理详解 |

