
生成 x86、x64 或 AMD64+x86 位置无关的 shellcode,可从内存加载 .NET 程序集、PE 文件及其他 Windows 有效负载,并带参数运行它们。

当前版本:v1.1
Donut 是一个位置无关代码,能够在内存中执行 VBScript、JScript、EXE、DLL 文件和 .NET 程序集。Donut 创建的模块可以从 HTTP 服务器分段加载,或直接嵌入到加载器本身中。该模块可选地使用 Chaskey 分组密码和 128 位随机生成的密钥进行加密。文件在内存中加载并执行后,原始引用会被擦除以阻止内存扫描器。生成器和加载器支持以下特性:
提供了适用于 Linux 和 Windows 的动态和静态库,可集成到您自己的项目中。还有一个 Python 模块,您可以在构建和使用 Python 扩展中了解更多信息。
Donut 为每种支持的文件类型包含单独的加载器。对于 .NET EXE/DLL 程序集,Donut 使用非托管 CLR 托管 API 来加载公共语言运行时 (CLR)。将 CLR 加载到宿主进程后,会创建一个新的应用程序域,以允许在可释放的 AppDomain 中运行程序集。当 AppDomain 准备就绪后,通过 AppDomain.Load_3 方法加载 .NET 程序集。最后,调用用户指定的 EXE 入口点或 DLL 的公共方法,并附带任何附加参数。有关非托管 CLR 托管 API 的文档,请参阅 MSDN CLR 托管接口。有关 CLR 主机的独立示例,请参阅这里的代码。
VBScript 和 JScript 文件使用 IActiveScript 接口执行。还提供对 Windows 脚本宿主(wscript/cscript)提供的部分方法的最小支持。有关独立示例,请参阅这里的代码。更详细的说明请阅读:内存中执行 JavaScript、VBScript、JScript 和 XSL
非托管或原生 EXE/DLL 文件使用自定义 PE 加载器执行,支持延迟导入、TLS 和修补命令行。仅支持包含重定位信息的文件。阅读 内存中执行 DLL 以了解更多信息。
加载器可以禁用 AMSI 和 WLDP,以帮助检测在内存中执行的恶意文件。有关更多信息,请阅读 红队如何绕过 .NET 动态代码的 AMSI 和 WLDP。它还支持使用 aPLib 或 RtlDecompressBuffer API 在内存中解压缩文件。阅读 数据压缩 以了解更多信息。
从 v1.0 开始,ETW 也被绕过。与 AMSI/WLDP 类似,这是一个模块化系统,允许您用自己的绕过替换默认绕过。默认绕过源自 XPN 的研究。阅读 隐藏 .NET - ETW 以了解更多信息。
默认情况下,加载器会覆盖非托管 PE 的 PE 头(从基址到 `IMAGE_OPTIONAL_HEADER.SizeOfHeaders`)。如果未使用诱饵模块(模块重载),则 PE 头将被清零。如果使用了诱饵模块,诱饵模块的 PE 头将用于覆盖有效载荷模块的 PE 头。这是为了防止通过比较内存中的模块 PE 头与磁盘上对应的文件来检测。用户可以请求保留所有 PE 头的原始状态。这在有效载荷模块需要访问其 PE 头时很有用,例如查找嵌入的 PE 资源时。
有关使用生成器的详细演练以及 Donut 如何影响战术,请阅读 Donut - 将 .NET 程序集注入为 Shellcode。有关加载器的更多信息,请阅读 从内存加载 .NET 程序集。
希望了解更多内部细节的人应参考开发者笔记。
有两种构建类型。如果您想调试 Donut,请参考这里的文档。如果不调试,请继续阅读发行版本构建。
在 Windows 命令提示符或 Linux 终端中,克隆仓库。
git clone http://github.com/thewover/donut.git
下一步取决于您的操作系统和选择的编译器。目前,Donut 的生成器和加载器模板可以使用 Microsoft Visual Studio 2019 和 MingGW-64 成功编译。要在您自己的 C/C++ 项目中使用这些库,请参考这里提供的示例。
生成加载器模板、动态库 donut.dll、静态库 donut.lib 和生成器 donut.exe。启动 x64 Microsoft Visual Studio 开发者命令提示符,切换到克隆 Donut 仓库的目录并输入以下命令:
nmake -f Makefile.msvc
要在 Windows 或 Linux 上使用 MinGW-64 执行相同操作,切换到克隆 Donut 仓库的目录并输入以下命令:
make -f Makefile.mingw
生成动态库 donut.so、静态库 donut.a 和生成器 donut。切换到克隆 Donut 仓库的目录,直接输入 make。
Donut 可以作为 Python 模块安装和使用。要从源代码安装,需要为 Python3 安装 pip。首先,确保没有安装旧版本的 donut-shellcode,在 Linux 终端或 Microsoft Visual Studio 命令提示符下执行以下命令:
pip3 uninstall donut-shellcode
确认旧版本已卸载后,执行以下命令:
pip3 install .
您也可以从 PyPi 仓库获取 Donut 并作为 Python 模块安装。
pip3 install donut-shellcode
有关更多信息,请参考构建和使用 Python 扩展。
构建 Docker 容器。
docker build -t donut .
运行 donut。
docker run -it --rm -v "${PWD}:/workdir" donut -h
Donut 包含其他几个可单独构建的可执行文件。包括 "hash.exe"、"encrypt.exe"、"inject.exe" 和 "inject_local.exe"。前两个用于 shellcode 生成。后两个用于帮助测试 donut shellcode。"inject.exe" 会通过 PID 或进程名将原始二进制文件 (loader.bin) 注入到进程中。"inject_local.exe" 会将原始二进制文件注入到自身进程中。
要单独构建这些支持可执行文件,可以使用 MSVC makefile。例如,要构建 "inject_local.exe" 来测试您的 donut shellcode,可以运行:
nmake inject_local -f Makefile.msvc
Donut 的每个发行版本都提供了包含已编译可执行文件的标签。
目前还有另外两个生成器可用。
下表列出了生成器命令行版本支持的开关。
| 开关 | 参数 | 描述 |
|---|---|---|
| -a | arch | 加载器的目标架构:1=x86, 2=amd64, 3=x86+amd64(默认)。 |
| -b | level | 绕过 AMSI/WLDP 的行为:1=无,2=失败时中止,3=失败时继续(默认)。 |
| -k | headers | 保留 PE 头。1=覆盖(默认),2=全部保留 |