onsdag den 14. december 2011

Game hacking: VTable hooking explanation and example

When hacking a game, you will sometimes need to hook some of the engine's functions. In case of the function that you want to hook is in a so called virtual method table(class with virtual functions), hooking the functions is very easy.
A virtual function is essentially a function in a class, that allows inherited classes to overwrite that function. On assembly level, this means that the compiler generates a table of pointers to functions, which are then called instead of calling the function directly. This allows inherited classes to easily overwrite the virtual function in the class instance. ex:

2521a783
2521a825
25220052
25228252
As you can see, it consists merely pointers, that point to the functions themselves.
(I am working on my paint skills):







With this information, we can actually easily replace the address that exists within the vmt with a pointer to our own function, while preserving the original function pointer for later use.
I've coded a little example code here just for the sake of consistency;

 
class VirtualTable
{
public:

virtual void VirtualFunction01( void );
};


void VirtualTable::VirtualFunction01( void )
{
cout << "VirtualFunction01 called" << endl;
}

//we use this to store and call the original function inside our custom one
typedef void ( __thiscall* VirtualFunction01_t )( void* thisptr );
VirtualFunction01_t g_org_VirtualFunction01;

//our custom function
void __fastcall hk_VirtualFunction01( void* thisptr, int edx )
{
cout << "Custom function called" << endl;

//call the original function
g_org_VirtualFunction01(thisptr);
}


int _tmain(int argc, _TCHAR* argv[])
{
VirtualTable* myTable = new VirtualTable();

//get the pointer to the actual virtual method table from our pointer to our class instance
void** base = *(void***)myTable;

DWORD oldProtection;
//one way to remove page protection(not the best but this is an example only)
VirtualProtect( &base[0], 4, PAGE_EXECUTE_READWRITE, &oldProtection );
//save the original function
g_org_VirtualFunction01 = (VirtualFunction01_t)base[0];
//overwrite
base[0] = &hk_VirtualFunction01;
//restore page protection
VirtualProtect( &base[0], 4, oldProtection, 0 );

//call the virtual function (now hooked) from our class instance
myTable->VirtualFunction01();

system("pause");

return 0;
}
Output:
Custom function called
VirtualFunction01 called