/HookLib

The functions interception library written on pure C and NativeAPI with UserMode and KernelMode support

Primary LanguageCMIT LicenseMIT

HookLib²

The Win32 lightweight functions interception library

✔ Advantages:

  • Written on pure C
  • Extremely lightweight
  • Based on the fastest and lightweight Zydis disassembler
  • Uses only NativeAPI functions
  • Has no other dependencies
  • Kernelmode support
  • Supports instructions relocation and thread's contexts fixup

📰 What's new in the 2nd Gen:

  • The HookLib was completely rewritten
  • Extremely reduced allocations, processes/threads enumerations and handles manipulations count
  • Multihook/multiunhook support that hooks/unhooks multiple functions in one session
  • Extremely reduced memory consumption for usermode hooks: one hook page (4Kb) can hold 39 cells for nearest hooks that removes the need to allocate one page per each hook
  • Support of KM->UM hooks (even with support of contexts fixup directly from kernelmode):
    • KM:Amd64 -> UM:Amd64
    • KM:Amd64 -> UM:Wow64
    • KM:i386 -> UM:i386

🔬 How it works:

TargetFunction():                                 ^ ; return
-> jmp Interceptor ------> Interceptor():         |
   ??? ; Broken bytes        ... Handler code ... |
   ... ; Continuation <--+   CallOriginal() ------|--> OriginalBeginning():
   ...         +---------|-> ...                  |      ... Original beginning ...
   ret --------+         |   ret -----------------+      ... of TargetFunction ...
                         +------------------------------ jmp Continuation

🧵 Trampolines:

Supported trampolines:

Jump to a relative offset:
E9 44 33 22 11  |  jmp rip+0x11223344 ; Relative jump to ±2Gb only

Jump to an absolute address (x32):
FF 25 00 00 00 00  | jmp [eip+00h]
44 33 22 11        | <- EIP is points to

Jump to an absolute address (x64):
FF 25 00 00 00 00        | jmp [rip+00h]
88 77 66 55 44 33 22 11  | <- RIP is points to

Trampolines selection logic:

if (relative_jumpable(fn, handler))
{
    set_relative_jump(fn, handler);
}
else
{
    /*
        'Intermediate' is an intermediate buffer that allocates
        in the same block with the function beginning:
    */
    if (relative_jumpable(fn, intermediate))
    {
        set_relative_jump(fn, intermediate);
        set_absolute_jump(intermediate, handler); 
    }
    else
    {
        set_absolute_jump(fn, handler);
    }
}

🪡 Usage:

Add the HookLib.vcxproj to your .sln and add the reference to the HookLib project into your project references list as described here: select project, open the project menu, click Add -> Reference and select the HookLib.
Then add ./HookLib/HookLib/ folder to your header folders list and you're good to go.

#include <HookLib.h>

int func(int a, int b)
{
    return a + b;
}

int handler(int a, int b)
{
    return a * b;
}

template <typename Fn>
Fn hookFunc(Fn fn, Fn handler)
{
    return static_cast<Fn>(hook(fn, handler));
}

void testSimpleHook()
{
    const auto orig = hookFunc(func, handler);
    
    assert(func(2, 3) == 6); // Hooked, the 'handler' will be called instead
    assert(orig(2, 3) == 5);
    
    unhook(orig);

    assert(func(2, 3) == 5);
}

void testCppHelpers()
{
    const auto holder = HookFactory::install(func, handler);
    assert(func(2, 3) == 6);
    assert(holder.call(2, 3) == 5);
}

int main()
{
    testSimpleHook();
    testCppHelpers();

    return 0;
}