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?
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é écritsectalign
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).
- Tiny PE; Alexander Sotirov; viewed 15/11/2017 @ 17: 50 SAST
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.