Search code examples
c++vtable

Is it possible to change any func pointer in vtable?


This is an academic question. I made a macro to call and get a pointer to a virtual function through a vtable. But changing the vfunc address variable causes a memory corruption. So it turns out that this memory area is protected from exploits?

Its classic implementation. I use GCC (MinGW) for 64 bits programs, the compiler adds a pointer to the vtable (array) of its class at the first hidden field of the object.

#define VTABLE_CALL(FUNC_TYPE, OBJECT, OFFSET, ...) \
    ((FUNC_TYPE)(*((size_t**)&(OBJECT))[(OFFSET)]))(__VA_ARGS__)

#define VTABLE_GET(OBJECT, OFFSET) \
    ((void*)((*(size_t**)&(OBJECT))[(OFFSET)]))

#define VTABLE_SET(OBJECT, OFFSET, NEW_FUNC_P) \
((*((size_t***)&(OBJECT))[(OFFSET)]) = (size_t*)(NEW_FUNC_P))

So, thats code gives SegFault

class A {
virtual void foo(void) { printf("Test\n"); }
};

int main()
{
    typedef void (*VMethod) (void*); // void* for "this"

    A a; // our object with first hidden vTablePtr;
    VMethod vm;

    VTABLE_CALL(VMethod, a, 0, &a); // call A::foo

    vm = (VMethod) VTABLE_GET(a, 0);
    vm(&a); // call again A::foo

    /* replace the pointer to ourselves */
    VTABLE_SET(a, 0, vm); // segmentation fault

    /* foot shot completed */
    return 0;
}

Solution

  • Vtables, like constants, are loaded and mapped read-only. A vtable is never intended to be modifiable.

    To do that, you would need to change the way loading and mapping is done, possibly by changing the assembly or object code to mark the section read-write, or to do another mapping at run time after startup (I don't know if that's even doable).