2026-07-03 22:22:19 +01:00
2026-07-03 22:22:19 +01:00
2026-07-03 22:00:03 +01:00
2026-07-03 02:00:27 +01:00
2026-07-03 22:22:19 +01:00
2026-07-02 20:09:18 +00:00
2026-07-03 22:00:03 +01:00

libradhook

A minimal, cross-platform inline function hooking library for x86-64 and AArch64, targeting Windows and Android, built as a lightweight alternative to libraries like MinHook and Dobby with a flat, C-style, handle-based API.

Features

  • Inline hooking on x86-64 and AArch64
  • Vtable hooking via direct slot swapping, no trampoline required
  • Windows and Android support
  • Flat C API with opaque handles
  • Typed convenience overload of RadHookCreate for function pointers
  • Trampolines to call the original function from within a detour
  • Enable / disable / destroy individual hooks, or all hooks at once
  • Deferred enable/disable via a queue, applied atomically in one pass
  • Hook enumeration and introspection (target, detour, trampoline, enabled state)
  • Human-readable status strings
  • Runtime version query for ABI sanity checks
  • Builds as a static or shared library via CMake

Requirements

  • CMake 3.21+
  • A C++20 compiler (msvc, gcc, or clang)
  • Android NDK (only if targeting android)

Building

CMake

cmake -S . -B build
cmake --build build

Useful options:

Option Default Description
BUILD_SHARED_LIBS ON Build radhook as a shared library instead of static
RADHOOK_BUILD_TESTS ON when top-level Build the test suite

Build.ps1

A helper PowerShell script is provided for common build targets:

./Build.ps1 -Target msvc -Config Release    # msvc, release, shared lib
./Build.ps1 -Target gcc -Config Release     # mingw/gcc via ninja
./Build.ps1 -Target android -Config Release # android
./Build.ps1 -Target msvc -Static -RunTests  # static build with tests

Usage

Inline hooking

#include <radhook/radhook.h>

int TargetFunction() { return 42; }
int DetourFunction() { return 1337; }

int main() {
    RadHookHandle handle = nullptr;

    // create and install the hook
    RadHookResult result = RadHookCreate(TargetFunction, (void*)DetourFunction, &handle);
    if (result != RadHookResult::Success) {
        // handle error, RadHookResultToString(result) for a message
    }

    // call through the trampoline
    using Fn = int(*)();
    Fn original = RadHookGetOriginalAs<Fn>(handle);
    original();

    RadHookDisable(handle);
    RadHookEnable(handle);

    RadHookDestroy(handle);
    return 0;
}

Vtable hooking

struct IFoo { 
    virtual int Value() { return 7; } 
    virtual ~IFoo() = default; 
};

int Detour(IFoo* self) { return 777; }

IFoo obj;
void** vtable = *reinterpret_cast<void***>(&obj);

RadHookHandle handle = nullptr;
RadHookVTableCreate(vtable, /*index=*/0, (void*)Detour, &handle);

// no relocation is needed for vtable hooks
using Fn = int(*)(IFoo*);
Fn original = RadHookGetOriginalAs<Fn>(handle);
original(&obj);

RadHookDestroy(handle);

Deferred apply

Stage several enable/disable transitions and flip them together in one pass, instead of one hook at a time:

RadHookQueueEnable(handleA);
RadHookQueueDisable(handleB);

// nothing has changed yet
Foo();

// then apply
RadHookApplyQueued(); // both transitions land together

If a handle is queued more than once before RadHookApplyQueued runs, the most recent call wins.

API overview

Function Name Description
RadHookCreate Create and install a hook, enabled by default
RadHookVTableCreate Create and install a hook on a vtable slot
RadHookEnable Enable an installed hook
RadHookDisable Disable an installed hook, restoring original bytes
RadHookDestroy Disable, release, and invalidate a hook
RadHookEnableAll / RadHookDisableAll Enable or disable every registered hook
RadHookQueueEnable / RadHookQueueDisable Stage a hook's enable/disable state without applying it
RadHookApplyQueued Apply every staged enable/disable transition at once
RadHookGetCount Number of currently registered hooks
RadHookGetHandles / RadHookEnumerate Enumerate registered hook handles
RadHookIsValid Check whether a handle refers to a registered hook
RadHookIsEnabled Check whether a hook is currently enabled
RadHookGetTarget Get the hooked target function pointer
RadHookGetDetour Get the detour function pointer
RadHookGetOriginal / RadHookGetOriginalAs<T> Get the trampoline to call the original implementation
RadHookResultToString Human-readable name for a RadHookResult
RadHookGetVersion Query the library's major/minor/patch version

All fallible operations return a RadHookResult, including granular error codes such as TrampolineTooFar, DisassemblyFailed, and MemoryProtectFailed.

Testing

Tests are built with CTest and cover creation, enable/disable and lifecycle transitions, trampoline behavior, vtable hooking, queued apply, invalid input handling, failure cases, memory integrity, and stress/churn scenarios.

cmake -S . -B build -DRADHOOK_BUILD_TESTS=ON
cmake --build build
ctest --test-dir build --output-on-failure

License

Licensed under the GNU Lesser General Public License v3 (LGPLv3). See LICENSE for details.

Description
Minimalistic x64 and aarch64 hooking library for C++
Readme LGPL-3.0 113 KiB
Languages
C++ 88.4%
CMake 5.2%
PowerShell 3.8%
C 2.2%
SWIG 0.4%