glizzykingdreko/botdeflector-deobfuscator

GitHub: glizzykingdreko/botdeflector-deobfuscator

基于 Babel AST 的 BotDeflector JavaScript 脚本反混淆工具,通过在沙箱中重建字符串解码器将混淆代码还原为可读源码。

Stars: 1 | Forks: 0

# botdeflector-deobfuscator
Status: Active Type: Reverse Engineering License: MIT GitHub stars GitHub repo

TakionAPI
针对 **BotDeflector** 客户端脚本 `pow.js` 和 `api.js` 的 Babel AST 反混淆工具。它在 sandbox 中重建字符串数组解码器,将每个解码器调用还原为其返回的字面量,随后删除这些脚手架代码,让你得到的是可读的代码,而不是五千次重复的 `a0_0x3b8e(0x1f3)`。 [![BotDeflector Captcha](https://takionapi.tech/blog/understanding-and-bypassing-botdeflector/cover.webp)](https://takionapi.tech/bypass/botdeflector) BotDeflector 也是 **Queue-it** 的 proof-of-work 和 icon challenge 背后的引擎,因此该工具同样适用于处理来自 `challenge.queue-it.net` 的 bundle。 请务必[阅读相关文章](https://takionapi.tech/blog/understanding-and-bypassing-botdeflector) ## 目录 ## 反混淆了哪些内容 BotDeflector 通过带有 string-array 编码的 [javascript-obfuscator](https://github.com/javascript-obfuscator/javascript-obfuscator) 发布其脚本。这意味着在你和源码之间隔着三样东西: - 一个 **string array**,保存了 bundle 中的所有字面量 - 一个 **hex accessor**,通过 offset 从中读取数据,例如 `a0_0x3b8e(0x1f3)` - 一个 **rotator IIFE**,在加载时打乱数组,因此静态读取会得到错误的字符串 这是一种毫无意义的混淆,逆向起来非常简单,但在进行其他操作之前,你仍然必须先将其还原。一旦字符串还原完毕,`pow.js` 读起来就像普通代码一样,它所实现的 Cuckoo Cycle 也就清晰地展现在你面前。 ## 核心逻辑简述 ### 1. 通过形状定位脚手架,而非名称 标识符在每次构建时都会改变,因此匹配 `a0_0x42b6` 毫无意义。请匹配形状: - **array function**,一个 0 参数的 `FunctionDeclaration`,其主体声明了一个由字符串字面量组成的大数组 - **accessor**,一个 2 参数的顶层 `FunctionDeclaration`,它引用了 array function - **rotator**,一个 `CallExpression`,其被调用者是一个接收 array function 并执行经典的由 `parseInt` 驱动的 `push(shift())` 洗牌操作的函数 ### 2. 仅提取 rotator 这是让简单的反混淆工具栽跟头的地方,因此值得为它单独列出一个步骤。rotator 经常被作为 **顶层 `SequenceExpression` 的第一个元素出现,而该表达式的另一个元素是整个应用程序**。如果你抓取整个序列并运行它,你也会运行应用程序,这会再次旋转或改变数组,导致之后你解码的每个字符串都是垃圾数据。 因此,请匹配树中任意位置的 `CallExpression` 本身,而不是其父节点: ``` traverse(ast, { CallExpression(path) { const usesArray = path.node.arguments.some(a => t.isIdentifier(a) && a.name === arrayFnName); const calleeIsFn = t.isFunctionExpression(path.node.callee) || t.isArrowFunctionExpression(path.node.callee); if (usesArray && calleeIsFn) { const code = generate(path.node.callee).code; if (/parseInt/.test(code) && /push|shift/.test(code)) { rotatorCall = path.node; path.stop(); } } }, }); ``` ### 3. 在 sandbox 中重建解码器 将 array function、accessor 和 rotator 放入一个 `vm` 上下文中,只运行这三个部分而不运行其他任何内容,然后暴露出 accessor: ``` vm.runInContext(setupCode + `\nthis.__decode = ${accessorFnName};`, sandbox, { timeout: 5000 }); // [+] decoder ready. sample: a0_0x3b8e(0x1f3) = "exponentialRampToValueAtTime" ``` 真正的解码器会执行核心工作,这意味着无论构建时使用了何种 offset 和 key 处理方式,你都能将其完整继承。 ### 4. 收集所有别名,直到 fixpoint Bundle 会针对每个作用域重新绑定解码器,如 `const _0xlocal = a0_0x3b8e;`,有时甚至会对别名进行别名化。一次遍历是不够的,因此需要不断迭代,直到没有新内容出现为止。 ### 5. 折叠调用 每个带有字面量参数的调用都会变为其返回的字符串。带有非字面量参数的调用,如 `C(someVar)`,则保持原样,因为它们无法进行静态解析。 ### 6. 删除脚手架并进行清理 一旦字符串被内联,array function、accessor、aliases 和 rotator 都变成了无用负载。接下来是两项听起来微不足道但实际上很重要的清理工作:`'a' + 'b'` 折叠为 `'ab'`,以及 `obj['prop']` 转换为 `obj.prop`。 ## 安装 ``` git clone https://github.com/glizzykingdreko/botdeflector-deobfuscator cd botdeflector-deobfuscator npm install ``` 运行验证器以确认一切正常: ``` npm test # 10/10 通过 ``` 测试会构建一个合成的混淆 bundle(包含 rotation trap),并断言字符串已还原、脚手架已删除且应用程序代码完好无损。本仓库中未引入任何 BotDeflector 的代码。 ## 作为 node 模块使用 ``` const { deobfuscate } = require('botdeflector-deobfuscator'); const fs = require('fs'); const { code, stats, decoder } = deobfuscate(fs.readFileSync('pow.js', 'utf8'), { onLog: (m) => console.error('[+]', m), }); fs.writeFileSync('pow.deob.js', code); console.log(stats); // { original: 142313, deobfuscated: 98204, replaced: 1847, unresolved: 3, aliases: 12 } ``` ## CLI 用法 ``` # direct node bin/cli.js input/pow.js output/pow.deob.js # 附带一份结构化报告 node bin/cli.js --input input/pow.js --output output/pow.deob.js --report output/report.json ``` | flag | 含义 | | --- | --- | | `--input ` | 位置参数输入的替代方案 | | `--output ` | 位置参数输出的替代方案,默认为 `.deob.js` | | `--report ` | 将统计信息和解码器元数据写入为 JSON | | `--log-level ` | `DEBUG \| INFO \| NONE`,默认为 `INFO` | | `--no-tidy` | 跳过字符串折叠和括号到点号的重写 | | `-h`, `--help` | 使用说明 | | exit code | 含义 | | --- | --- | | 0 | 正常运行,所有内容均已解析 | | 1 | 致命错误:错误的输入、缺失脚手架、解析失败 | | 2 | 已完成,但部分解码器调用无法进行静态解析 | ## 相关工作 - [botdeflector-pow](https://github.com/glizzykingdreko/botdeflector-pow):此反混淆工具揭示的 Cuckoo Cycle proof of work,已用 Node、Python 和 Go 实现,并为每种语言提供了验证器。 - [new-datadome-deobfuscator](https://github.com/glizzykingdreko/new-datadome-deobfuscator):针对 DataDome 的相同思路实现,工作量要大得多。 - [AWS-WAF-Deobfuscator](https://github.com/glizzykingdreko/AWS-WAF-Deobfuscator)、[Incapsula-utmvc-Deobfuscator](https://github.com/glizzykingdreko/Incapsula-utmvc-Deobfuscator)、[PerimeterX-Deobfuscator](https://github.com/glizzykingdreko/PerimeterX-Deobfuscator):我发布的其他 AST 反混淆工具。 ## 与我联系 如果你觉得这个工具有用,可以在 GitHub 和 Medium 上关注我,以便在我发布文章或开源项目时收到通知。 - [GitHub](https://github.com/glizzykingdreko) - [Twitter](https://mobile.twitter.com/glizzykingdreko) - [Medium](https://medium.com/@glizzykingdreko) - [Email](mailto:glizzykingdreko@protonmail.com) - [TakionAPI](https://takionapi.tech) - [请我喝杯咖啡 ❤️](https://www.buymeacoffee.com/glizzykingdreko) ## 许可证 MIT,详见 [LICENSE](./LICENSE)。
标签:Babel AST, CMS安全, JavaScript, MITM代理, 云资产清单, 反混淆, 域环境探测, 数据可视化, 网络调试, 自动化, 自定义脚本, 逆向工程, 验证码绕过