How to hack the virtual table?

The V-Table is an implementation detail.

The compiler is not required to use one (it just happens to be the easiest way to implement virtual functions). But saying that each compiler can (and does) implement it slightly differently as a result there is no answer to your question.

If you ask how do I hack a vtable for a program built with:

Compiler <X> Version <Y> Build <Z>

Then somebody may know the answer.


This works for 32-bit MSVC builds (it's a very simplified version of some production code that's been in use for well over a year). Note that your replacement method must explicitly specify the this parameter (pointer).

// you can get the VTable location either by dereferencing the
// first pointer in the object or by analyzing the compiled binary.
unsigned long VTableLocation = 0U;
// then you have to figure out which slot the function is in. this is easy
// since they're in the same order as they are declared in the class definition.
// just make sure to update the index if 1) the function declarations are
// re-ordered and/or 2) virtual methods are added/removed from any base type.
unsigned VTableOffset = 0U;
typedef void (__thiscall Base::*FunctionType)(const Base*);
FunctionType* vtable = reinterpret_cast<FunctionType*>(VTableLocation);

bool hooked = false;
HANDLE process = ::GetCurrentProcess();
DWORD protection = PAGE_READWRITE;
DWORD oldProtection;
if ( ::VirtualProtectEx( process, &vtable[VTableOffset], sizeof(int), protection, &oldProtection ) )
{
    vtable[VTableOffset] = static_cast<FunctionType>(&ReplacementMethod);

    if ( ::VirtualProtectEx( process, &vtable[VTableOffset], sizeof(int), oldProtection, &oldProtection ) )
        hooked = true;
}

void HackedVtable()
{
    cout << "Hacked V-Table" << endl;
}

class Base
{

public:
       virtual Test()  { cout <<"base";    }
       virtual Test1() { cout << "Test 1"; }
       void *prt;
       Base(){}
};

class Derived:public Base
{
    public: 
           Test() 
           {
                   cout <<"derived";
           }
};

typedef void (*FUNPTR)();
typedef struct
{
   FUNPTR funptr;
} VTable;


int main()
{

    Base b1;
    Base *b1ptr = &b;

    VTable vtable;
    vtable.funptr = HackedVtable;

    VTable *vptr = &vtable;
    memcpy ( &b1, &vptr, sizeof(long) );

    b1ptr->Test();

    //b1.Test(); // how to change this so that HackedVtable() should be called instead of Test()

    return 0;
}

Tags:

C++

Virtual