Guide

A detailed guide on how to use the plugin effectively, ensuring you maximize its features and functionality for your needs.

Hooking C/C++ Functions Dynamically in Any Language

It is a plugin that enables dynamic runtime hooking of C++ functions — including both virtual function table (vtable) hooks and code detour hooks. It’s based on the powerful polyhook2 backend and is designed to be easily integrated into your plugin or scripting environment.

This guide covers:

  • Hooking detour (raw function address) functions
  • Hooking virtual functions (by index or by function pointer)
  • Registering pre- and post-callbacks
  • Inspecting and modifying function arguments and return values
  • Unhooking and managing callbacks

Basic Concepts

What is a Hook?

A hook is a method to intercept function calls. You can:

  • Inspect/modify function arguments before the call (pre)
  • Observe/alter return value after the call (post)
  • Override or entirely skip the original function (supercede)

Types of Hooks

  • HookDetour: Hooks a standalone or static function.
  • HookVirtual: Hooks a class method via vtable index or function pointer.

Data Types

Use DataType enum to describe argument and return types:

enum class DataType : uint8_t {
  Void, Bool, Int8, UInt8, Int16, UInt16,
  Int32, UInt32, Int64, UInt64,
  Float, Double, Pointer, String
};

Use these consistently when describing function signatures to the hook APIs.

Hooking Functions

1. Detour Hook

Use HookDetour to hook a global/static function:

Callback* HookDetour(void* pFunc, DataType returnType, const plg::vector<DataType>& args, int varIndex);
  • pFunc: Pointer to the function to hook.
  • returnType: Return type using DataType.
  • args: List of argument types.
  • varIndex: Use -1 for normal calls; set if variable argument.

Example:

void* targetFunc = (void*) &DoSomething;
plg::vector<DataType> args = { DataType::Int32, DataType::Pointer };
Callback* cb = HookDetour(targetFunc, DataType::Void, args, -1);

2. Virtual Hook (by index)

Hook a method from an object’s vtable:

Callback* HookVirtual(void* pClass, int index, DataType returnType, const plg::vector<DataType>& args, int varIndex);

Example:

Callback* cb = HookVirtual(someObj, 3, DataType::Bool, { DataType::Pointer }, -1);

You can also get the vtable index from a function pointer:

int index = GetVTableIndex((void*) &MyClass::MyMethod);

3. Virtual Hook (by function pointer)

Instead of using vtable index:

Callback* HookVirtualByFunc(void* pClass, void* pFunc, DataType returnType, const vector<DataType>& args, int varIndex);

Unhooking

  • UnhookDetour(void* pFunc)
  • UnhookVirtual(void* pClass, int index)
  • UnhookVirtualByFunc(void* pClass, void* pFunc)
  • UnhookAll() – removes all hooks
  • UnhookAllVirtual(void* pClass) – removes all vtable hooks for a class

Callback System

1. Register Callback

bool AddCallback(Callback* cb, CallbackType type, CallbackHandler handler);
  • type: CallbackType::Pre or CallbackType::Post
  • handler: Function pointer

Handler Signature:

ReturnAction myHandler(Callback* cb, const Parameters* params, int32_t count, const Return* ret, CallbackType type);

Use this to inspect or modify arguments and returns.

2. ReturnAction

enum class ReturnAction : int32_t {
  Ignored,   // Don't interfere
  Handled,   // Interfere but call real function
  Override,  // Call real function but change return value
  Supercede  // Skip real function entirely
};

Access Arguments & Return

Getting arguments:

int val = GetArgumentInt32(params, 0);
void* ptr = GetArgumentPointer(params, 1);

Setting arguments:

SetArgumentInt32(params, 0, 42);
SetArgumentPointer(params, 1, myPtr);

Getting return value:

float retVal = GetReturnFloat(ret);

Overriding return:

SetReturnFloat(ret, 1.0f);
return ReturnAction::Supercede;

Full Example

Hook int Add(int a, int b) and modify result:

ReturnAction preAdd(Callback* cb, const Parameters* params, int32_t count, const Return* ret, CallbackType type) {
  int32_t a = GetArgumentInt32(params, 0);
  int32_t b = GetArgumentInt32(params, 1);
  SetArgumentInt32(params, 0, a + 1);
  SetArgumentInt32(params, 1, b + 1);
  return ReturnAction::Handled;
}

ReturnAction postAdd(Callback* cb, const Parameters* params, int32_t count, const Return* ret, CallbackType type) {
  int32_t result = GetReturnInt32(ret);
  SetReturnInt32(ret, result * 2);
  return ReturnAction::Override;
}

void setup() {
  auto cb = HookDetour((void*)&Add, DataType::Int32, { DataType::Int32, DataType::Int32 }, -1);
  AddCallback(cb, CallbackType::Pre, preAdd);
  AddCallback(cb, CallbackType::Post, postAdd);
}

Utility Functions

  • FindDetour, FindVirtual, FindVirtualByFunc: Lookup hooks
  • AreCallbacksRegistered, IsCallbackRegistered: Introspection
  • GetFunctionAddr: Get function pointer (possibly detoured)
  • GetOriginalAddr: Get trampoline/original function

Summary

ActionFunction
Hook DetourHookDetour
Hook Virtual (Index)HookVirtual
Hook Virtual (Func)HookVirtualByFunc
Add CallbackAddCallback
Access ArgsGetArgumentX, SetArgumentX
Access ReturnGetReturnX, SetReturnX
UnhookUnhookDetour, UnhookVirtual, etc.
Get AddressesGetFunctionAddr, GetOriginalAddr

Use this guide as a reference when developing with your PolyHook-based plugin. Always validate pointer arguments and ensure type safety when casting arguments or return values.