johnzfitch/bun-chop

GitHub: johnzfitch/bun-chop

一款专为 Bun 编译的独立二进制文件设计的反编译与反混淆工具,支持本地 AI 语义重命名和代码往返重组。

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) → cluster modules by dependency graph (Louvain community detection) → organize into semantic directories → readable, organized source code → reassemble back into a working binary (round-trip) ``` 反混淆后的代码不仅可读 —— 而且是**可运行的**。你可以修改单个模块文件,并将它们重新组装回可工作的 Bun 二进制文件中。 ## 快速开始 ``` 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. 构建依赖图 node src/extract-deps.mjs decoded/manifest.json --out deps-graph.json # 6. 聚类模块(扫描 resolutions,选择最佳方案) 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 (可视化) # 7. 标记聚类(创建包含目录名的 cluster-labels.json) # 使用 PNG + 每个聚类的热门函数进行命名。 # 参见下文“Organizing modules”了解格式。 # 8. 组织到语义目录中 node src/organize.mjs decoded/ # → decoded-organized/ 包含命名目录 + INDEX.md ``` 步骤 1-4 是完全自动化的。步骤 5-8 将输出组织到目录中 —— 步骤 7 需要手动标记(或使用 LLM)。 ### 往返:重新组装并运行 在反混淆(并可选地修改)单个模块文件后,将它们重新组装回可工作的二进制文件: ``` # 将反混淆后的模块重组为可运行的 bundle node scripts/build.mjs --source decoded --no-bun-cjs # 运行它 cd /extracted && bun run.js --version ``` `--no-bun-cjs` 标志将代码包装为自执行 IIFE,而不是依赖 Bun 严格的 `@bun-cjs` CJS 加载器,该加载器要求字节级精确的格式,这与任何代码转换都不兼容。 ### 使用 AI 辅助重命名(可选,提高可读性) 在步骤 4 之后,组织之前: ``` # 批量重命名:将每个模块发送给 LLM,一次性获取所有重命名 node src/ai-rename.mjs --dir decoded/ --out renames-ai.json node src/deobfuscate.mjs --dir decoded/ --batch renames-ai.json --only rename # 范围重命名:基于 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 ``` ### 增量流程(更新到新版本) 如果你已经有一个解码版本并希望更新到更新的二进制文件: ``` # 通过基于内容的匹配传输所有 artifacts(重命名、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 部分 (macOS)、附加的 ELF 数据 (Linux) 或 `.bun` PE 部分 (Windows) 中。该部分包含一个 `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`,逗号拆分 2. **lebab** — ES5→ES6+ 现代化(默认跳过 —— 重新组装时 `var`→`let/const` 会导致跨文件冲突) 3. **extract** — 从 `MR()` 导出映射 + `this.name`/`displayName` 模式自动生成重命名映射 4. **rename** — 通过 recast 进行保留格式的 AST 重命名(仅标识符字节发生变化,其他所有内容保持字节相同) 5. **prettier** — 一致的格式化 运行时文件(`00-runtime.js`,`99-main.js`)会自动从 wakaru/lebab/prettier 中排除。在运行时文件中声明的标识符(Bun 的模块系统全局变量,如 `h`、`v`、`y`、`MR`)会自动从重命名中排除 —— 它们被所有模块(包括 vendor)引用。 ### 名称恢复 Bun 的 `__export()` 模式 —— `MR(target, { exportName: () => minifiedVar })` —— 将原始导出名称保留为字符串键。这是名称恢复的最大来源。其他模式:类构造函数中的 `this.name = "X"`,`displayName = "X"` 赋值,以及 20 多个映射的 Bun 运行时辅助程序。 对于剩余的标识符,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 层算法将模块分配到目录: - **Layer 1:** 直接聚类成员资格 - **Layer 2:** 函数级亲和性(来自跨模块调用者/被调用者的多数投票) - **Layer 3:** 清单级亲和性(来自 import/export 依赖项的多数投票) - **Layer 4:** 剩余模块放入 `uncategorized/` ### 跨版本支持 `diff-versions.mjs` 和 `transfer-artifacts.mjs` 使用基于内容的指纹识别(字符串 + 属性 + 导出 —— 从不使用变量名)来跨版本匹配模块,并传递重命名工件、vendor 分类和文件布局。 ## 工具 ### 核心流程 | 脚本 | 描述 | |--------|-------------| | `src/extract.mjs` | 解析 Bun 二进制格式,提取所有嵌入的模块 | | `src/resplit.mjs` | 将包拆分为每个文件一个模块 | | `src/match-vendors.mjs` | Vendor 分类:指纹数据库 + 洪水填充。`--classify`,`--no-move` | | `src/deobfuscate.mjs` | 完整流程:wakaru → lebab → extract → rename → prettier | | `build.mjs`(项目中)| 将模块重新组装成可运行的包。`--no-bun-cjs`,`--run` | ### 名称恢复 | 脚本 | 描述 | |--------|-------------| | `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 段。尾部后的代码签名(约 1.7MB 填充)。 - **Linux**: 附加到 ELF 二进制文件的数据。尾部位于最末尾。 - **Windows**: `.bun` PE 部分。无 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
标签:AI 重命名, AI风险缓解, AST 抽象语法树, Bun, Bun.sh, CMS安全, Decompiler, Deobfuscation, JavaScript, JavaScript 逆向, LLM评估, MCP Server, MITM代理, Ollama, 二进制提取, 云安全监控, 云资产清单, 代码反编译, 依赖图分析, 去混淆, 反混淆工具, 本地大模型, 模块聚类, 混淆还原, 源码恢复, 网络安全, 自定义脚本, 逆向工程, 隐私保护, 静态分析