winapi - Hvad er den mindste mulige Windows (PE) eksekverbar?

Indlæg af Hanne Mølgaard Plasc

Problem



Som en forløber for at skrive en compiler forsøger jeg at forstå Windows (32-bit) Portable Executable format. Specielt vil jeg gerne se et eksempel på en eksplosionsbar eksekverbar, som ikke gør andet end at indlæse korrekt, køre og afslutte .


Jeg har forsøgt at skrive og kompilere en simpel C-hovedfunktion, som ikke gør noget, men den resulterende .exe er ~ 22KB og indeholder mange import fra KERNEL32.DLL (formodentlig brugt af LIBC til at oprette miljø, dynger etc.). Selv DOS Header kunne nok være mindre (det udskriver for øjeblikket standard 'Dette program kan ikke køres i DOS-tilstand').


Hvad er strukturen af ​​den mindste mulige Windows 32-bit eksekverbar?

Bedste reference


Som citeret fra kilde (Oprettelse af mindste mulige PE eksekverbare): 1 [9]


  • Mindste mulige PE-fil: 97 bytes
  • Mindste mulige PE-fil i Windows 2000: 133 bytes
  • Mindste PE-fil, der overfører en fil via WebDAV og udfører det: 133 bytes
Filerne ovenfor er de mindste mulige PE-filer på grund af kravene i PE-filformatet og kan ikke forbedres yderligere.


Dette resultat blev opnået med nogle kloge NASM-tricks, såsom at fjerne det trin, der linker til C stdlib og fjerne et antal headerfelter og datakataloger.


Den fulde kildekode er nedenfor. Det er faktisk det samme som artiklen med disse ændringer:



  • Fjernelse af tomme linjer

  • sectalign etiketten omdøbes til sect\_align. Siden den tid denne forsamlingskode blev skrevet sectalign blev et NASM-søgeord. Omdøb den for at undgå advarsler og fejl.



Koden er som følger:


; 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 $ - $$


At bygge ind i en eksekverbar brug:


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


For GNU/Linux ELF eksekverbare filer, se artiklen 'Whirlwind Tutorial om at skabe virkelig Teensy ELF Executables for Linux'. TL; DR : 1340 bytes, ved hjælp af NASM [10]


Bemærk : Dette svar er en udvidelse af J ... 's kommentar den 3. december kl. 17:31 for at bevare oplysningerne i linket (hvis det også går død) .






  1. Lille PE; Alexander Sotirov; set 15/11/2017 @ 17:50 SAST


Andre referencer 1


På Windows XP (x32) er den mindste PE eksekverbare 97 bytes.
På 32bit versioner af Vista og 7 er den mindste PE eksekverbare 252 bytes.
På 64bit versioner af Windows er den mindste 32bit eksekverbare 268 byte. På dette forum finder du et bit-kort over sådanne eksekverbare. [11] [12]


Den mindste x64 PE eksekverbare er 268 byte. Det er endda muligt at udføre hver byte i en eksekverbar af denne størrelse. Du kan også finde et link på dette forum. [13]


Koden nedenfor er en eksekverbar fil x64 PE (aka PE32 +) med størrelse 268 byte.


; 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
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 På denne blogindgang finder du en lille (316 bytes) x32 eksekverbar med assembler kildekode og mange tekniske detaljer. [14]