一个支持多种注入技术的shellcode加载器生成器,专为红队演练而构建。
hollow 是一个 shellcode 加载器生成器。你提供原始 shellcode 二进制文件和一个配置文件,它会生成一个编译好的 Windows PE 加载器,其中内嵌了加密后的 shellcode。
二进制文件可在 releases 页面获取,或从源码构建:
go build -o hollow .
需要 x86_64-w64-mingw32-gcc 进行交叉编译。
在 Arch Linux 上:pacman -S mingw-w64-gcc
在 Debian/Ubuntu 上:apt install gcc-mingw-w64-x86-64
./hollow -shellcode payload.bin -profile profiles/new_process_injection_sc.json
| 标志 | 描述 |
|---|---|
-shellcode | 原始 shellcode 的路径 (.bin) |
-profile | 配置文件 JSON 的路径 |
-templates | 模板目录 (默认: ./templates) |
hollow 遵循一个三步流程:加密、替换、编译。
你的 shellcode 使用 AES-256-CBC 进行加密,每次运行时都会生成一个随机密钥和 IV。它们都被嵌入到输出的二进制文件中。然后,选定的 C 模板中的占位符会被替换为加密后的 shellcode、密钥和 IV,最后通过 MinGW 编译成一个 stripped、静态链接的 PE 文件。
在运行时,加载器使用 Windows BCrypt 解密 shellcode,并使用模板实现的注入技术在进程中执行它。
模板是实现实际注入逻辑的 C 源文件。每个模板位于 templates/ 目录中,包含占位符令牌(${SHELLCODE}、${KEY}、${IV}、${TARGET_PROCESS}),hollow 在编译前会填充这些占位符。你通过配置文件选择模板。
hollow 内置了六个模板:
你可以编写自己的模板并放入 templates/ 目录中——只要配置文件指向它,hollow 会自动识别。
配置文件是 JSON 文件,告诉 hollow 使用哪个模板、目标进程以及编译参数。它们位于 profiles/ 目录中,可根据具体任务进行定制。
{
"name": "通过直接系统调用进行新进程注入",
"author": "",
"template": "new_process_injection_sc",
"target_process": "C:\\Windows\\System32\\cmd.exe",
"arch": "x64",
"compile": {
"automatic": true,
"gcc": "x86_64-w64-mingw32-gcc",
"strip": true,
"output_type": "exe"
},
"output_dir": "./output"
}
output_type 可以是 exe 或 dll。将 automatic: false 设置为 false 可以将替换后的 C 源码输出到磁盘而不编译,在构建前手动修改代码时很有用。
输出文件写入 output_dir,文件名为 {template}_loader.{exe|dll}。
模板:new_process_injection
技术: 向新启动的进程注入远程线程。
使用 CREATE_BREAKAWAY_FROM_JOB | CREATE_NO_WINDOW 启动目标进程,等待两秒初始化,然后在目标进程地址空间中分配内存,写入解密后的 shellcode,标记为可执行,并创建指向它的远程线程。BREAKAWAY 标志在加载器从 WinRM 启动时需要,因为 WinRM 会将所有进程包装在作业对象中。目标是一个完整的可执行文件路径。
Win32 调用:CreateProcessA、VirtualAllocEx、WriteProcessMemory、VirtualProtectEx、CreateRemoteThread。
模板:new_process_injection_sc
技术: 向新启动的进程注入远程线程,通过直接系统调用 (Hell's Gate)。
行为与 new_process_injection 相同,但所有内存分配和线程调用都完全绕过 Win32 层。SSN 在运行时从 ntdll 解析,并通过原始的 syscall 指令执行。请参考基准测试部分。
模板:remote_thread_injection
技术: 经典向现有进程注入远程线程。
使用 CreateToolhelp32Snapshot 按名称查找运行中的进程,打开它的句柄,然后分配内存、写入 shellcode 并创建远程线程。不启动新进程。最适合长期运行的进程,如 explorer.exe。目标是进程映像名称,而非完整路径。
Win32 调用:OpenProcess、VirtualAllocEx、WriteProcessMemory、VirtualProtectEx、CreateRemoteThread。
模板:remote_thread_injection_sc
技术: 经典向现有进程注入远程线程,通过直接系统调用 (Hell's Gate)。
行为与 remote_thread_injection 相同,绕过 Win32 层。请参考基准测试部分。
模板:earlybird_apc
技术: Early Bird APC 注入 (CyberArk, 2018)。
以挂起状态启动目标进程(CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB | CREATE_NO_WINDOW),将解密后的 shellcode 写入其地址空间,然后通过 QueueUserAPC 向主线程排队一个指向 shellcode 的异步过程调用(APC),最后使用 ResumeThread 恢复线程。由于 APC 在进程入口点运行之前触发,因此 shellcode 在进程内任何防御性工具初始化之前执行。完全避免了 VirtualAllocEx + WriteProcessMemory + CreateRemoteThread 三连调用。
模板:dll_sideload
技术: DLL 侧加载 / 进程内 shellcode 执行。
生成 DLL 而非 EXE。在 DLL_PROCESS_ATTACH 时,启动一个线程,该线程在进程内解密并执行 shellcode:VirtualAlloc、memcpy、VirtualProtect,然后直接函数调用进入 shellcode。在负载初始化期间(对于 Sliver beacon 大约 10 秒),宿主进程必须保持活动状态。部署时,将 DLL 放在合法二进制文件会通过缺失的 DLL 搜索路径项加载它的位置。
在 Windows 10 Build 19041 上测试,Windows Defender 实时保护开启,定义版本 1.453.354.0,负载为 17 MB 的 Donut 包裹的 Sliver beacon:
Trojan:Win64/AsyncRat.RPY!MTB 是一个机器威胁行为规则,由经典的远程注入序列触发:通过 Win32 API 层对远程进程句柄调用 VirtualAllocEx + WriteProcessMemory + CreateRemoteThread。Defender 会注册一个内核回调,当这三个调用按顺序出现时触发。
_sc 模板通过从不调用这些 Win32 函数来绕过此规则。相反,它们在运行时使用 Hell's Gate 直接从 ntdll 解析相应的内核系统调用服务编号(SSN):每个未挂钩的 ntdll 桩以四字节序言 4C 8B D1 B8 开始,SSN 位于偏移量 4 处。实际的系统调用是一个 GCC 裸函数,仅包含 movq %rcx, %r10 / movl ssn(%rip), %eax / syscall / ret,这正是 ntdll 桩本身会执行的序列。Defender 的回调永远不会触发,因为受监控的 Win32 包装器从未被调用。
在 ntdll 桩被完整 EDR 修补(序言被替换为跳转)的系统上,干净桩检查失败,加载器会提前退出。Halo's Gate(扫描相邻桩以推断 SSN)未实现。
加载器代码增加约 19 KB 的开销。输出大小基本上等于输入 shellcode 的大小。17 MB 的 Sliver beacon 会生成一个 18 MB 的加载器。典型的 Metasploit shellcode(约 200 KB)将生成一个约 220 KB 的加载器。
欢迎贡献。如果你编写了一个模板并想添加,或对现有模板有改进,欢迎提交 PR。如果发现错误或有建议,请提交 issue。
这个工具的目标是让加载器开发过程更简单,而不是一个成品。新模板、更好的配置文件以及对核心的改进都是受欢迎的。hollow 的另一个目的是帮助人们理解 shellcode 加载器和注入技术背后的概念,因此清晰可读的模板代码与功能性同等重要。
我将很快在我的博客上详细介绍每种技术背后的概念以及 hollow 的完整用法。敬请期待。
| 模板 | 技术 |
|---|
new_process_injection | 向新启动的进程注入远程线程 |
new_process_injection_sc | 同上,通过直接系统调用 (Hell's Gate) |
remote_thread_injection | 经典向现有进程注入远程线程 |
remote_thread_injection_sc | 同上,通过直接系统调用 (Hell's Gate) |
earlybird_apc | Early Bird APC 注入 |
dll_sideload | DLL 侧加载,生成 DLL 而非 EXE |
| 模板 | Defender 行为告警 | 会话建立 |
|---|
| new_process_injection | Trojan:Win64/AsyncRat.RPY!MTB | 是 |
| remote_thread_injection | Trojan:Win64/AsyncRat.RPY!MTB | 是 |
| earlybird_apc | 无 | 是 |
| dll_sideload | 无 | 是 |
| new_process_injection_sc | 无 | 是 |
| remote_thread_injection_sc | 无 | 是 |