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



我有以下C程序:

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

我用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

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

我更喜欢不编写汇编代码的解决方案,但我也对汇编解决方案感兴趣。

我尝试过-Wl,-N来减少节(段)的数量,但在Wine中运行.exe时会导致segfault。

本文建议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)

不幸的是,这些#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

我仍在寻找相当于/MERGE的MinGW。

这个问题是类似的,但它并不试图低于9000字节。

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

是否可以从.exe中剥离更多的标头,即加载程序不使用的标头?

这个问题从1995年开始就有大量的网络文献。

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

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

  • hh6d.golden.exe(584字节)是可移植的:它适用于微软发布的所有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 repo中包含的程序集源代码

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

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

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

相关文献:

  • https://www.codejuggle.dj/creating-the-smallest-possible-windows-executable-using-assembly-language/
  • http://pferrie.host22.com/misc/tiny/pehdr.htm
  • https://drakopensulo.wordpress.com/2017/08/06/smallest-pe-executable-x64-with-every-byte-executed/
  • http://www.phreedom.org/research/tinype/
  • http://www.pouet.net/topic.php?which=9565
  • http://www.crinkler.net/
  • https://code.google.com/archive/p/corkami/wikis/PE.wiki

最新更新