什么是最小的 Windows (PE) 可执行文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/553029/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the smallest possible Windows (PE) executable?
提问by Matthew Murdoch
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 executable which does nothing except load correctly, run and exit.
作为编写编译器的前身,我试图了解 Windows(32 位)可移植可执行文件格式。我特别想看一个简单的可执行文件的例子,它除了正确加载、运行和退出之外什么都不做。
I've tried writing and compiling a simple C main function which does nothing but the resulting .exe is ~22KB and contains many imports from KERNEL32.DLL (presumably used by LIBC to set up environment, heaps etc.). Even the DOS Header could probably be smaller (it currently prints the default 'This program cannot be run in DOS mode').
我已经尝试编写和编译一个简单的 C 主函数,它除了生成的 .exe 是 ~22KB 之外什么都不做,并且包含许多来自 KERNEL32.DLL 的导入(大概被 LIBC 用于设置环境、堆等)。甚至 DOS 标题也可能更小(它当前打印默认的“此程序不能在 DOS 模式下运行”)。
What is the structure of the smallest possible Windows 32-bit executable?
最小的 Windows 32 位可执行文件的结构是什么?
回答by Agi Hammerthief
As quoted from source (Creating the smallest possible PE executable): 1
引用自源代码(创建尽可能小的 PE 可执行文件):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.
- 最小的 PE 文件:97 字节
- Windows 2000 上可能的最小 PE 文件:133 字节
- 通过 WebDAV 下载文件并执行的最小 PE 文件:133 字节
由于PE文件格式的要求,以上文件是可能的最小PE文件,无法进一步改进。
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.
这个结果是通过一些聪明的 NASM 技巧实现的,例如删除链接到 C 的步骤stdlib
并删除一些标题字段和数据目录。
The full source code is below. It is effectively the same as the article with these modification:
完整的源代码如下。它实际上与具有这些修改的文章相同:
- Removal of blank lines
sectalign
label renamed tosect_align
. Since the time this assembly code was writtensectalign
became a NASM keyword. Rename it to avoid warnings and errors.
- 去除空行
sectalign
标签重命名为sect_align
. 自从编写此汇编代码以来,sectalign
它就成为 NASM 关键字。重命名它以避免警告和错误。
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
对于 GNU/Linux ELF 可执行文件,请参阅文章“关于为 Linux 创建真正小巧的 ELF 可执行文件的旋风教程”。TL;DR:1340
字节,使用 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).
注意:此答案是 J... 在 2016 年 12 月 3 日 17:31 发表的评论的扩展,以保留链接中找到的信息(以防链接失效)。
- Tiny PE; Alexander Sotirov; viewed 15/11/2017 @ 17:50 SAST
- 小PE;亚历山大·索蒂罗夫;查看 15/11/2017 @ 17:50 SAST
回答by DrakoPensulo
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 forumyou find a bit-map of such executable.
在 Windows XP (x32) 上,最小的 PE 可执行文件是 97 字节。在 32 位版本的 Vista 和 7 上,最小的 PE 可执行文件是 252 字节。在 64 位版本的 Windows 上,最小的 32 位可执行文件是 268 字节。在此论坛上,您可以找到此类可执行文件的位图。
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 forumas well.
最小的 x64 PE 可执行文件是 268 字节。甚至可以执行这种大小的可执行文件中的每个字节。您也可以在此论坛上找到链接。
The code below is a x64 PE (aka PE32+) executable file of size 268 bytes.
下面的代码是一个大小为 268 字节的 x64 PE(又名 PE32+)可执行文件。
; 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 On this blog entryyou find a small (316 bytes) x32 executable with assembler source code and many technical details.
顺便说一句,在此博客条目中,您可以找到一个带有汇编源代码和许多技术细节的小型(316 字节)x32 可执行文件。