如何使用MinGW创建微小的PE(Win32)可执行文件

pts*_*pts 7 c winapi mingw portable-executable

我有以下C程序:

#include <windows.h>
void __cdecl mainCRTStartup() {
  DWORD bw;
  HANDLE hfile = GetStdHandle(STD_OUTPUT_HANDLE);
  WriteFile(hfile, "Hello, World!\r\n", 15, &bw, 0);
  ExitProcess(0);  /* Needed for successful (0) exit. */
}
Run Code Online (Sandbox Code Playgroud)

我使用以下命令行使用GCC 4.8.2编译它:

i686-w64-mingw32-gcc -s -Os -fno-ident -fno-stack-protector -fomit-frame-pointer \
-fno-unwind-tables -fno-asynchronous-unwind-tables -falign-functions=1  \
-mpreferred-stack-boundary=2 -falign-jumps=1 -falign-loops=1 -mconsole \
-nostdlib -nodefaultlibs -nostartfiles -o h.exe h.c -lkernel32
Run Code Online (Sandbox Code Playgroud)

生成的.exe文件长度为2048字节.如何使用MinGW将其缩小,最好是1024字节,或者(甚至更好)最多512字节?

我更喜欢没有编写汇编代码的解决方案,但我也对组装解决方案感兴趣.

我试图-Wl,-N减少部分(段)的数量,但是在Wine中运行.exe时会导致段错误.

文章认为,480个字节是可能的.它使用以下设置:

#pragma comment(linker, "/FILEALIGN:16")
#pragma comment(linker, "/ALIGN:16")// Merge sections
#pragma comment(linker, "/MERGE:.rdata=.data")
#pragma comment(linker, "/MERGE:.text=.data")
#pragma comment(linker, "/MERGE:.reloc=.data")
#pragma optimize("gsy", on)
Run Code Online (Sandbox Code Playgroud)

不幸的是,这些#pragma不适用于MinGW GCC.有等价物吗?

这里,我能够找到GCC标志 -Wl,--section-alignment,16,--file-alignment,16,将.exe大小降低到752字节..exe似乎适用于Wine.

通过修改链接脚本我能够合并.data.rdata,并深入到736个字节.除了以上那些之外,我正在使用这些GCC标志:-Wl,--section-alignment,16,--file-alignment,16,-T,tinygccpe.scr.

我还在寻找相当于MinGW的/MERGE.

这个问题类似,但它不会尝试低于9000字节.

我也在寻找一个strip工具(stripMinGW中的命令不会进一步减小.exe大小),它可以删除DOS存根(在偏移量0x40和0x80之间,它包含This program cannot be run in DOS mode.,我们可以节省64个字节).此代码可以删除它,但它也会破坏.exe中的所有绝对偏移量.不幸的是ld,MinGW中的链接器无法删除DOS存根,它在文件中硬编码bfd/peXXigen.c,就在上面NT_SIGNATURE.

是否可以从.exe中删除更多标题,即加载程序不使用的标题?

pts*_*pts 5

这个问题在网上有大量文献,大约从 1995 年开始。

32 位和 64 位 Windows 的每个版本对于它们在 PE .exe 可执行文件中接受的标头值都有一组不同的规则。例如,Windows 7 接受段数为 0、段对齐方式为 4、文件对齐方式为 4 的 .exe 文件,而其他版本的 Windows(例如 Windows XP 和 2020 年最新的 Windows 10)则拒绝这些文件。

不过,可以创建小于 2048 字节的工作 .exe 文件。例子:

  • hh6d.golden.exe(584 字节)是可移植的:它适用于 Microsoft 发布的所有 Win32 实现以及 Wine。(在 Windows NT 3.1、Windows 95、Windows XP 和 Windows 10、Wine 1.6.2、Wine 5.0 上测试。)
  • hh2d.golden.exe(408 字节)适用于 Windows 95 及更高版本。(在 Windows 95、Windows XP、Windows 7 和 Windows 10 上测试)。
  • hh1.golden.exe(268 字节)在 Windows XP 上不起作用,在 Windows 7 上起作用,在 Windows 10 上不起作用。
  • 汇编源代码包含在pts-tinype存储库中。

这就是为什么短于 584 字节的可移植 Win32 PE .exe hello-world 不太可能被发布的原因:

  • 程序代码必须放入可执行节,并且该节的最早文件字节偏移量为 512,因为SectionAlignment 必须至少为 512,并且该节不能从文件开头开始。
  • hello-world 打印机 i386 Win32 机器代码的最小大小为 36 字节。(这不包括消息大小,因为消息可以存储在标头中的前 512 个字节内。)
  • 对于 KERNEL32.DLL,IMAGE_IMPORT_DESCRIPTORS 的最小大小为 20 字节。Windows 95 不允许在标头中使用此内容,因此必须将其放在文件字节偏移 512 之后。
  • IAT(导入地址表)的最小大小为 16 个字节:4 个字节用于 GetStdHandle,4 个字节用于 WriteFile,4 个字节用于 ExitProcess,4 个字节用于列表末尾。由于加载程序修改了这些地址,因此无法将它们放入标头(只读),因此必须将它们放在文件字节偏移 512 之后。
  • 如果将它们相加,我们将得到 512 + 36 + 20 + 16 = 584 字节。

小于 268 字节的 .exe 文件仅适用于早于 Windows XP 的 Windows 版本,并且不适用于 64 位 Windows 系统。

相关文献: