What is the smallest possible Windows (PE) executable? What is the smallest possible Windows (PE) executable? windows windows

What is the smallest possible Windows (PE) executable?


As quoted from source (Creating the smallest possible PE executable): 1

  • Smallest possible PE file: 97 bytes
  • Smallest possible PE file on Windows 2000: 133 bytes
  • Smallest PE file that downloads a file over WebDAV and executes it: 133 bytes

The files above are the smallest possible PE files due to requirements of the PE file format and cannot be improved further.

This result was achieved with some clever NASM tricks, such as removing the step that links to C stdlib and removing a number of header fields and data directories.

The full source code is below. It is effectively the same as the article with these modification:

  • Removal of blank lines
  • sectalign label renamed to sect_align. Since the time this assembly code was written sectalign became a NASM keyword. Rename it to avoid warnings and errors.

The code is as follows:

; tiny97.asm, copyright Alexander SotirovBITS 32;; MZ header; The only two fields that matter are e_magic and e_lfanewmzhdr:    dw "MZ"       ; e_magic    dw 0          ; e_cblp UNUSED; PE signaturepesig:    dd "PE"       ; e_cp, e_crlc UNUSED       ; PE signature; PE headerpehdr:    dw 0x014C     ; e_cparhdr UNUSED          ; Machine (Intel 386)    dw 1          ; e_minalloc UNUSED         ; NumberOfSections;   dd 0xC3582A6A ; e_maxalloc, e_ss UNUSED   ; TimeDateStamp UNUSED; Entry pointstart:    push byte 42    pop eax    retcodesize equ $ - start    dd 0          ; e_sp, e_csum UNUSED       ; PointerToSymbolTable UNUSED    dd 0          ; e_ip, e_cs UNUSED         ; NumberOfSymbols UNUSED    dw sections-opthdr ; e_lsarlc UNUSED      ; SizeOfOptionalHeader    dw 0x103      ; e_ovno UNUSED             ; Characteristics; PE optional header; The debug directory size at offset 0x94 from here must be 0filealign equ 4sect_align equ 4  ; must be 4 because of e_lfanew%define round(n, r) (((n+(r-1))/r)*r)opthdr:    dw 0x10B      ; e_res UNUSED              ; Magic (PE32)    db 8                                      ; MajorLinkerVersion UNUSED    db 0                                      ; MinorLinkerVersion UNUSED; PE code sectionsections:    dd round(codesize, filealign)  ; SizeOfCode UNUSED  ; Name UNUSED    dd 0  ; e_oemid, e_oeminfo UNUSED ; SizeOfInitializedData UNUSED    dd codesize  ; e_res2 UNUSED  ; SizeOfUninitializedData UNUSED  ; VirtualSize    dd start  ; AddressOfEntryPoint  ; VirtualAddress    dd codesize  ; BaseOfCode UNUSED  ; SizeOfRawData    dd start  ; BaseOfData UNUSED  ; PointerToRawData    dd 0x400000  ; ImageBase  ; PointerToRelocations UNUSED    dd sect_align ; e_lfanew  ; SectionAlignment  ; PointerToLinenumbers UNUSED    dd filealign  ; FileAlignment  ; NumberOfRelocations, NumberOfLinenumbers UNUSED    dw 4  ; MajorOperatingSystemVersion UNUSED ; Characteristics UNUSED    dw 0  ; MinorOperatingSystemVersion UNUSED    dw 0  ; MajorImageVersion UNUSED    dw 0  ; MinorImageVersion UNUSED    dw 4  ; MajorSubsystemVersion    dw 0  ; MinorSubsystemVersion UNUSED    dd 0  ; Win32VersionValue UNUSED    dd round(hdrsize, sect_align)+round(codesize,sect_align) ; SizeOfImage    dd round(hdrsize, filealign)  ; SizeOfHeaders    dd 0  ; CheckSum UNUSED    db 2  ; Subsystem (Win32 GUI)hdrsize equ $ - $$filesize equ $ - $$

To build into an executable use:

nasm -f bin tiny97.asm -o tiny97.exe

For GNU/Linux ELF executables, See the article "Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux". TL;DR: 1340 bytes, using NASM

Note: This answer is an expansion of J...'s comment on Dec 3 '16 at 17:31, in order to preserve the information found in the link (in case that too goes dead).


  1. Tiny PE; Alexander Sotirov; viewed 15/11/2017 @ 17:50 SAST


On Windows XP (x32) the smallest PE executable is 97 bytes. On 32bit versions of Vista and 7 the smallest PE executable is 252 bytes.On 64bit versions of Windows the smallest 32bit executable is 268 bytes. On this forum you find a bit-map of such executable.

