Now onto some examples of how to hook into the unreal engine using vtables. I will be using the vmthooks library written by Casual_Hacker over at Game/Deception to abstract the whole hooking process. If you wish to adapt your own feel free to do so.
You will also need an SDK for the game you are hacking (uNrEaL has released alot for the unreal engine).
First we would create a new DLL. The OnAttach function is what will be called when you inject your DLL into the game.
Basic stuff really. Then we will need to declare some global variables and includes that we will be using later one. You can do this in a separate header if you like, or not.
BOOL WINAPI DllMain ( HMODULE hModule, DWORD dwReason, LPVOID lpReserved )
if ( dwReason == DLL_PROCESS_ATTACH )
If you aren't sure what these will be used for, I will get to that later. Next you will need to start by implementing the OnAttach function and the first thing you need to do is find an instance of the object you want to hook. Good classes to hook for the unreal engine are the "HUD class", the "Viewport class" and the "PlayerController". In my example I'll be hooking the viewport class, as it allows engine drawing in postrender.
#pragma once //Header guard
#include <windows.h> // duh
#include "vmthooks.h" //vmt hooking class
#include "SDKheaders.h" //SDK headers
toolkit::VMTHook* hook; //Pointer to the VMTHook class
typedef void (__stdcall *ProcessEvent ) ( UFunction*, void*, void* ); //typedef for the processevent function pointer
ProcessEvent pProcessEvent = NULL; //pointer to original processevent
UFunction *pUFunc = NULL; //pointers to processevent arguements
void *pParms = NULL;
void *pResult = NULL;
I'll leave it up to you to find the viewport, it shouldn't be hard and there are many ways to do it. (tip: use the object dump (GObjects). Next we hook the object using the VMThook class. This will allow you to manipulate teh vtable. Make sure you store a pointer to the old pProcesEvent. Its at index 60 for APB, not sure about other unreal games.
UObject* viewport = getViewport(); //get a pointer to the viewport
hook = new toolkit::VMTHook(viewport); //hook object
pProcessEvent = hook->GetMethod<tProcessEvent>(60); //save the orginal funtion in global variable
hook->HookMethod(&ProcessEventHooked, 60); //replace the orginal function with the hooked function
Then proceed by replacing the Vtable with a copy( Don't modify the orginal or your hack will be much easier to detect) and now replace the pointer at the proper index with a pointer to your own hooked function, which we still need to make.
This is an empty template for the a hooked processevent function (thanks lowHertz!). I'll try to explain briefly what goes on here (as far as my understanding of it goes).
void __declspec(naked) ProcessEventHooked ()
__asm mov pCallObject, ecx; //get caller from ecx register and save it in pCallObject
mov eax, dword ptr [esp + 0x8]
mov pUFunc, eax
mov eax, dword ptr [esp + 0xC]
mov pParms, eax
mov eax, dword ptr [esp + 0x10]
mov pResult, eax
} // Manually get the proper parameters for the function
__asm pushad //Save registers on stack
//Do stuff here!
__asm popad //restore registers from stack
} //put parameters on stack and call the orginal function
__declspec(naked) is a calling convention that basicly leaves it to the programmer to prepare and clean the stack for the function. Don't ask me for details, I basicly c&p this from lowHertz :P.
With the first line we take a pointer from the ECX register, this pointer points to the object that called the function. Since in my method we already have a pointer to the correct object this is not really necessary.
The block that follows is asm for putting the arguments (that the orginal function got called with) into the global variables you declared earlier. You also need these to call the orginal function later.
pushad saves the registers on the stack. So now you can execute whatever code you want and afterwards it restores the registers to their orginal state by popping them off the stack with popad.
The last bit pushes the arguments onto the stack and calls the orginal function, which you stored earlier. If all is well then the orginal function executes properly and the game resumes as it would usually.
Edit: things above used APB as example