dolphinwesting248/deob

GitHub: dolphinwesting248/deob

一个通用的 AST 级别 JavaScript 去混淆预处理框架,专为 LLM 辅助逆向工程设计,通过 17 步语义保持变换重构代码结构。

Stars: 0 | Forks: 0

# deob 一个通用的 AST 级别 JavaScript 去混淆预处理框架。所有转换都是**保持语义的** — 它们重组代码而不改变运行时行为。旨在作为**面向 LLM 辅助逆向工程的数据准备步骤**。 - **通用性。** 无需混淆器检测,无需特征匹配。obfuscator.io、JSVMP、webpack bundles、自定义混淆器 — 全部一视同仁。 - **保持语义。** 拆分、展开、简化、内联 — 每一个处理过程都保持原始逻辑不变。仅改变代码结构。 - **面向 LLM。** 结构报告、调用图、字符串警报、词汇查找索引、SQLite 代码索引 — 输出专为 LLM 消费而设计,而不仅仅是为了人类可读性。 ## 快速开始 ``` npm install npm link # 单个文件 deob main.js # → main.deob/main.js deob main.js --split # → main.deob/ (per-function files) deob main.js --metrics # → main.deob/ + metrics.html deob main.js --md --json # → main.deob/ + structure reports deob main.js --index # → main.deob/ + code index # 目录(跨文件汇总) deob src/ --md --json # → src.deob/ + summary.md # Config-driven(自动检测 deob.config.js) deob init # generate config template deob # run with ./deob.config.js deob --config path/to/config.js # explicit config path ``` 所有输出都会进入一个目录: ``` main.deob/ ├── main.js ← deobfuscated code ├── metrics.html ← readability report (--metrics) ├── structure.md ← function inventory + hotspots + alerts (--md) ├── structure.json ← machine-readable (--json) └── .index/ ← code intelligence index (--index) ``` ## CLI 参考 ``` deob auto-detect deob.config.js in cwd deob [output-dir] [options] deob --config deob init [--force] ``` | 标志 | 输出 | 描述 | |------|--------|-------------| | (默认) | `main.js` | 单个去混淆文件 | | `--split` | 按函数拆分的文件 | 每一个 `_sub_` 函数都在单独的文件中,按父级分组 | | `--metrics` | `metrics.html` | 使用 Chart.js 进行转换前后的可读性对比 | | `--md` | `structure.md` | 函数清单、调用图、热点、警报、查找索引 | | `--json` | `structure.json` | 与 `--md` 内容相同,格式为机器可读的 JSON | | `--index` | `.index/` | 用于 AI 辅助探索的 SQLite 知识图谱 | | `--config ` | — | 从配置文件加载选项,忽略其他标志 | | `init` | `deob.config.js` | 在当前目录生成配置模板 | **目录输入:** 独立处理每一个 `.js` 文件,随后生成包含跨文件热点、合并警报以及组合查找索引的 `summary.md` / `summary.json`。 **配置格式**(`deob init` 生成模板): ``` module.exports = { input: "src/main.js", // file, directory, or array // input: ["a.js", "b.js", "sub/"], // output: "out/", // optional split: false, metrics: false, md: true, json: false, index: false, }; ``` ## 结构报告章节 | 章节 | 内容 | |---------|---------| | Summary (摘要) | 函数总数、子函数/原始函数细分、最大嵌套深度、提取类型 | | Hotspots (热点) | 调用最频繁的函数、根入口点、叶子终端、热点组 | | Hot Groups (热点组) | 具有最多跨函数调用边的目录 | | Quick Lookup (快速查找) | 单词 → 函数索引(将 `_sub_program_init_vars` 拆分为 `program` · `init` · `vars`) | | String Alerts (字符串警报) | 与安全相关的模式:API endpoint、token、加密、eval、存储、DOM sink | | Call Graph (调用图) | 跨函数调用的 Mermaid 图表 | | Function Inventory (函数清单) | 包含名称、行数、参数、调用、被调用的完整表格 | ## 代码索引 使用 `node:sqlite` + `@babel/traverse` 构建 SQLite 知识图谱。 **Schema:** `nodes`(函数、类、变量)、`edges`(调用、包含、引用)、FTS5 搜索。 **针对去混淆输出的优化:** - 跳过 `index.js` 胶水文件 - 为每个节点标记 `metadata.group`(父目录) - 从混淆标识符中过滤掉无意义的 `MemberExpression` 引用 **查询示例:** ``` SELECT name, file_path FROM nodes WHERE json_extract(metadata, '$.group') = 'misc' AND kind = 'function'; SELECT target, COUNT(*) as c FROM edges WHERE kind = 'calls' GROUP BY target ORDER BY c DESC LIMIT 10; ``` ## Pipeline | 步骤 | 处理过程 | 描述 | |------|------|-------------| | 1 | `traverse` | 收集所有函数节点,从最内层开始处理 | | 2 | `wrapper` | 从逗号链中提取顶层的 IIFE | | 3 | `hoist` | 将 var/let/const/function 移动到每个作用域的顶部 | | 4 | `extract-inline` | 提取嵌入式函数表达式(return、赋值、IIFE、MemberExpression) | | 5 | `simplify` | 折叠常量,简化布尔值,折叠字符串操作,标准化 AST | | 6 | `short-circuit` | 将 `A\|\|B\|\|(C,D)` 转换为 `if(!A&&!B){C;D;}`,三元表达式转换为 if/else,`var x=cond?a:b` 转换为 if/else | | 7 | `expand-seq` | 将逗号链拆分为独立的语句 | | 8 | `short-circuit` | 第二次处理 — 捕获由逗号拆分暴露出的 LogicalExpression | | 9 | `dead-code` | 移除 if(false)、return 后的不可达代码、空的 catch | | 10 | `inline-props` | 用字面量值替换 config.PROP | | 11 | `unused` | 移除从未被引用的辅助函数 | | 12 | `conditions` | 简化 `a?true:false→!!a`,if/return 模式 | | 13 | `wrappers` | 内联纯粹的 wrapper 函数 | | 14 | `call-tree` | 拓扑排序:被调用者在调用者之前 | | 15 | `single-caller` | 内联仅从一个地方调用的函数 | | 16 | `normalize` | 多重声明拆分,链式赋值拆分,for(;;) 转换为 while(true) | | 17 | `extract-inline` | 第二次处理 — 捕获因重构暴露出的模式 | ## 输出示例 所有示例均根据实际的 pipeline 输出进行了验证。 ### 逗号操作符展开 + 内联函数提取 ``` // Input function a0_0x5465(_0x147aca,_0x1c469e){var _0x477d9d=a0_0x1cb6();return (a0_0x5465=function(_0x593f2d,_0x4d5e1e){var _0x2a8c=_0x477d9d[_0x593f2d];return _0x2a8c?_0x2a8c(_0x4d5e1e,_0x147aca):_0x4d5e1e}),a0_0x5465(_0x147aca,_0x1c469e)} // Output function a0_0x5465(_0x147aca, _0x1c469e) { var _0x477d9d = a0_0x1cb6(); a0_0x5465 = _sub_return_fn1; return a0_0x5465(_0x147aca, _0x1c469e); } function _sub_return_fn1(_0x593f2d, _0x4d5e1e, _0x477d9d, _0x147aca) { var _0x2a8c = _0x477d9d[_0x593f2d]; return _0x2a8c ? _0x2a8c(_0x4d5e1e, _0x147aca) : _0x4d5e1e; } ``` ↑ `return (a=fn, b)` → 两个语句;内联的 `function` 被提取至 `_sub_return_fn1`,外部引用作为参数传入。 ### 短路 polyfill → if 块 ``` // Input "undefined"==typeof Element||Element.prototype.addEventListener||(u=[],Ao=function(n,t){for(var e=0;e` | 父函数名、方法名,或对于匿名函数使用 `lnXXXX` | | `` | 两位数的提取顺序 | | `` | `if`、`else`、`try`、`catch`、`init_vars`、`iife_body`... | ## API ``` const { main } = require("./scripts"); main({ input: "obfuscated.js", output: "out/", split: true }); ``` ## 目录结构 ``` deob.js ← CLI entry point scripts/ ├── pipeline.js ← Main orchestration (17 passes) ├── extract.js ← Syntactic splitting (IIFE, try-catch, if-else, switch, …) ├── passes.js ← All post-processing passes ├── traverse.js ← Innermost-first function collection ├── metrics.js ← Readability analysis + HTML Chart.js report ├── structure.js ← Function inventory, hotspots, alerts, lookup index ├── ast-utils.js ← AST walker, detectors, clone ├── scope.js ← Variable scope & external reference analysis ├── emit.js ← Sub-function declaration builder ├── naming.js ← Naming convention helpers ├── wrapper.js ← Top-level IIFE extraction ├── config.js ← Parser, generator, globals ├── index.js ← Public API exports └── indexer/ ← Code intelligence indexer ├── index.js ← Orchestration: scan → extract → store → resolve ├── extract.js ← Babel-based JS symbol & call-graph extractor ├── schema.js ← SQLite schema └── store.js ← node:sqlite database operations ``` ## License ISC
标签:CMS安全, JavaScript, LLM辅助, MITM代理, 云安全监控, 云资产清单, 代码反混淆, 数据可视化, 自定义脚本, 逆向工程, 静态分析