Skip to main content

Overview

Virtual Method Table (VMT) hooking is a technique used to intercept C++ virtual function calls by replacing function pointers in an object’s virtual table. This is useful for hooking class methods in games and applications. The VMT hooking API in libmem provides a complete set of functions to create, manage, and clean up VMT hooks.

lm_vmt_t Structure

The lm_vmt_t structure is used to manage VMT hooks:
typedef struct lm_vmt_entry_t {
    lm_address_t           orig_func;
    lm_size_t              index;
    struct lm_vmt_entry_t *next;
} lm_vmt_entry_t;

typedef struct lm_vmt_t {
    lm_address_t   *vtable;
    lm_vmt_entry_t *hkentries;
} lm_vmt_t;
vtable
lm_address_t*
Pointer to the virtual method table being managed.
hkentries
lm_vmt_entry_t*
Linked list of hooked entries, storing original function pointers and their indices.

LM_VmtNew

Creates a new VMT manager from the VMT at vtable.

Signature

lm_bool_t LM_VmtNew(
    lm_address_t *vtable,
    lm_vmt_t     *vmt_out
);

Parameters

vtable
lm_address_t*
required
The virtual method table to manage.
vmt_out
lm_vmt_t*
required
A pointer to the VMT manager that will be populated by this function.

Returns

LM_TRUE on success, LM_FALSE on failure.

LM_VmtHook

Hooks the VMT function at index from_fn_index in the VMT managed by vmt, changing it to to.

Signature

lm_bool_t LM_VmtHook(
    lm_vmt_t    *vmt,
    lm_size_t    from_fn_index,
    lm_address_t to
);

Parameters

vmt
lm_vmt_t*
required
The VMT manager.
from_fn_index
lm_size_t
required
The index of the VMT function to hook.
to
lm_address_t
required
The function that will replace the original VMT function.

Returns

LM_TRUE on success, LM_FALSE on failure.

LM_VmtUnhook

Unhooks the VMT function at index fn_index in the VMT managed by vmt, restoring the original function.

Signature

lm_bool_t LM_VmtUnhook(
    lm_vmt_t *vmt,
    lm_size_t fn_index
);

Parameters

vmt
lm_vmt_t*
required
The VMT manager.
fn_index
lm_size_t
required
The index of the VMT function to unhook.

Returns

LM_TRUE on success, LM_FALSE on failure.

LM_VmtGetOriginal

Returns the original VMT function at index fn_index in the VMT managed by vmt. If the function has not been hooked before, it returns the function pointer at that index in the VMT array.

Signature

lm_address_t LM_VmtGetOriginal(
    const lm_vmt_t *vmt,
    lm_size_t       fn_index
);

Parameters

vmt
const lm_vmt_t*
required
The VMT manager.
fn_index
lm_size_t
required
The index of the VMT function to query.

Returns

The original VMT function at index fn_index in the VMT managed by vmt.

LM_VmtReset

Resets all the VMT functions back to their original addresses.

Signature

lm_void_t LM_VmtReset(
    lm_vmt_t *vmt
);

Parameters

vmt
lm_vmt_t*
required
The VMT manager.

LM_VmtFree

Frees the VMT manager, restoring everything.

Signature

lm_void_t LM_VmtFree(
    lm_vmt_t *vmt
);

Parameters

vmt
lm_vmt_t*
required
The VMT manager.

Example

#include <libmem/libmem.h>

// Original function pointer type
typedef void (*render_func_t)(void *thisptr);

// Hook function
void hk_render(void *thisptr)
{
    printf("Render function hooked!\n");
    
    // Call the original function if needed
    // render_func_t orig = (render_func_t)LM_VmtGetOriginal(&vmt, 5);
    // orig(thisptr);
}

int main()
{
    // Get the object's vtable pointer
    void *object = get_game_object();
    lm_address_t *vtable = *(lm_address_t **)object;
    
    lm_vmt_t vmt;
    
    // Create a VMT manager
    if (!LM_VmtNew(vtable, &vmt)) {
        printf("Failed to create VMT manager\n");
        return 1;
    }
    
    // Hook the render function at index 5
    if (LM_VmtHook(&vmt, 5, (lm_address_t)hk_render)) {
        printf("[*] Render function hooked successfully\n");
    }
    
    // ... do something ...
    
    // Unhook the render function
    if (LM_VmtUnhook(&vmt, 5)) {
        printf("[*] Render function unhooked\n");
    }
    
    // Or reset all hooks
    // LM_VmtReset(&vmt);
    
    // Free the VMT manager when done
    LM_VmtFree(&vmt);
    
    return 0;
}

Build docs developers (and LLMs) love