An easy solution used by programs such as self-extracting .zip files, is to simply append the data onto the end of the .exe file. The size of the .exe can be calculated from values in the header, which will give you the offset where the appended data begins. Here is an example C program that compiles with Borland Turbo C v2.01 (available as freeware) - note that I have omitted error checking for clarity:
#include <stdio.h>
int main(int argc, const char *argv[])
{
FILE *fSelf;
unsigned short lenFinalBlock, numBlocks;
unsigned long offEnd;
char trailing[256];
int len;
/* Open our own .exe file */
fSelf = fopen(argv[0], "rb");
/* Read part of the .exe header */
fseek(fSelf, 2, SEEK_SET);
fread(&lenFinalBlock, 2, 1, fSelf);
fread(&numBlocks, 2, 1, fSelf);
/* Calculate the size of the .exe from the header values */
offEnd = numBlocks * 512;
if (lenFinalBlock) offEnd -= 512 - lenFinalBlock;
/* Jump to the end of the .exe and read what's there */
fseek(fSelf, offEnd, SEEK_SET);
/* Just read it as a string - you'd presumably be using
some custom data format here instead */
len = fread(trailing, 1, 256, fSelf);
trailing[len] = 0;
printf("Trailing data (%d bytes @ 0x%lX):\n%s", len, offEnd, trailing);
fclose(fSelf);
return 0;
}
Once compiled to trailing.exe
you can use it like this:
C:\>trailing
Trailing data (0 bytes @ 0x2528):
I'm on Linux so I will append some example data using the shell:
$ echo Hello >> trailing.exe
Running it again shows it picking up the trailing data:
C:\>trailing
Trailing data (6 bytes @ 0x2528):
Hello