Skip to content

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

License

Notifications You must be signed in to change notification settings

HoShiMin/HookLib

Folders and files

NameName
Last commit message
Last commit date
Oct 10, 2023
Oct 10, 2023
Oct 10, 2023
Aug 29, 2021
Feb 10, 2019
May 31, 2020
Feb 10, 2019
Aug 29, 2021
Feb 10, 2019
Sep 5, 2021

Repository files navigation

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 for KM->UM hooks (even with support for 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 44 33 22 11  | jmp ds:[0x11223344]
NN NN NN NN        | <- 0x11223344 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;
}