Quel est le plus petit exécutable Windows (PE) possible?

en tant que précurseur pour écrire un compilateur j'essaye de comprendre le format exécutable Portable de Windows (32 bits). En particulier, j'aimerais voir un exemple d'exécutable simple qui ne fait rien d'autre que charger correctement, exécuter et quitter.

j'ai essayé d'écrire et de compiler une simple fonction C principale qui ne fait rien d'autre que le résultat .exe est ~22KB et contient de nombreuses importations en provenance de KERNEL32.DLL (probablement utilisé par LIBC pour configurer l'environnement, les tas, etc.). Même le DOS de l'en-Tête pourrait probablement être plus petit (il affiche actuellement la valeur par défaut 'ce programme ne peut pas être exécuté en mode DOS').

Quelle est la structure du plus petit exécutable Windows 32 bits possible?

21
demandé sur Agi Hammerthief 2009-02-16 14:33:44

2 réponses

tel que cité par la source ( Creating the smest possible PE executable):1

  • plus petit fichier PE possible: 97 octets
  • plus petit fichier PE possible sur Windows 2000: 133 octets
  • le plus petit fichier PE qui télécharge un fichier sur WebDAV et l'exécute: 133 octets

les fichiers ci-dessus sont les plus petits fichiers PE possibles en raison des exigences du format de fichier PE et ne peuvent pas être améliorés plus.

ce résultat a été obtenu avec quelques astuces NASM astucieuses, telles que la suppression de l'étape qui renvoie à C stdlib et la suppression d'un certain nombre de champs d'en-tête de données et de répertoires.

Le code source complet est ci-dessous. C'est effectivement la même que celle de l'article avec ces modification:

  • suppression des lignes vides
  • sectalign label renommé sect_align. Depuis l'époque où ce code d'assemblage a été écrit sectalign est devenu un NASM mot. Renommer pour éviter les avertissements et les erreurs.

le code est le suivant:

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

Pour générer un exécutable utilisation:

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

pour les exécutables ELF GNU/Linux, voir l'article "Tourbillon Tutoriel sur la Création de Vraiment Teensy Exécutables ELF pour Linux". TL;DR:1340 octets, à l'aide de MSNA

Remarque:: Cette réponse est une extension de J...'s commentaire sur Dec 3 '16 à 17:31, dans l'ordre pour préserver les informations trouvées dans le lien (au cas où cela aussi s'éteint).


  1. Tiny PE; Alexander Sotirov; viewed 15/11/2017 @ 17: 50 SAST
3
répondu Agi Hammerthief 2018-06-04 16:24:54

sur Windows XP (x32) le plus petit exécutable PE est de 97 octets. Sur les versions 32 bits de Vista et 7, le plus petit exécutable PE est de 252 octets. Sur les versions 64bit de Windows, le plus petit exécutable de 32bit est de 268 octets. ce forum vous trouvez un bit-map d'un tel exécutable.

le plus petit exécutable x64 PE est de 268 octets. Il est même possible d'exécuter chaque octet dans un exécutable de cette taille. Vous pouvez trouver un lien sur ce forum.

le code ci-dessous est un fichier exécutable x64 PE (alias PE32+) de 268 octets.

; 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 Sur ce entrée de blog vous trouvez un petit exécutable x32 (316 octets) avec code source assembleur et de nombreux détails techniques.

0
répondu DrakoPensulo 2018-08-21 11:24:26