Just wanted to post the source code of a nifty little program I recently made to make GunZ auto-load a DLL on start.
RELEASE NOTES:
The patch method uses a codecave and will use addresses 0x005E5DFF - (strlen(dllname) + 1) through to 0x005E5E15 (inclusive). I don't suggest putting your own codecaves in there. You can always change the address of it if need be, but you have to patch the jmp...
There are a couple TODOs in the source, if anyone wants to DO this, it would be great if you posted an updated version. Thanks.
Compiled with VSTS2008. Will work with other Microsoft compilers and possibly GCC. I have not tested either of those though.Code:#include <cstdlib>
#include <cstdio>
#include <windows.h>
// 4 megabytes
#define MAX_BUFFER_SIZE (1024*1024*4)
// The size of the buffer after reading in the file.
DWORD actualSizeOfBuffer = 0;
// The input and output files.
BYTE fileBuffer [MAX_BUFFER_SIZE];
enum ERROR_CODES
{
INVALID_NUMBER_OF_ARGUMENTS = 1,
COULD_NOT_OPEN,
COULD_NOT_READ,
COULD_NOT_WRITE,
COULD_NOT_SEEK,
BUFFER_OVERFLOW,
BACKUP_FAILED
};
int UpdateBuffer(DWORD address, BYTE* data, int len)
{
// The offset represents the position in the file the address would be at.
// It's the address minus the image base.
// TODO: Make it automatically detect the image base.
DWORD offset = address - 0x00400000;
// Don't apply the patch if it's out of range.
if(offset > actualSizeOfBuffer)
{
printf_s("%s",
"Buffer overflow!"
);
return BUFFER_OVERFLOW;
}
memcpy_s(fileBuffer + offset, actualSizeOfBuffer - offset, data, len);
return 0;
}
int main(int argc, char** argv)
{
int ret;
// Display help if an invalid number or arguments were passed.
if(argc != 3)
{
printf_s("%s",
"Usage:\n"
"DLLAutoLoader.exe [gunz.exe] [MyCoolDll.dll]\n"
"Where [gunz.exe] is the path to the gunz we'll be patching\n"
"and [MyCoolDll.dll] is the path to the dll we'll be loading."
);
return INVALID_NUMBER_OF_ARGUMENTS;
}
// TODO: Detect an invalid file for the patch. (filesize is a possibility, so is
// determining the bytes at the patch locations and making sure they match
// expected values.
// Just to be safe, make a backup of the file.
char temp[MAX_PATH] = { 0 };
strcpy_s(temp, MAX_PATH, argv[1]);
strcat_s(temp, MAX_PATH, ".bak");
if(!CopyFileA(argv[1], temp, true))
{
printf_s("%s",
"Could not create a backup."
);
return BACKUP_FAILED;
}
// We have the correct number or arguments. Open up gunz.exe
FILE* fGunz = NULL;
if(fopen_s(&fGunz, argv[1], "rb"))
{
printf_s("%s %s %s",
"Could not open", argv[1], "for reading."
);
return COULD_NOT_OPEN;
}
// Copy the entire file into the input buffer.
if(!(actualSizeOfBuffer = fread_s(fileBuffer, MAX_BUFFER_SIZE, 1, MAX_BUFFER_SIZE, fGunz)))
return COULD_NOT_READ;
fclose(fGunz);
if(actualSizeOfBuffer == MAX_BUFFER_SIZE)
return BUFFER_OVERFLOW;
// Update the entry point.
UpdateBuffer(0x00574255, (BYTE*)
"\xE9\xA5\x1B\x07\x00" // jmp [addr of codecave]
"\x90" // nop
"\x90", // nop
7
);
// The contents of the codecave that will be copied into the buffer.
BYTE codecave[] = {
// vvvv vvvv vvvv vvvv <- That's where the address of the dll name goes.
0x68, 0x00, 0x00, 0x00, 0x00, // push [stringPtr]
0xE8, 0x72, 0xBF, 0x21, 0x7C, // call kernel32.LoadLibraryA
0x83, 0xF8, 0x00, // cmp eax, 0
0x75, 0x07, // jne [push 60] --------------------------------------------
0x6A, 0x00, // push 0 |
0xE8, 0xFD, 0x6C, 0x23, 0x7C, // call kernel32.ExitProcess |
// |
// Here begins the emulation of commands we overwrote with our jump to the codecave. |
0x6A, 0x60, // push 60 <-------------------------------------------------
0x68, 0x48, 0x91, 0x60, 0x00, // push offset 0x00609148
0x39, 0x3B, 0xE4, 0xF8, 0xFF // jmp [after the instructions we overwrote]
};
// Go to the string.
int fullStringSize = strlen(argv[2]) + 1;
DWORD stringPtr = 0x005E5DFF - fullStringSize;
// Write in the dll's name.
if(ret = UpdateBuffer(stringPtr, (BYTE*)argv[2], fullStringSize))
return ret;
// Fix the codecave with the dll's address.
memcpy_s(codecave + 1, sizeof(codecave) - 1, &stringPtr, 4);
// Finally, update the buffer with the codecave.
if(ret = UpdateBuffer(0x005E5DFF, codecave, sizeof(codecave)))
return ret;
if(fopen_s(&fGunz, argv[1], "wb"))
{
printf_s("%s %s %s",
"Could not open", argv[1], "for writing."
);
return COULD_NOT_OPEN;
}
// Dump the buffer back into the file.
if(!fwrite(fileBuffer, 1, actualSizeOfBuffer, fGunz))
return COULD_NOT_WRITE;
printf("%s",
"Success!"
);
return 0;
}

