Lightweight Windows API hooking library using Import/Export Address Table manipulation.
tablehook intercepts Windows API calls by patching the IAT (Import Address Table) and EAT (Export Address Table) of loaded modules. No inline patching or detours - just clean table modifications that are fully reversible.
Supports x86, x64, and ARM64.
Requires MinGW or MSVC with psapi.lib.
64-bit:
gcc -m64 -O2 -o tablehook64.exe main.c src/tablehook.c -Iinclude -lpsapi
32-bit:
gcc -m32 -O2 -o tablehook32.exe main.c src/tablehook.c -Iinclude -lpsapi
#include "tablehook.h"
#include <stdio.h>
static DWORD (WINAPI *Real_GetCurrentProcessId)(void) = NULL;
DWORD WINAPI Hooked_GetCurrentProcessId(void) {
printf("hooked!\n");
return Real_GetCurrentProcessId();
}
int main(void) {
th_init();
th_hook_t *hook = th_create(
"kernel32.dll",
"GetCurrentProcessId",
Hooked_GetCurrentProcessId,
(void **)&Real_GetCurrentProcessId
);
th_enable(hook);
GetCurrentProcessId(); // prints "hooked!"
th_destroy(hook);
th_shutdown();
return 0;
}
Note: Compiler optimizations may cache function pointers. Use attribute((noinline)) wrappers or -O0 if hooks aren't triggering during testing.
Initialization:
bool th_init(void) Initialize the library
void th_shutdown(void) Cleanup and restore all hooks
bool th_is_initialized(void) Check init state
Hook management:
th_hook_t *th_create(module, func, hook_fn, original_out)
th_hook_t *th_create_ex(module, func, hook_fn, original_out, flags)
void th_destroy(hook)
void th_destroy_all(void)
Hook control:
bool th_enable(hook) Apply the hook
bool th_disable(hook) Remove the hook
bool th_is_enabled(hook) Check if active
uint32_t th_enable_all(void) Enable all hooks
uint32_t th_disable_all(void) Disable all hooks
Hook info:
void *th_get_original(hook) Get original function pointer
const char *th_get_module(hook) Get target module name
const char *th_get_function(hook) Get target function name
Flags for th_create_ex:
TH_HOOK_IAT Hook import tables (default)
TH_HOOK_EAT Hook export table
TH_HOOK_DELAY Hook delay-load imports
TH_HOOK_ALL All of the above
Error handling:
th_error_t th_error(void)
const char *th_error_string(err)
IAT hooks scan all loaded modules for import entries pointing to the target function and redirect them to your hook. This catches calls from any module in the process.
EAT hooks modify the target module's export table. Future GetProcAddress calls return your hook instead of the real function. Existing cached pointers are unaffected.
Trampolines are allocated within ±2GB of the target module for relative addressing on x64.