maskop9/proxydllgenerator

GitHub: maskop9/proxydllgenerator

一款自动化生成代理 DLL 以实现 DLL 劫持并执行自定义 shellcode 的安全测试工具。

Stars: 23 | Forks: 10

# proxydllgenerator 一款用于自动化构建代理 DLL 以进行 DLL 劫持的 Python 工具。 给定一个 DLL 和原始的 shellcode payload,它会生成一个替代 DLL,该 DLL 会: - **转发**所有命名的导出函数到真实的 DLL,通过运行时 `LoadLibrary` 加汇编 JMP stub 实现——无需重命名原始 DLL。 - **执行** shellcode,在 `DLL_PROCESS_ATTACH` 时从 `DllMain` 中生成一个专门的线程来运行。 - **可选加密**嵌入的 shellcode,使用 AES-CBC 加密,并在运行时使用 Windows BCrypt API 进行解密。 编译由 **MinGW-w64** 交叉编译器执行,因此该工具可以在 Linux、macOS 和 Windows 上运行,而不受主机架构的限制。 ## 前置条件 ### Python 3.9+ ``` python3 -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install -r requirements.txt ``` | Package | Purpose | |---------|---------| | `pefile >= 2023.2.7` | 解析 PE 导出目录 | | `pycryptodome >= 3.18.0` | AES-CBC shellcode 加密(仅在使用 `--encrypt` 或 `--aes-key` 时需要) | ### MinGW-w64 交叉编译器 | Target | Binary required | |--------|----------------| | AMD x64 | `x86_64-w64-mingw32-gcc` | | AMD x86 | `i686-w64-mingw32-gcc` | **Ubuntu / Debian** ``` sudo apt-get install mingw-w64 ``` **Fedora / RHEL** ``` sudo dnf install mingw64-gcc mingw32-gcc ``` **Arch Linux** ``` sudo pacman -S mingw-w64-gcc ``` **macOS** ``` brew install mingw-w64 ``` **Windows (MSYS2)** ``` pacman -S mingw-w64-x86_64-gcc mingw-w64-i686-gcc ``` 将 `C:\msys64\mingw64\bin` 和 `C:\msys64\mingw32\bin` 添加到 `PATH` 中。 ## 安装说明 ``` git clone https://github.com/maskop9/proxydllgenerator cd proxydllgenerator python3 -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install -r requirements.txt ``` ## 用法 首先激活 venv,然后运行: ``` source .venv/bin/activate # Windows: .venv\Scripts\activate python proxydll.py -dll -shellcode [options] ``` ### 必需项 | Argument | Description | |----------|-------------| | `-dll ` | 要代理的 DLL 路径(用于解析导出) | | `-shellcode ` | 原始二进制 shellcode 文件的路径(明文或预加密) | ### 可选项 | Argument | Default | Description | |----------|---------|-------------| | `-arch x64\|x86\|all` | `all` | 目标架构 | | `-o / --output ` | 与输入 DLL 相同 | 输出文件名(无扩展名) | | `--output-dir ` | `./output` | 编译后 DLL 的根目录 | | `--keep-sources` | off | 保留生成的 `dllmain.c`、`stubs.s`、`proxy.def` | | `-v / --verbose` | off | 打印编译器命令和诊断信息 | ### AES 加密 | Argument | Description | |----------|-------------| | `--encrypt` | 使用随机生成的 AES-256-CBC 密钥和 IV 加密 shellcode | | `--aes-bits 128\|192\|256` | 使用 `--encrypt` 时的密钥大小(默认:`256`) | | `--aes-key ` | 用于**预加密** shellcode 文件的十六进制编码密钥(必须与 `--aes-iv` 配合使用) | | `--aes-iv ` | 用于**预加密** shellcode 文件的十六进制编码 IV(必须与 `--aes-key` 配合使用) | `--encrypt` 和 `--aes-key` / `--aes-iv` 是互斥的——请选择其中一种模式使用。 当使用 `--encrypt` 时,该工具会将生成的密钥和 IV 打印到标准输出: ``` [+] Key (hex) : 3f8a1b... [+] IV (hex) : c72d09... ``` ## 示例 ``` # 两种架构,无加密(默认) python proxydll.py -dll secur32.dll -shellcode payload.bin # 使用随机 AES-256 key 自动加密 python proxydll.py -dll secur32.dll -shellcode payload.bin --encrypt # 使用 AES-128 自动加密 python proxydll.py -dll secur32.dll -shellcode payload.bin --encrypt --aes-bits 128 # Shellcode 已使用 AES-256-CBC 加密 — 以十六进制格式提供 key 和 IV python proxydll.py -dll secur32.dll -shellcode payload.enc \ --aes-key <64-hex-chars> --aes-iv <32-hex-chars> # 仅限 x64,自定义输出名称 python proxydll.py -dll secur32.dll -shellcode payload.bin -arch x64 -o secur32 # 检查生成的源代码 python proxydll.py -dll version.dll -shellcode shell.bin --keep-sources -v ``` ## 输出结构 ``` output/ └── AMD/ ├── x64/ │ └── .dll └── x86/ └── .dll ``` 使用 `--keep-sources` 时: ``` output/_sources/ ├── x64/ │ ├── dllmain.c │ ├── stubs.s │ └── proxy.def └── x86/ └── ... ``` ## 工作原理 ### 导出转发 对于每一个命名的导出,`DllMain` 会使用其完整路径从 `System32` 加载真实的 DLL: ``` char path[MAX_PATH]; GetSystemDirectoryA(path, MAX_PATH); lstrcatA(path, "\\secur32.dll"); HMODULE orig = LoadLibraryA(path); ``` 使用完整的 `System32` 路径可以避免在代理 DLL 位于更高优先级的搜索目录时,意外地加载代理本身。 每个导出都通过生成的汇编 JMP stub 进行转发: ``` AcceptSecurityContext: jmpq *proxy_fns+0(%rip) ; x64 ``` `proxy_fns[]` 数组在加载时会填充 `GetProcAddress` 获取的指针。所有的参数、寄存器和返回值都会原封不动地通过。 ### Shellcode 执行 在加载时,代理 DLL 会生成一个线程来执行以下操作: 1. **解密 shellcode**(如果使用了加密),通过 Windows BCrypt API 进行。 2. 尝试 `NtCreateSection` / `NtMapViewOfSection` —— 由 section 支持的可执行内存可以绕过 `ProcessDynamicCodePolicy`(ACG / Arbitrary Code Guard)。 3. 对于没有 ACG 的目标,则回退使用 `VirtualAlloc(PAGE_EXECUTE_READWRITE)`。 当启用 AES 加密时,shellcode 字节将以密文形式存储在 `.rdata` 中。AES 密钥和 IV 也被嵌入在二进制文件中。在运行时,BCrypt 将其解密到堆缓冲区中,将其复制到可执行内存中,然后立即使用 `SecureZeroMemory` 将堆上的副本清零——从而最大限度地减少密钥材料的暴露。 ### AES-CBC 解密(仅限加密构建) 生成的 C 代码使用了 Windows 的 **BCrypt** API(目标机器上不需要第三方 DLL): ``` BCryptOpenAlgorithmProvider → BCRYPT_AES_ALGORITHM BCryptSetProperty → BCRYPT_CHAIN_MODE_CBC BCryptGenerateSymmetricKey → key bytes embedded in .rdata BCryptDecrypt → BCRYPT_BLOCK_PADDING (removes PKCS7 padding) ``` 当启用加密时,`-lbcrypt` 会自动添加到链接器命令中。 ### 仅有 ordinal 的导出 没有名称的导出将被跳过并发出警告。大多数 Windows 系统 DLL 都是通过名称导出所有内容的。 ## 部署 1. 将生成的代理 DLL 放入一个会在 System32 **之前**被搜索的目录中——通常是目标应用程序自己的文件夹。 2. 代理 DLL 会在运行时直接从 `System32` 加载真实的 DLL。 ``` python proxydll.py -dll secur32.dll -shellcode payload.bin --encrypt # → output/AMD/x64/secur32.dll # → output/AMD/x86/secur32.dll ``` ## 限制 - **仅限系统 DLL** —— `System32` 回退机制仅对存在于该目录中的 DLL 有效。对于不在 `System32` 中的应用程序捆绑 DLL,请将代理与目标放在一起,并确保搜索顺序将其放在首位。 - **不支持 ARM** —— 需要 `llvm-mingw`。如果需要,请在 `src/compiler.py` 中添加 ARM `ArchConfig` 条目。 - **仅有 ordinal 的导出会被跳过** —— 见上文。 - **Shellcode 必须是位置无关代码 (PIC)** —— 内存是在随机基地址分配的。 - **AES 密钥嵌入在二进制文件中** —— 密钥和 IV 存在于编译后 DLL 的 `.rdata` 节中。这是一个混淆层,而不是针对能够读取该 DLL 的人的加密保护。 ## 延伸阅读 - [Phantom DLL 劫持](https://samipp.com.np/posts/phantom-dll-hijacking/) —— 该技术的完整演练、OneDrive 实验环境、此工具自动化的手动代理 DLL 流程,以及检测/防御视角。 ## 法律声明 本工具仅供授权的安全测试、渗透测试活动、红蓝对抗演练和教育目的使用。在您不拥有或未获得明确书面许可进行测试的系统上使用是违法的。作者对任何滥用行为不承担责任。
标签:Dionaea, DLL劫持, MinGW, Shellcode执行, 自动回退, 逆向工具