Creating small executables with Microsoft Visual Studio

Starting with an empty project, I will show you how to use Microsoft Visual Studio 2010 to compile your C code without the usual bloating that the compiler adds automatically. This article will just feature C code, I may extend this blog entry for usage with C++ at a later point.

In the empty workspace, create a new file called tinyexe.c with following content:

#include <windows.h>

void main()
{
  MessageBoxA(0, "Hello", "world!", MB_OK);
  ExitProcess(0);
}

Switch the solution configuration from Debug to Release and compile the project (F7 is the default key for this). The output will be a 6.656 byte sized exe file. Could have been worse I would say 🙂 Let’s have a look at what is inside the exe, I am using the file view of Total Commander which will give you a nice view of the file content and showing zero bytes as whitespace.

This is the portable executable header, containing 5 section definitions (.text, .rdata, .data, .rsrc, .reloc).

The code section contains way more code than needed for calling the 2 Windows APIs in our code.

This section contains the import table, import address table as well as a reference to a .pdb debug info file. In the list of imported API functions you will see way more APIs than the 2 that we actually intended to use. The reference to mscvrt.dll means that this exe uses functions of the Microsoft Visual C Run-Time Library, which we did not intend to do. The Visual Studio compiler adds the crt library initialization code by default which then calls our main function.

At the end of this exe file you can see a manifest xml file followed by relocation data, both features we do not need.

Lets see how we can pimp that exe (without using external tools) now:

  • To get rid of the console window that pops up on program start set the project option Linker/System/Subsystem to Windows (/SUBSYSTEM:WINDOWS)
  • Set the project option Linker/Advanced/Entry Point to main. This will remove the crt library initialization code and since we don’t use any C standard library functions also the reference to the msvcrt dll.
  • Set Linker/Debugging/Generate Debug Info to No. This will remove the .pdb debug information file reference.
  • Set Linker/Manifest File/Generate Manifest to No. Now the manifest xml is removed.
  • Set Linker/Advanced/Randomized Base Address to No. We don’t need relocations for a normal non library project.

Compile the project again and the resulting exe file will now be 2.048 byte small and look like this:

Between the DOS stub and PE header you can find the undocumented Rich Signature from Microsoft, which is present in newer Visual Studio compiler versions and is not needed, so you could zero those bytes out.

You may also like