Starsite 星夕小站 - EXE
type: channel
link: https://starset.top/tag/EXE/
items: 探究：Windows 10/11 的最小PE EXE文件能有多小？

探究：Windows 10/11 的最小PE EXE文件能有多小？
type: item
date: 2026-08-15T20:50:00+08:00
description: 用 Python 手搓 268 字节 / 387 字节的 PE EXE—— 顺便彻底搞懂《到底能多小》关键词：PE 格式、最小可执行文件、i386 / AMD64、Windows 11、逐字节构造、加载器实证 实测环境：Windows 11（x64, build 10.0.26100.0） 所有生成器与测试脚本均为纯 Python，不依赖任何汇编器/编译器/链接器TL;DR（太长不看版）在 Windows 11 (x64, 26100) 上，我最终做出了两个“最小可运行”的 PE EXE：口径位宽文件大小内容验证结果32 位 i386 (PE32)32-bit268 字节xor eax,eax; ret运行退出码 0，且这是当前加载器硬性长度下限64 位 AMD64 (PE32+)64-bit387 字节同上运行退出码 0关键结论：“最小”不是玄学，而是当前加载器划死的硬边界：32 位：267 字节被拒、268 字节通过 —— 差一个字节都不行。64 位：受 FileAlignment ≥ 0x80、可选头 ≥ 0x88、必须有可执行区段三条硬约束锁定在 387。为什么把 268 字节的 32 位方案“翻译”到 64 位，反而膨胀到 387？因为 64 位加载器把三条让 32 位变小的“历史宽松行为”全部堵死了。本文将把来龙去脉、每一个字节、每一组实验都讲清楚。目录缘起：我想知道最小的 EXE 到底多大前置知识：PE 文件到底长什么样一次“正经”的最小化：先写出 387 字节的 64 位 EXE差点翻车：387 不是全局最小第二次最小化：268 字节的 32 位 EXE（一个字节也不能再少）为什么 32 位能更小，而 64 位不能？逐条对照字节级拆解：268 与 387 到底都有什么完整实验方法（可直接复现）代码清单结论与展望参考与延伸阅读1. 缘起：我想知道最小的 EXE 到底多大“一个能跑的 Windows 可执行文件，理论上最小能到多少字节？”这个问题一直很吸引我。网上最著名的答案之一是 TinyPE-on-Win10 那个 268 字节、还能弹消息框的 PE。于是我也想在自己这台 Windows 11 上复现一次，亲手做出“最小”的 EXE。但“最小”有个麻烦的定义问题：如果只用 64 位 AMD64、并走“标准一区段”路线，你会得到 387 字节。如果切到 32 位 i386、并复用头部字节当代码，你能压到 268 字节。而“还能不能再小”，取决于当前加载器到底接受多小的空洞——这无法从规格书中直接推导，必须靠实验验证。这篇博客的核心，就是用实验而非脑补，把这几个数字的边界一一敲实。2. 前置知识：PE 文件到底长什么样Windows 可执行文件（EXE / DLL）遵循 PE（Portable Executable） 格式。逐字节手工构造时，我们主要关心这几块（按文件中的先后顺序）：+------------------+-------------------------------------------+ | DOS 头/存根 | 开头必须是 'MZ'；文件偏移 0x3C 处是 e_lfanew | | | 它告诉加载器“PE 头开始于文件哪个偏移” | +------------------+-------------------------------------------+ | PE 签名 | 4 字节 'PE\0\0' | +------------------+-------------------------------------------+ | COFF 头 (20B) | 机器类型（i386/AMD64）、区段数量、可选头长度等| +------------------+-------------------------------------------+ | 可选头 | PE32 (0x10B) 或 PE32+ (0x20B)；入口点、基址、| | | 对齐、子系统和目录指针都在这里 | +------------------+-------------------------------------------+ | 区段头(们) 40B/个| 每个区段（.text/.data/...）的虚拟地址、文件偏移| +------------------+-------------------------------------------+ | 区段数据 | 真正的机器码 / 数据 | +------------------+-------------------------------------------+关键点（也是后面全部“最小化手段”的抓手）：DOS 头不必是完整的 64 字…