vicnaum/bun-demincer
GitHub: vicnaum/bun-demincer
针对 Bun 编译的独立 JavaScript 二进制文件的反编译与反混淆工具,可提取源码、恢复标识符并重建可读的项目结构。
Stars: 0 | Forks: 0
# bun-demincer
用于 [Bun](https://bun.sh) 编译的独立 JavaScript 二进制文件的反编译器、还原器和反混淆器。
从 Bun 的二进制格式中提取嵌入的 JavaScript 源代码,将其拆分为单个模块,识别 vendor (npm) 包,恢复原始标识符,并将所有内容组织成可读、结构化的代码库 —— 所有操作均基于单个编译后的二进制文件。
## 功能介绍
```
Bun binary (opaque executable)
→ extract embedded JS + assets
→ split into individual modules (1 file per module)
→ classify vendor vs app modules (fingerprint DB + flood-fill)
→ deobfuscate (structural transforms + name recovery + formatting)
→ reconstruct ES import/export statements
→ cluster modules by dependency graph (Louvain community detection)
→ organize into semantic directories
→ readable, organized source code
```
## 快速开始
```
npm install
```
### 完整流程(冷启动 —— 对二进制文件无先验知识)
```
# 1. 从 Bun 二进制文件中提取 JS
node src/extract.mjs /path/to/bun-binary extracted/
# 2. 拆分为独立模块
node src/resplit.mjs extracted/bundle.js resplit/
# 3. 通过指纹库识别 Vendor 包
node src/match-vendors.mjs resplit/ --db data/vendor-fingerprints-1000.json --classify
# 4. 反混淆(结构变换 + 自动提取重命名 + 格式化)
cp -r resplit/ decoded/
node src/deobfuscate.mjs --dir decoded/
# 5. 重建 ES imports/exports
node src/reconstruct-imports.mjs decoded/
# 6. 构建 Dependency graph
node src/extract-deps.mjs decoded/manifest.json --out deps-graph.json
# 7. 聚合模块(扫描解析结果,选择最佳项)
node src/cluster-graph.mjs deps-graph.json --sweep
node src/cluster-graph.mjs deps-graph.json --pick 1.5 --png
# → clusters-core.json(聚合成员)
# → clusters.png(可视化)
# 8. 标记聚合(创建包含目录名称的 cluster-labels.json)
# 使用 PNG 及每个聚合的热门函数进行命名。
# 请参阅下方的“Organizing modules”了解格式。
# 9. 整理为语义化目录
node src/organize.mjs decoded/
# → decoded-organized/(包含命名目录) + INDEX.md
```
步骤 1-5 是全自动化的。步骤 6-9 将输出组织到目录中 —— 步骤 8 需要手动标记(或使用 LLM)。
### 配合 AI 辅助重命名(可选,提高可读性)
在步骤 5 之后,组织之前:
```
# 批量重命名:将每个模块发送给 LLM,一次性获取所有重命名
node src/ai-rename.mjs --dir decoded/ --out renames-ai.json
node src/deobfuscate.mjs --dir decoded/ --batch renames-ai.json --only rename
# Scoped 重命名:基于 AST 上下文的逐标识符操作(质量更高,API 调用更多)
node src/ai-rename-scoped.mjs --dir decoded/ --out renames-scoped.json
node src/deobfuscate.mjs --dir decoded/ --batch renames-scoped.json --only rename
```
### 增量流程(更新到新版本)
如果您已经有一个解码版本并希望更新到更新的二进制文件:
```
# 通过基于内容的匹配迁移所有构建产物(重命名、Vendor 标记、布局)
node src/transfer-artifacts.mjs new-version/ --reference old-version/
# 或直接应用旧版本的文件布局
node src/apply-reference-layout.mjs new-decoded/ --reference old-decoded-organized/
```
## 前置条件
- **Node.js** (v18+)
- **Bun**(可选 —— 仅在*运行*提取的代码时需要,而非反编译)
## 工作原理
### 二进制格式
Bun 独立可执行文件将所有 JavaScript 嵌入在 `__BUN` Mach-O section(macOS)、附加的 ELF 数据或 `.bun` PE section(Windows)中。该 section 包含一个 `StandaloneModuleGraph`:
```
[8-byte size header (u64 LE)]
[data buffer: source code, bytecode, native addons, wasm modules...]
[module table: array of CompiledModuleGraphFile structs (52 bytes each)]
[Offsets struct (32 bytes)]
[\n---- Bun! ----\n]
```
即使使用 `--bytecode` 编译,完整的 JavaScript 源代码也总是存储在字节码旁边(JSC 需要它)。`--bytecode` 标志是一种启动优化,而非混淆。
有关全面的 Bun 打包器内部机制,请参阅 [docs/BUN.md](docs/BUN.md)。
### 模块拆分
`resplit.mjs` 检测 Bun 的模块包装器模式:
- **`y((exports, module) => { ... })`** — CJS 模块 (`__commonJS`)
- **`h(() => { ... })`** — ESM 懒加载初始化器 (`__esm`)
输出每个模块一个扁平文件,附带依赖图和导出映射。
### Vendor 分类
`match-vendors.mjs --classify` 使用属性名称和字符串字面量的指纹数据库(这些在压缩后依然存在)来识别 npm 包。然后通过反向调用者漫灌算法传播:如果某个模块的所有调用者都已经是 vendor,则该模块也是 vendor。
指纹数据库(`data/vendor-fingerprints-1000.json`,26MB)覆盖了来自 1,668 个 npm 包的 23,746 个文件。可以使用 `--rebuild-db --npm-dir /path/to/node_modules` 进行扩展。
### 反混淆流程
1. **wakaru** — 结构转换:`!0`→`true`,`void 0`→`undefined`,逗号拆分,`var`→`const/let`
2. **lebab** — ES5→ES6+ 现代化
3. **extract** — 从 `MR()` 导出映射 + `this.name`/`displayName` 模式自动生成重命名映射
4. **rename** — 通过 Babel 进行基于 AST 的标识符重命名(批量 JSON 文件)
5. **prettier** — 统一格式化
### 名称恢复
Bun 的 `__export()` 模式 —— `MR(target, { exportName: () => minifiedVar })` —— 将原始导出名称保留为字符串键。这是名称恢复的最大来源。其他模式包括:类构造函数中的 `this.name = "X"`,`displayName = "X"` 赋值,以及 20 多个映射的 Bun runtime 辅助函数。
对于其余标识符,AI 辅助重命名(`ai-rename.mjs`,`ai-rename-scoped.mjs`)使用 LLM 从上下文推断语义名称。
### 组织模块
反混淆后,模块是扁平的编号文件。组织流程将它们转换为有意义的目录结构:
1. **`extract-deps.mjs`** 构建函数级依赖图(哪个模块调用哪个模块)
2. **`cluster-graph.mjs --sweep`** 以 14 种分辨率运行 Louvain 社区检测并显示对比表 —— 模块度分数、集群数量、大小分布
3. **`cluster-graph.mjs --pick `** 选择一个分辨率并输出 `clusters-core.json`(成员资格)+ PNG 可视化
4. **您创建 `cluster-labels.json`** — 根据顶级函数命名每个集群:
{
"clusters": {
"0": { "directory": "ui", "label": "UI rendering" },
"1": { "directory": "api", "label": "API client" }
}
}
5. **`organize.mjs`** 使用 4 层算法将模块分配到目录:
- **第 1 层:** 直接集群成员资格
- **第 2 层:** 函数级亲和力(来自跨模块调用者/被调用者的多数表决)
- **第 3 层:** 清单级亲和力(来自导入/导出依赖关系的多数表决)
- **第 4 层:** 其余模块放入 `uncategorized/`
### 跨版本支持
`diff-versions.mjs` 和 `transfer-artifacts.mjs` 使用基于内容的指纹识别(字符串 + 属性 + 导出 —— 绝不使用变量名)来跨版本匹配模块,并传递重命名构件、vendor 分类和文件布局。
## 工具
### 核心流程
| 脚本 | 描述 |
|--------|-------------|
| `src/extract.mjs` | 解析 Bun 二进制格式,提取所有嵌入的模块 |
| `src/resplit.mjs` | 将包拆分为单模块单文件。`--reassemble` 用于重组 |
| `src/match-vendors.mjs` | Vendor 分类:指纹数据库 + 漫灌算法。`--classify`,`--no-move` |
| `src/deobfuscate.mjs` | 完整流程:wakaru → lebab → extract → rename → prettier |
| `src/reconstruct-imports.mjs` | 转换内部标记 → ES import/export 语句 |
### 名称恢复
| 脚本 | 描述 |
|--------|-------------|
| `src/rename.mjs` | AST 感知标识符重命名。单个、批量 JSON,`--dry-run` |
| `src/extract-exports.mjs` | 自动提取 `MR()` 导出映射 → 重命名 JSON |
| `src/extract-names.mjs` | 从 `this.name="X"` + `displayName="X"` 模式提取重命名 |
| `src/extract-tools.mjs` | 从 `userFacingName()` 模式提取名称 |
| `src/extract-errors.mjs` | 从工厂模式提取错误类名 |
| `src/ai-rename.mjs` | AI 语义重命名。可恢复,并发 |
| `src/ai-rename-scoped.mjs` | 作用域排序的逐标识符 AI 重命名(humanify 风格) |
### 组织
| 脚本 | 描述 |
|--------|-------------|
| `src/extract-deps.mjs` | 函数级依赖图。`--query`,`--stats`,`--dot` |
| `src/cluster-graph.mjs` | Louvain 聚类 + PNG 可视化。`--sweep`,`--pick`,`--png` |
| `src/organize.mjs` | 通过集群成员资格 + 亲和力投票将模块分配到目录 |
### 跨版本
| 脚本 | 描述 |
|--------|-------------|
| `src/diff-versions.mjs` | 跨版本差异对比:指纹识别 → 匹配 → 规范化 → 差异 |
| `src/transfer-artifacts.mjs` | 通过基于内容的模块匹配将构件传输到新版本 |
| `src/apply-reference-layout.mjs` | 应用参考版本的文件布局(目录、文件名、vendor 标志) |
## 平台说明
- **macOS**: `__BUN`/`__bun` Mach-O segment。尾部有代码签名(~1.7MB 填充)。
- **Linux**: 数据附加到 ELF 二进制文件。尾部位于最末端。
- **Windows**: `.bun` PE section。无 8 字节大小头。
- 原生 `.node` 插件是平台特定的。JS 和 WASM 是可移植的。
## 项目结构
```
src/ 18 pipeline scripts (all standalone, no cross-imports)
data/
vendor-fingerprints-1000.json Vendor fingerprint DB (26MB, 1,668 packages)
docs/
BUN.md Bun bundler internals & deobfuscation strategies
```
## 许可证
MIT
标签:AST 抽象语法树, Bun, CMS安全, DNS枚举, JavaScript, MITM代理, WebSocket, 二进制分析, 云安全监控, 云安全运维, 云资产清单, 代码反混淆, 依赖分析, 反编译器, 反迷你化, 可执行文件分析, 模块化重构, 源码恢复, 社区发现算法, 网络安全工具, 自定义脚本, 自定义脚本, 软件开发, 逆向工程, 静态分析