Code:
//File dllmain2.cpp
// Compile cl.exe /LD dllmain2.cpp
#pragma comment(lib, "user32.lib")
#include <windows.h>
#include <stdio.h>
bool HOOKED = false;
#pragma optimize("", off)
int _declspec(naked) _stdcall MsgBoxTramp (HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType)
{
__asm{
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
_emit 0xAA
_emit 0xAA
_emit 0xAA
_emit 0xAA
_emit 0xAA
ret
}
}
#pragma optimize("", on)
#pragma optimize("", off) //Turn optimisation off. Unreferenced code is removed by compiler optimization.
int _stdcall MyMessageBox(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType)
{
int retval;
char* NewText = (char*)malloc(256); // Just to indicate that malloc can be called. Not really relevant
strcpy(NewText, "You have been hooked!!!");
retval = MsgBoxTramp(hWnd, NewText, lpCaption, uType);
free (NewText);
return retval;
}
void HookMsgBox(void)
{
//Initialise our vars, get pointers as chars to BOTH our trampoline function _and_ the hook function
unsigned char NewData[5], OldData[5], TrampJump[5]; //This is a 5 byte hook, it could be more but I use Windows XP SP2..
unsigned char* MessageBoxPtr = (unsigned char*)&MessageBoxA;
unsigned char* HookTramp = (unsigned char*)&MsgBoxTramp;
DWORD OldProtect;
int i;
//First off, we fill our replacement code arrays with data:
//NewData will contain the bytes for the jmp to be installed.
//Make the first byte an E9, meaning jmp.
NewData[0] = 0xE9;
//Set the remaining 4 bytes to the address offset. An ‘E9 jmp’ tells the processor to increment or decrement its EIP, it doesn’t tell the processor what the EIP should be.
*(PDWORD)&NewData[1] = (DWORD)( (DWORD)MyMessageBox - ((DWORD)MessageBoxA + 5)); //Note the +5. The last byte of your jmp will be located at MessageBoxA+5, and this is where the address offset needs to be calculated from. (Change in address = New minus Old. Complex maths formula ain't it? ;> )
//TrampJump will contain the bytes where you that hardcode the jump back to MessageBox. It is technically fine for TrampJump to just have a “jmp [MessageBoxA+5]” tagged at the end of it, as the compiler can do that. But I don’t trust compilers.
TrampJump[0] = 0x68; //Push
*(PDWORD)&TrampJump[1] = (DWORD)MessageBoxA + 5; //Push Address, as I explained already. :>
VirtualProtectEx(GetCurrentProcess(), MessageBoxA, 10, PAGE_EXECUTE_WRITECOPY, &OldProtect); //Unprotect the target memory. 10 bytes for good measure.
for (i = 0; i < 5; i++){
OldData[i] = MessageBoxPtr[i]; //Grab the overwritten bytes
MessageBoxPtr[i] = NewData[i]; //Insert the new bytes. *MAKE SURE YOU DON’T CUT OFF PART OF AN INSTRUCTION!*
}
VirtualProtectEx(GetCurrentProcess(), MessageBoxA, 10, OldProtect, NULL); //Reprotect the memory.
VirtualProtectEx(GetCurrentProcess(), MsgBoxTramp, 25, PAGE_EXECUTE_WRITECOPY, &OldProtect);
for (i = 0; i < 5; i++){
HookTramp[i] = OldData[i]; //Make the first 5 bytes of the trampoline equal the bytes removed.
}
for (i = 0; i < 50; i++){
//Search for the last 5 bytes that you put aside for this push operation.
if (HookTramp[i] == 0xAA &&
HookTramp[i+1] == 0xAA &&
HookTramp[i+2] == 0xAA &&
HookTramp[i+3] == 0xAA &&
HookTramp[i+4] == 0xAA)
{
//Overwrite the bytes when found
HookTramp[i] = TrampJump[0];
HookTramp[i+1] = TrampJump[1];
HookTramp[i+2] = TrampJump[2];
HookTramp[i+3] = TrampJump[3];
HookTramp[i+4] = TrampJump[4];
break;
}
}
VirtualProtectEx(GetCurrentProcess(), MsgBoxTramp, 25, OldProtect, NULL);
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
LPVOID lpvReserved )
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
if(!HOOKED)
{
HookMsgBox();
HOOKED = true;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}