What is the smallest possible Windows (PE) executable?

前端 未结 2 1605
暖寄归人
暖寄归人 2020-11-29 00:34

As a precursor to writing a compiler I\'m trying to understand the Windows (32-bit) Portable Executable format. In particular I\'d like to see an example of a bare-bones exe

相关标签:
2条回答
  • 2020-11-29 00:55

    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.asm
    
    format binary as 'exe' 
    use64 
    
    
    EntryPoint:
    db 'MZ'     ; DOS signature
    dw 0faceh
    
    dd 00004550h    ; Signature PE\0\0
    dw 8664h    ; Machine
    dw 0000h    ; NumberOfSections
    
    dd 0facefaceh   ; TimeDateStamp
    
    dd 0facefaceh   ; PointerToSymbolTable
    
    dd 0facefaceh   ; NumberOfSymbols
    
    dw 0        ; SizeOfOptionalHeader      ; must be multiple of 8 not too large 
    dw 002fh    ; Characteristics       ; must be bit 1=1 bit 13=0
    
    dw 020Bh    ; PE32+ Magic
    db 0fah     ; MajorLinkerVersion
    db 0fah     ; MinorLinkerVersion
    
    dd 0facefaceh   ; SizeOfCode
    
    dd 0facefaceh   ; SizeOfInitializedData
    
    dd 0facefaceh   ; SizeOfUninitializedData
    
    dd start    ; AddressOfEntryPoint       ; cannot be smaller than SizeOfHeaders
    
    dd 0facefaceh   ; BaseOfCode
    
    dq 0000000100000000h    ; ImageBase     ; must be multiple of 64k
    
    dd 4        ; SectionAlignment and e_lfanew ; PE header offset in file
    
    dd 4        ; FileAlignment
    
    dw 0faceh   ; MajorOperatingSystemVersiom
    
    dw 0faceh   ; MinorOperatingSystemVersion
    
    dw 0faceh   ; MajorImageVersion
    
    dw 0faceh   ; MinorImageVersion
    
    dw 5        ; MajorSubsystemVersion     ; >3.1 or 4  
    dw 0h       ; MinorSubsystemVersion
    
    dd 0facefaceh   ; Win32VersionValue     
    
    dd 0400h    ; SizeOfImage           ; MSB has to be small, must be >0200h
    
    dd start    ; SizeOfHeaders         ; SizeOfHeaders has to be < SizeOfImage
    
    dd 0facefaceh   ; CheckSum
    
    dw 0002h    ; Subsystem 2-GUI 3-CUI
    dw 0        ; DllCharacteristics
    
    dd 000cefaceh
    dd 0        ; SizeOfStackReserve  upper dword has to be 0, MSB of lower dword has to be small
    
    dd 000cefaceh
    dd 0        ; SizeOfStackCommit  upper dword has to be 0, MSB of lower dword has to be small
    
    dd 000cefaceh
    dd 0        ; SizeOfHeapReserve  upper dword has to be 0, MSB of lower dword has to be small
    
    dd 000cefaceh
    dd 0        ; SizeOfHeapCommit  upper dword has to be 0, MSB of lower dword has to be small
    
    dd 0facefaceh   ; LoaderFlags
    
    dd 0        ; NumberofRvaAndSizes   
    
    dd 0facefaceh
    dd 0facefaceh   ; Export Directory Address and Size
    
    dd 0facefaceh
    dd 0facefaceh   ; Import Directory Address and Size
    
    dd 0facefaceh   
    dd 0facefaceh   ; Resource Directory Address and Size
    
    dd 0facefaceh
    dd 0facefaceh   ; Exception Directory Address and Size
    
    dd 0facefaceh
    dd 0facefaceh   ; Security Directory Address and Size
    
    dd 0facefaceh
    dd 0facefaceh   ; Base Relocation Table Address and Size
    
        dd 0facefaceh
    dd 0facefaceh   ; Debug Directory Address and Size
    
    dd 0facefaceh   
    dd 0facefaceh   ; Architecture Specific Data Address and Size
    
    dd 0facefaceh
    dd 0facefaceh   ; RVA of GlobalPtr Directory Address and Size
    
    dd 0facefaceh
    dd 0facefaceh   ; TLS Directory Address and Size
    
    dd 0facefaceh
    dd 0facefaceh   ; Load Configuration Directory Address and Size
    
    dd 0facefaceh
    dd 0facefaceh   ; Bound Import Directory Address and Size
    
    dd 0facefaceh
    dd 0facefaceh   ; Import Address Table Address and Size
    
    dd 0facefaceh
    dd 0facefaceh   ; Delay Load Import Descriptors Address and Size
    
    dd 0facefaceh
    dd 0facefaceh   ; COM runtime Descriptors Address and Size
    
    dd 0facefaceh
    
    start:
    push 2ah
    pop rax
    ret     ; Reserved Descriptor
    

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

    0 讨论(0)
  • 2020-11-29 01:01

    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 Sotirov
    
    BITS 32
    ;
    ; MZ header
    ; The only two fields that matter are e_magic and e_lfanew
    
    mzhdr:
        dw "MZ"       ; e_magic
        dw 0          ; e_cblp UNUSED
    
    ; PE signature
    pesig:
        dd "PE"       ; e_cp, e_crlc UNUSED       ; PE signature
    
    ; PE header
    pehdr:
        dw 0x014C     ; e_cparhdr UNUSED          ; Machine (Intel 386)
        dw 1          ; e_minalloc UNUSED         ; NumberOfSections
    
    ;   dd 0xC3582A6A ; e_maxalloc, e_ss UNUSED   ; TimeDateStamp UNUSED
    
    ; Entry point
    start:
        push byte 42
        pop eax
        ret
    
    codesize 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 0
    
    filealign equ 4
    sect_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 section
    sections:
        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
    0 讨论(0)
提交回复
热议问题