Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Understanding C++ Virtual Tables and VTable Hooking

Tech 1

Exploring Virtual Tables (VTables)

To understand the lifecycle and structure of virtual tables in C++, let's start with a set of test classes involving virtual functions and multiple inheritance.

Virtual Function Classes

#include <cstdio>

class SampleClass {
public:
    int internalValue;

    virtual void displayValue() {
        printf("Value = 0x%x\n", internalValue);
    }
};

class AbstractBaseA {
public:
    int dataA;
    virtual void executeTaskA() = 0;
};

class AbstractBaseB {
public:
    int dataB;
    virtual void executeTaskB() = 0;
};

class MultiDerived : public AbstractBaseA, public AbstractBaseB {
public:
    void executeTaskA() override {
        printf("Task A Data = 0x%x\n", AbstractBaseA::dataA);
    }

    void executeTaskB() override {
        printf("Task B Data = 0x%x\n", AbstractBaseB::dataB);
    }
};

Test Execution

void runTest() {
    SampleClass stackObj;
    SampleClass* heapObj = new SampleClass();

    heapObj->internalValue = 0x8888;
    heapObj->displayValue();

    stackObj.internalValue = 0x777;
    stackObj.displayValue();

    delete heapObj;
}

void runMultiInheritanceTest() {
    MultiDerived derivedObj;
    derivedObj.executeTaskA();
}

1. Where is the VTable Located?

Using a debugger like WinDbg, we can inspect the memory attributes of a vtable address. Typically, the vtable is found in a region mapped to the binary image (RegionUsageImage) with read-only permissions.

2. Do Instances of the Same Class Share a VTable?

Yes, every instance of the same class points to the same virtual table location. If you check the memory address of the first 4/8 bytes (the vtable pointer) of multiple objects, they will point to the same memory address in the global data section.

3. Is the VTable Initialized at Runtime?

No, the vtable is generally stored in the .rdata section of the PE (Portable Executable) file. This section is used for constant data and is marked as read-only.

By calculating the Virtual Address (VA) and checking the raw bytes in the PE file (accounting for little-endian storage), we can see that the function pointers with in the vtable are already populated by the compiler/linker. The loader simply performs relocations if the module base address changes.

4. VTable Layout in Multiple Inheritance

In multiple inheritance, the derived class object contains the data members of each parent class in the order they were inherited. Consequently, the object holds multiple vtable pointers—one for each base class that contains virtual functions.

5. What is VTable Hooking?

If you are familiar with IAT (Import Address Table) hooking, vtable hooking follows a similar logic. There are two primary methods:

  • Static Binary Patching: Directly modifying the function pointers within the vtable in the PE file to point to a custom function.
  • Memory Hooking: Modifying the vtable pointers in memory after the module has loaded. This requires changing page protections (e.g., using VirtualProtect) to make the read-only .rdata section writable.

Implementation of Memory-Based VTable Hooking

#include <windows.h>
#include <tchar.h>

class VTableHijacker {
public:
    // Define a member function pointer type for the target signature
    typedef void (VTableHijacker::*FuncPtr)();

    static BOOL ApplyHook(void* vtableOffsetVA) {
        HMODULE hModule = GetModuleHandle(NULL);
        if (!hModule) return FALSE;

        // Calculate the actual memory address after relocation
        FuncPtr* targetEntry = reinterpret_cast<FuncPtr*>(
            reinterpret_cast<UINT_PTR>(vtableOffsetVA) + reinterpret_cast<UINT_PTR>(hModule)
        );

        DWORD oldProtect;
        // Remove write protection
        if (VirtualProtect(targetEntry, sizeof(FuncPtr), PAGE_READWRITE, &oldProtect)) {
            FuncPtr hookFunc = &VTableHijacker::detourDisplay;
            *targetEntry = hookFunc;
            VirtualProtect(targetEntry, sizeof(FuncPtr), oldProtect, &oldProtect);
            return TRUE;
        }
        return FALSE;
    }

private:
    void detourDisplay() {
        printf("The function has been successfully hijacked!\n");
    }
};

This hook can be triggered during DLL injection via DllMain:

BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved) {
    if (reason == DLL_PROCESS_ATTACH) {
        // Provide the RVA of the specific virtual function entry
        VTableHijacker::ApplyHook((void*)0x0007DF2C);
    }
    return TRUE;
}

Analysis of Hooking Results

After injecting the hook into a target process, we observe an interesting phenomenon: objects allocated on the heap are successfully hooked, but local stack objects might still execute the original code.

Why does this happen?

When inspecting the disassembly, we find that compilers often optimize virtual function calls. If the compiler can determine the exact type of the object at compile time (as is often the case with local stack objects), it may bypass the vtable entirely and perform a direct function call to save overhead. This is known as static dispatch or devirtualization. The vtable is only reliably used when calling functions through a pointer or reference where the polymorphic type is determined at runtime.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.