The smallest x64 PE executable is 268 bytes. It is even possible to execute every byte in an executable of this size. You can find a link on this forum as well.

The code below is a x64 PE (aka PE32+) executable file of size 268 bytes.

; PE64smallest.asm   Aug 19, 2018 (c) DrakoPensulo; A smallest PE32+ executable (x64); ; Features:;  - Windows Vista/7/8/10 compatible;  - Size: 268 bytes (an executable file on x64 Windows cannot be smaller);  - No sections;  - No Data Directories (in particular no imports and no TLS callbacks);  - Exits with code 0x2a (this executable does nothing else than that);;; Compile using FASM (https://flatassembler.net)  command line: fasm.exe PE64smallest.asmformat binary as 'exe' use64 EntryPoint:db 'MZ'     ; DOS signaturedw 0facehdd 00004550h    ; Signature PE\0\0dw 8664h    ; Machinedw 0000h    ; NumberOfSectionsdd 0facefaceh   ; TimeDateStampdd 0facefaceh   ; PointerToSymbolTabledd 0facefaceh   ; NumberOfSymbolsdw 0        ; SizeOfOptionalHeader      ; must be multiple of 8 not too large dw 002fh    ; Characteristics       ; must be bit 1=1 bit 13=0dw 020Bh    ; PE32+ Magicdb 0fah     ; MajorLinkerVersiondb 0fah     ; MinorLinkerVersiondd 0facefaceh   ; SizeOfCodedd 0facefaceh   ; SizeOfInitializedDatadd 0facefaceh   ; SizeOfUninitializedDatadd start    ; AddressOfEntryPoint       ; cannot be smaller than SizeOfHeadersdd 0facefaceh   ; BaseOfCodedq 0000000100000000h    ; ImageBase     ; must be multiple of 64kdd 4        ; SectionAlignment and e_lfanew ; PE header offset in filedd 4        ; FileAlignmentdw 0faceh   ; MajorOperatingSystemVersiomdw 0faceh   ; MinorOperatingSystemVersiondw 0faceh   ; MajorImageVersiondw 0faceh   ; MinorImageVersiondw 5        ; MajorSubsystemVersion     ; >3.1 or 4  dw 0h       ; MinorSubsystemVersiondd 0facefaceh   ; Win32VersionValue     dd 0400h    ; SizeOfImage           ; MSB has to be small, must be >0200hdd start    ; SizeOfHeaders         ; SizeOfHeaders has to be < SizeOfImagedd 0facefaceh   ; CheckSumdw 0002h    ; Subsystem 2-GUI 3-CUIdw 0        ; DllCharacteristicsdd 000cefacehdd 0        ; SizeOfStackReserve  upper dword has to be 0, MSB of lower dword has to be smalldd 000cefacehdd 0        ; SizeOfStackCommit  upper dword has to be 0, MSB of lower dword has to be smalldd 000cefacehdd 0        ; SizeOfHeapReserve  upper dword has to be 0, MSB of lower dword has to be smalldd 000cefacehdd 0        ; SizeOfHeapCommit  upper dword has to be 0, MSB of lower dword has to be smalldd 0facefaceh   ; LoaderFlagsdd 0        ; NumberofRvaAndSizes   dd 0facefacehdd 0facefaceh   ; Export Directory Address and Sizedd 0facefacehdd 0facefaceh   ; Import Directory Address and Sizedd 0facefaceh   dd 0facefaceh   ; Resource Directory Address and Sizedd 0facefacehdd 0facefaceh   ; Exception Directory Address and Sizedd 0facefacehdd 0facefaceh   ; Security Directory Address and Sizedd 0facefacehdd 0facefaceh   ; Base Relocation Table Address and Size    dd 0facefacehdd 0facefaceh   ; Debug Directory Address and Sizedd 0facefaceh   dd 0facefaceh   ; Architecture Specific Data Address and Sizedd 0facefacehdd 0facefaceh   ; RVA of GlobalPtr Directory Address and Sizedd 0facefacehdd 0facefaceh   ; TLS Directory Address and Sizedd 0facefacehdd 0facefaceh   ; Load Configuration Directory Address and Sizedd 0facefacehdd 0facefaceh   ; Bound Import Directory Address and Sizedd 0facefacehdd 0facefaceh   ; Import Address Table Address and Sizedd 0facefacehdd 0facefaceh   ; Delay Load Import Descriptors Address and Sizedd 0facefacehdd 0facefaceh   ; COM runtime Descriptors Address and Sizedd 0facefacehstart:push 2ahpop raxret     ; Reserved Descriptor

BTW On this blog entry you find a small (316 bytes) x32 executable with assembler source code and many technical details.