Convert Exe To Shellcode [exclusive] -
Short guide: convert a Windows EXE to position-independent shellcode
Warning: Running or generating shellcode can be dangerous. Only work with binaries you own or have explicit permission to analyze. I provide a high-level, lawful-usage guide and reproducible steps for research, reverse engineering, or red-team testing in controlled environments.
Prerequisites
- Windows PE (EXE) binary you control.
- A Linux or Windows analysis machine with:
- Python 3
- pefile (Python library)
- mingw-w64 (for cross-building, optional)
- msfvenom (part of Metasploit) — optional helper
- Donut (https://github.com/TheWover/donut) or sRDI/Reflective DLL loader if using DLLs
- x64dbg/OllyDbg/IDA/Ghidra for static analysis (recommended)
- A sandbox/VM to test (e.g., isolated Windows VM, snapshots)
High-level approaches (pick one)
- Pack EXE into a single-stage shellcode payload that:
- Allocates memory in target process
- Writes the EXE bytes
- Performs manual loading (rebuilds sections, resolves imports, calls entry point)
- Or drops the EXE to disk and executes it (simple but leaves disk traces)
- Use a reflective loader (common for DLLs) — convert EXE to DLL or wrap logic into DLL, then use reflective loader shellcode to load it in-memory.
- Use a tool (Donut / msfvenom) to produce shellcode that executes a PE in-memory (Donut supports EXE/NET/PE).
Step-by-step: Method A — Donut (fast, recommended) convert exe to shellcode
- Get Donut:
- git clone https://github.com/TheWover/donut
- Build per project README to produce donut binary.
- Generate shellcode:
- Example for an EXE:
- donut.exe -f 1 -a 2 -p 1 -o payload.bin myprogram.exe
- -f 1: shellcode format (native)
- -a 2: architecture (2 = x64) — match target
- -p 1: position-independent
- -o payload.bin: output raw shellcode
- Adjust args per Donut docs for .NET vs native and options.
- donut.exe -f 1 -a 2 -p 1 -o payload.bin myprogram.exe
- Example for an EXE:
- Test safely:
- Use a small C loader that allocates memory, copies payload.bin, and calls it. Compile in an isolated VM.
- Example (x64 Windows loader skeleton — compile with Visual Studio/mingw):
/* loader.c */ #include <windows.h> extern unsigned char shellcode[]; int main() void *mem = VirtualAlloc(NULL, /*size*/, MEM_COMMIT - Link shellcode into the loader or load from file at runtime.
- Verify behavior in sandbox VM and monitor for unwanted actions.
Step-by-step: Method B — Manual packer that drops-and-executes (simpler, less stealthy)
- Read EXE bytes into your packer program (C/Python).
- Embed them as a byte array inside a small shellcode stub that:
- Creates a temporary file via GetTempPath + GetTempFileName.
- Writes bytes to file (CreateFile/WriteFile).
- Calls CreateProcess or ShellExecute to run it.
- Optionally cleans up the file after execution.
- Convert the stub + embedded bytes into position-independent shellcode:
- Keep the stub small and avoid absolute addresses.
- Compile the stub to raw bytes (ensure no relocations or strip symbols).
- Use a tool to extract the raw code section (objcopy or a custom extractor).
- Deliver and test in VM.
Step-by-step: Method C — Manual in-memory PE loader (advanced, stealthy)
- Analyze EXE with pefile/Ghidra to find sections, entry point, import table.
- Shellcode responsibilities:
- Call VirtualAlloc to allocate enough RWX memory for the image size.
- Copy headers and sections into allocated memory at correct virtual addresses or relocate if needed.
- Apply base relocations when the allocated base differs from the image base.
- Resolve imports: parse IMAGE_IMPORT_DESCRIPTOR, load dependent DLLs (LoadLibraryA), resolve functions (GetProcAddress), and write addresses into IAT.
- If TLS callbacks exist, call them.
- Call the PE entry point (or exported function) with proper calling convention (for EXE, call entry point with HINSTANCE and other args as needed).
- Implement loader in position-independent assembly or C with syscall/WinAPI usage; compile and produce raw shellcode.
- Test intensely in a disposable sandbox.
Recommended tooling and snippets
- pefile (Python): parse headers, sections, imports, relocations.
- lief (Python/C++): manipulate PE programmatically.
- Donut: direct EXE → shellcode for many cases.
- msfvenom: generate stagers/shellcode (payloads, bind/reverse shells).
- objdump / r2 / radare2: inspect compiled shellcode bytes.
- sRDI / ReflectiveLoader: for DLL reflective loading.
Safety, testing, and troubleshooting
- Always test inside an isolated VM with no network or with controlled network.
- Use Procmon, x64dbg, and Wireshark to observe behavior.
- If shellcode crashes:
- Check calling convention and stack alignment.
- Verify imports/resolutions and relocation application.
- Ensure memory protections are correct (RWX may be needed temporarily).
- If antivirus flags payloads, try packing/obfuscation or use known loaders (Donut often bypasses some AVs but may still be detected).
Example minimal workflow (practical)
- Create/simple EXE: myprog.exe
- Use Donut: donut -f 1 -a 2 -o shell.bin myprog.exe
- Build small Windows loader that reads shell.bin into memory and executes it.
- Test in VM.
Further reading (tools to search)
- Donut, msfvenom, pefile, lief, reflective DLL injection, manual PE loader, VirtualAlloc/VirtualProtect, IMAGE_IMPORT_DESCRIPTOR, base relocations (IMAGE_BASE_RELOCATION).
If you want, I can:
- Provide a simple loader C source that loads a raw shellcode file and executes it (specify x86 or x64).
- Show a Python script using pefile to extract imports/sections for a custom loader. Which of those would you like?
1. Using Donut (Recommended Tool)
Donut is the most popular tool for this purpose:
# Basic conversion donut -f payload.exe -o payload.bin3. Pe2shc
A lightweight tool specifically designed to convert PE files to shellcode. It focuses on simplicity and smaller output sizes compared to feature-heavy frameworks like Donut. Short guide: convert a Windows EXE to position-independent
Test with loader
python3 loader.py shellcode.bin