¿Cuál es el ejecutable de Windows (PE) más pequeño posible?

Como precursor de escribir un comstackdor, bash comprender el formato ejecutable portátil de Windows (32 bits). En particular, me gustaría ver un ejemplo de un ejecutable escueto que no hace más que cargar correctamente, ejecutar y salir.

Intenté escribir y comstackr una función principal C simple que no hace más que el .exe resultante es ~ 22KB y contiene muchas importaciones de KERNEL32.DLL (presumiblemente utilizado por LIBC para configurar el entorno, montones, etc.). Incluso el encabezado de DOS podría ser más pequeño (actualmente imprime el predeterminado ‘Este progtwig no se puede ejecutar en modo DOS’).

¿Cuál es la estructura del ejecutable de Windows 32 bit más pequeño posible?

Según lo citado de la fuente ( Creando el ejecutable PE más pequeño posible ): 1

  • El archivo PE más pequeño posible: 97 bytes
  • El archivo PE más pequeño posible en Windows 2000: 133 bytes
  • El archivo PE más pequeño que descarga un archivo sobre WebDAV y lo ejecuta: 133 bytes

Los archivos anteriores son los archivos PE más pequeños posibles debido a los requisitos del formato de archivo PE y no pueden mejorarse aún más.

Este resultado se logró con algunos trucos ingeniosos de NASM, como eliminar el paso que vincula a C stdlib y eliminar varios campos de encabezado y directorios de datos.

El código fuente completo está debajo. Es efectivamente lo mismo que el artículo con estas modificaciones:

  • Eliminación de líneas en blanco
  • etiqueta sectalign renombrada a sect_align . Desde el momento en que se escribió este código ensamblador, sectalign convirtió en una palabra clave NASM. Renombrarlo para evitar advertencias y errores.

El código es el siguiente:

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

Para construir en un uso ejecutable:

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

Para ejecutables ELF de GNU / Linux, consulte el artículo “Tutorial de Whirlwind sobre la creación de ejecutables ELF realmente complejos para Linux” . TL; DR : 1340 bytes, utilizando NASM

Nota : Esta respuesta es una expansión del comentario de J … el 3 de diciembre de 2016 a las 17:31, con el fin de preservar la información que se encuentra en el enlace (en caso de que también desaparezca).


  1. Tiny PE ; Alexander Sotirov; visto el 15/11/2017 a las 17:50 SAST

En Windows XP (x32), el ejecutable PE más pequeño tiene 97 bytes. En las versiones de 32 bits de Vista y 7, el ejecutable PE más pequeño tiene 252 bytes. En las versiones de 64 bits de Windows, el ejecutable de 32 bits más pequeño tiene 268 bytes. En este foro encontrará un bitmap de dicho ejecutable.

El ejecutable de x64 PE más pequeño tiene 268 bytes. Incluso es posible ejecutar cada byte en un ejecutable de este tamaño. Puede encontrar un enlace en este foro también.

El siguiente código es un archivo ejecutable x64 PE (también conocido como PE32 +) de tamaño 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 

Por cierto, en esta entrada de blog encontrará un ejecutable pequeño (316 bytes) x32 con código fuente ensamblador y muchos detalles técnicos.