A minimal Windows x64 PE executable built from scratch, handcrafted byte-by-byte to understand the PE file format at its core.
This project demonstrates how to create the smallest possible valid Windows executable while still adhering to proper PE structure, including:
- Valid DOS header with MZ signature
- Complete PE/COFF headers
- Proper section alignment (0x1000)
- File alignment (0x200)
- A single
.textsection - Minimal code that returns an exit code
The final executable is carefully structured to pass Windows loader validation while remaining as compact as possible.
- ✅ Valid PE32+ (x64) format
- ✅ Follows proper section and file alignment
- ✅ Minimal subsystem version requirements
- ✅ No external dependencies or imports
- ✅ Clean exit via
retinstruction (no syscalls needed) - ✅ Customizable exit code
Requirements:
- NASM (Netwide Assembler)
- Make
makeThis will assemble main.asm into main.exe.
The executable:
- Sets up a minimal but valid PE structure
- Entry point executes:
push 10; pop rax; ret - Returns control to Windows with exit code in RAX (10 in this case)
The Windows loader pushes a return address onto the stack before jumping to the entry point, so a simple ret instruction pops that address and exits cleanly.
File Structure:
- DOS Header (0x00 - 0x3F)
- PE Signature (0x40 - 0x43)
- COFF Header (0x44 - 0x57)
- Optional Header (0x58 - 0x147)
- Section Headers (0x148 - 0x1FF)
- Code Section (0x200+)
Key PE Fields:
- Machine:
0x8664(AMD64) - Subsystem:
0x03(Console) - Entry Point RVA:
0x1000 - Image Base:
0x140000000 - Section Alignment:
0x1000 - File Alignment:
0x200
This project was built to understand:
- PE/COFF file format internals
- Windows executable structure
- Minimal requirements for a valid x64 executable
- How the Windows loader validates and runs executables
- The subsystem version (
MajorSubsystemVersion= 6) is critical - Windows will reject version 0.0 - The executable uses standard alignment values for compatibility
- No imports, exports, or data directories are used (except headers)
- Stack space is reserved but minimal code doesn't use it
Do whatever you want with it. It's just bytes.
Exit Code: The executable returns 10 by default. Modify the push value in the assembly to change it.