How to create miniature PE executables (Win32) using MinGW

I have the following C program:

#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. */ } 

I compile it with GCC 4.8.2 using the following command line:

 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 hc -lkernel32 

The generated .exe file has a length of 2048 bytes. How to make it smaller using MinGW, preferably no more than 1024 bytes or (even better) no more than 512 bytes?

I would prefer a solution without writing assembler code, but I am also interested in assembler solutions.

I tried -Wl,-N to reduce the number of partitions (segments), but this caused segfault when running .exe in Wine.

This article assumes 480 bytes are possible. The following settings are used:

 #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) 

Unfortunately, these #pragma do not work with MinGW GCC. Are there any equivalents?

Here I was able to find the GCC -Wl,--section-alignment,16,--file-alignment,16 flags -Wl,--section-alignment,16,--file-alignment,16 which reduce the .exe size to 752 bytes. .Exe seems to work in Wine.

.rdata linker script, I was able to combine .data and .rdata and .rdata to 736 bytes. I use these GCC flags in addition to the ones above: -Wl,--section-alignment,16,--file-alignment,16,-T,tinygccpe.scr .

I am still looking for the MinGW equivalent /MERGE .

This question is similar, but it is not trying to drop below 9000 bytes.

I am also looking for the strip tool (the strip command in MinGW no longer reduces the size of .exe) that can remove the DOS stub (which is between the offsets 0x40 and 0x80, it contains. This program cannot be run in DOS mode. , We could save 64 byte). This code may remove it, but it also violates all absolute offsets in .exe. Unfortunately, the ld linker in MinGW cannot remove the DOS stub; it is hard-coded in the bfd/peXXigen.c , just above NT_SIGNATURE .

Is it possible to remove more headers from .exe, that is, headers that the loader does not use?

+7
source share
1 answer

This question has extensive online literature dating back to 1995.

Each version of 32-bit and 64-bit Windows has a different set of rules about what header values ​​they accept in PE.exe executables. For example, Windows XP refuses to import 32-bit .exe files if they have at least 3 partitions, and their section alignment is 4096, and their file alignment is at least 512. (Command i686-w64-mingw32-gcc in question generates such executables.) Windows 7 does accept these .exe files, but it also accepts .exe files with 0 partitions, alignment of partition 4, alignment of file 4.

It is possible to create working .exe files of less than 2048 bytes in size. Example:

  • hh2.golden.exe (402 bytes) works on Windows XP, Windows 7 and above.
  • hh4.golden.exe (268 bytes) does not work in Windows XP, it works on Windows 7 and above.
  • Assembly source code included in the pts-tinype repo.

Files .exe less than 268 bytes in size only work on versions of Windows earlier than Windows XP, and they do not work on 64-bit Windows systems.

Related literature:

+2
source

Source: https://habr.com/ru/post/1263776/


All Articles