The minimalistic x86 x64 api hooking library for windows

MinHook

The Minimalistic x86/x64 API Hooking Library for Windows

http://www.codeproject.com/KB/winsdk/LibMinHook.aspx

Version history

  • v1.3.4 — 28 Mar 2025

    • Improved error handling for enumerating and suspending threads.
    • Visual Studio 2022 support.
    • CMake support.
    • Fixed compilation with Clang.
    • Fixed compilation as C++ code.
  • v1.3.3 — 8 Jan 2017

    • Added a helper function MH_CreateHookApiEx. (Thanks to asm256)
    • Support Visual Studio 2017 RC.
  • v1.3.2.1 — 9 Nov 2015 (Nuget package only)

    • Fixed an insufficient support for Visual Studio 2015.
  • v1.3.2 — 1 Nov 2015

    • Support Visual Studio 2015.
    • Support MinGW.
  • v1.3.2-beta3 — 21 Jul 2015 (Nuget package only)

    • Support MinGW. (Experimental)
  • v1.3.2-beta2 — 18 May 2015

    • Fixed some subtle bugs. (Thanks to RaMMicHaeL)
    • Added a helper function MH_StatusToString. (Thanks to Jan Klass)
  • v1.3.2-beta — 12 May 2015

    • Fixed a possible thread deadlock in x64 mode. (Thanks to Aleh Kazakevich)
    • Reduced the footprint a little more.
    • Support Visual Studio 2015 RC. (Experimental)
  • v1.3.1.1 — 7 Apr 2015 (Nuget package only)

    • Support for WDK8.0 and 8.1.
  • v1.3.1 — 19 Mar 2015

    • No major changes from v1.3.1-beta.
  • v1.3.1-beta — 11 Mar 2015

    • Added a helper function MH_CreateHookApi. (Thanks to uniskz).
    • Fixed a false memory leak reported by some tools.
    • Fixed a degradated compatibility issue.
  • v1.3 — 13 Sep 2014

    • No major changes from v1.3-beta3.
  • v1.3-beta3 — 31 Jul 2014

    • Fixed some small bugs.
    • Improved the memory management.
  • v1.3-beta2 — 21 Jul 2014

    • Changed the parameters to Windows-friendly types. (void* to LPVOID)
    • Fixed some small bugs.
    • Reorganized the source files.
    • Reduced the footprint a little more.
  • v1.3-beta — 17 Jul 2014

    • Rewrote in plain C to reduce the footprint and memory usage. (suggested by Andrey Unis)
    • Simplified the overall code base to make it more readable and maintainable.
    • Changed the license from 3-clause to 2-clause BSD License.
  • v1.2 — 28 Sep 2013

    • Removed boost dependency (jarredholman).
    • Fixed a small bug in the GetRelativeBranchDestination function (pillbug99).
    • Added the MH_RemoveHook function, which removes a hook created with the MH_CreateHook function.
    • Added the following functions to enable or disable multiple hooks in one go: MH_QueueEnableHook, MH_QueueDisableHook, MH_ApplyQueued. This is the preferred way of handling multiple hooks as every call to MH_EnableHook or MH_DisableHook suspends and resumes all threads.
    • Made the functions MH_EnableHook and MH_DisableHook enable/disable all created hooks when the MH_ALL_HOOKS parameter is passed. This, too, is an efficient way of handling multiple hooks.
    • If the target function is too small to be patched with a jump, MinHook tries to place the jump above the function. If that fails as well, the MH_CreateHook function returns MH_ERROR_UNSUPPORTED_FUNCTION. This fixes an issue of hooking the LoadLibraryExW function on Windows 7 x64 (reported by Obble).
  • v1.1 — 26 Nov 2009

    • Changed the interface to create a hook and a trampoline function in one go to prevent the detour function from being called before the trampoline function is created. (reported by xliqz)
    • Shortened the function names from MinHook_* to MH_* to make them handier.
  • v1.0 — 22 Nov 2009

    • Initial release.

Building MinHook — Using vcpkg

You can download and install MinHook using the vcpkg dependency manager:

git clone https://github.com/microsoft/vcpkg
.\vcpkg\bootstrap-vcpkg.bat
.\vcpkg\vcpkg integrate install
.\vcpkg\vcpkg install minhook

The MinHook port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please create an issue or pull request on the vcpkg repository.

MinHook is a Windows API hooking library originally written by Tsuda Kageyu.
It’s probably the best free WinAPI library out there which supports both x86 and x64.
But it’s not perfect, and didn’t completely fit my needs, so I created a fork on GitHub which addresses some of its limitations.

Below you’ll see how the fork improves upon the original MinHook library.

Added the ability to enable/disable multiple hooks in one go

This was the most critical limitation for me.

Enabling or disabling a hook is a very expensive operation. In order to safely enable/disable a hook, all the process’ threads must be suspended, and resumed after the trampoline is patched. With the original API you couldn’t avoid doing this for every hook you enable or disable.

The fork introduces new APIs for efficiently enabling/disabling multiple hooks in one go: MH_QueueEnableHook, MH_QueueDisableHook and MH_ApplyQueued.

By calling MH_QueueEnableHook or MH_QueueDisableHook multiple times, the hooks aren’t actually get enabled or disabled, but are merely flagged for the desired change. Then, when MH_ApplyQueued is called, all the flagged hooks are enabled/disabled in one go. The process’ threads get suspended and resumed only once, instead of every time for each enabled or disabled hook.

Also, the MH_EnableHook and MH_DisableHook functions can now be called with the MH_ALL_HOOKS parameter, which will efficiently enable or disable all created hooks.

The result: toggling 100 hooks could take about 700 ms (almost one second!) with the old APIs, but takes only 6 ms with the new APIs. (source)

Fixed bugs and improved compatibility

In short: now it works with more functions, and will correctly fail if a function can’t be hooked (instead of corrupting other functions).
For more details see here.

Removed Boost dependency

This is not as critical as the previous limitations, but is definitely an improvement.

Download

Get the latest code of the MinHook fork here.

Posted in Programming by Michael (Ramen Software) on September 30th, 2013.
Tags: minhook

Provides the basic part of Microsoft Detours functionality for both x64/x86 environments.

  • Download Source (v1.3.3) — 49.1 KB
  • Download Precompiled DLLs (v1.3.3) — 19.0 KB
  • Download Precompiled Static Libraries (v1.3.3) — 1.8 MB
  • Download Samples (v1.3.2) — 120.6 KB
  • Release archive of my GitHub repository
  • NuGet Package for the latest version (NuGet Gallery)
v1.3.3 was released on 8 Jan 2017!

We added support for Visual Studio 2017. Feel free to visit my GitHub repository. Your reviews and bug reports are welcome.

Background

As you who are interested in Windows API hooking know, there is an excellent library for it by Microsoft Research named Detours. It’s really useful, but its free edition (called ‘Express’) doesn’t support the x64 environment. Though its commercial edition (called ‘Professional’) supports x64, it’s too expensive for me to afford. It costs around US$10,000!

So I decided to write my own library or «poorman’s Detours» from scratch. But I haven’t designed my library as the perfect clone of Detours. It has just the API hooking functionality because that’s all I want.

As of April 2016, this library is used in some projects: 7+ Taskbar Tweaker, Better Explorer, ConEmu, DxWnd, Mumble, NonVisual Desktop Access, Open Broadcaster Software, QTTabBar, x360ce, mods for some games and more. I am happy finding that this project is helpful to people.

Using the Library

Look at the sample code below. That’s all. It hooks the MessageBoxW() function and modifies its text. This example is included in the source and binary archive. Please try it in both x64 and x86 modes.

The NuGet Package is now available for those who are familiar with NuGet.

#include <Windows.h>
#include "MinHook.h"

#if defined _M_X64
#pragma comment(lib, "libMinHook.x64.lib")
#elif defined _M_IX86
#pragma comment(lib, "libMinHook.x86.lib")
#endif

typedef int (WINAPI *MESSAGEBOXW)(HWND, LPCWSTR, LPCWSTR, UINT);

// Pointer for calling original MessageBoxW.
MESSAGEBOXW fpMessageBoxW = NULL;

// Detour function which overrides MessageBoxW.
int WINAPI DetourMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
{
    return fpMessageBoxW(hWnd, L"Hooked!", lpCaption, uType);
}

int main()
{
    // Initialize MinHook.
    if (MH_Initialize() != MH_OK)
    {
        return 1;
    }

    // Create a hook for MessageBoxW, in disabled state.
    if (MH_CreateHook(&MessageBoxW, &DetourMessageBoxW, 
        reinterpret_cast<LPVOID*>(&fpMessageBoxW)) != MH_OK)
    {
        return 1;
    }

    // or you can use the new helper function like this.
    //if (MH_CreateHookApiEx(
    //    L"user32", "MessageBoxW", &DetourMessageBoxW, &fpMessageBoxW) != MH_OK)
    //{
    //    return 1;
    //}

    // Enable the hook for MessageBoxW.
    if (MH_EnableHook(&MessageBoxW) != MH_OK)
    {
        return 1;
    }

    // Expected to tell "Hooked!".
    MessageBoxW(NULL, L"Not hooked...", L"MinHook Sample", MB_OK);

    // Disable the hook for MessageBoxW.
    if (MH_DisableHook(&MessageBoxW) != MH_OK)
    {
        return 1;
    }

    // Expected to tell "Not hooked...".
    MessageBoxW(NULL, L"Not hooked...", L"MinHook Sample", MB_OK);

    // Uninitialize MinHook.
    if (MH_Uninitialize() != MH_OK)
    {
        return 1;
    }

    return 0;
}

If you are a C++ user, you can write a small wrapper for MH_CreateHook() and MH_CreateHookApi(). It allows you to remove annoying reinterpret_casts like this:

template <typename T>
inline MH_STATUS MH_CreateHookEx(LPVOID pTarget, LPVOID pDetour, T** ppOriginal)
{
    return MH_CreateHook(pTarget, pDetour, reinterpret_cast<LPVOID*>(ppOriginal));
}

template <typename T>
inline MH_STATUS MH_CreateHookApiEx(
    LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, T** ppOriginal)
{
    return MH_CreateHookApi(
        pszModule, pszProcName, pDetour, reinterpret_cast<LPVOID*>(ppOriginal));
}

...

// Create a hook for MessageBoxW, in disabled state.
if (MH_CreateHookApiEx(L"user32", "MessageBoxW", &DetourMessageBoxW, &fpMessageBoxW) != MH_OK)
{
    return 1;
}

How It Works

The basic concept of this software is the same as Microsoft Detours and Daniel Pistelli’s Hook-Engine. It replaces the prologue of the target function with x86’s JMP (unconditional jump) instruction to the detour function. It’s safe, stable, and a proven method.

Overwriting the Target Function

In the x64/x86 instruction set, there are some forms of the JMP instruction. I decided to always use a 32 bit relative JMP of 5 bytes. It’s the shortest form that can be used in reality. In this case, shorter is better.

In x86 mode, 32bit relative JMP covers the whole address space. Because the overflowed bits are just ignored in the relative address arithmetic, in x86 mode, the function addresses don’t matter.

; x86 mode (assumed that the target function is at 0x40000000)

; 32bit relative JMPs of 5 bytes cover whole address space
0x40000000:  E9 FBFFFFBF      JMP 0x0        (EIP+0xBFFFFFFB)
0x40000000:  E9 FAFFFFBF      JMP 0xFFFFFFFF (EIP+0xBFFFFFFA)

; Shorter forms are useless in this case
; 8bit JMPs of 2 bytes cover -126 ~ +129 bytes
0x40000000:  EB 80            JMP 0x3FFFFF82 (EIP-0x80)
0x40000000:  EB 7F            JMP 0x40000081 (EIP+0x7F)
; 16bit JMPs of 4 bytes cover -32764 ~ +32771 bytes
0x40000000:  66E9 0080        JMP 0x3FFF8004 (EIP-0x8000)
0x40000000:  66E9 FF7F        JMP 0x40008003 (EIP+0x7FFF)

But, in x64 mode, it’s a problem. It only covers the very narrow range in comparison with the whole address space. So I introduced a new function called ‘Relay Function’ which just has a 64 bit jump to the detour function and is placed near the target function. Fortunately, the VirtualAlloc() API function can accept the address to allocate, and it’s an easy job to look for unallocated regions near the target function.

; x64 mode (assumed that the target function is at 0x140000000)

; 32bit relative JMPs of 5 bytes cover about -2GB ~ +2GB
0x140000000: E9 00000080      JMP 0xC0000005  (RIP-0x80000000)
0x140000000: E9 FFFFFF7F      JMP 0x1C0000004 (RIP+0x7FFFFFFF)

; Target function (Jump to the Relay Function)
0x140000000: E9 FBFF0700      JMP 0x140080000 (RIP+0x7FFFB)

; Relay function (Jump to the Detour Function)
0x140080000: FF25 FAFF0000    JMP [0x140090000 (RIP+0xFFFA)]
0x140090000: xxxxxxxxxxxxxxxx ; 64bit address of the Detour Function

Building the Trampoline Function

The target function is overwritten to detour. And, how do we call the original target function? In many cases, we have to call the original function from within the detour function. MinHook has a function called «Trampoline Function» for the purpose of calling the original function (and Daniel Pistelli call it «Bridge Function»). This is a clone of the prologue of the original function with the trailing unconditional jump for resuming into the original function. The real world examples are here. They are what MinHook actually creates.

We should disassemble the original function to know the instructions boundary and the instructions to be copied. I adopted Vyacheslav Patkov‘s Hacker Disassembler Engine (HDE) as a disassembler. It’s small, light-weight and suitable for my purpose. I disassembled thousands of API functions on Windows XP, Vista, and 7 for examination purposes, and built the trampoline function for them.

; Original "USER32.dll!MessageBoxW" in x64 mode
0x770E11E4: 4883EC 38         SUB RSP, 0x38
0x770E11E8: 4533DB            XOR R11D, R11D
; Trampoline
0x77064BD0: 4883EC 38         SUB RSP, 0x38
0x77064BD4: 4533DB            XOR R11D, R11D
0x77064BD7: FF25 5BE8FEFF     JMP QWORD NEAR [0x77053438 (RIP-0x117A5)]
; Address Table
0x77053438: EB110E7700000000  ; Address of the Target Function +7 (for resuming)

; Original "USER32.dll!MessageBoxW" in x86 mode
0x7687FECF: 8BFF              MOV EDI, EDI
0x7687FED1: 55                PUSH EBP
0x7687FED2: 8BEC              MOV EBP, ESP
; Trampoline
0x0014BE10: 8BFF              MOV EDI, EDI
0x0014BE12: 55                PUSH EBP
0x0014BE13: 8BEC              MOV EBP, ESP
0x0014BE15: E9 BA407376       JMP 0x7687FED4

What if the original function contains the branch instructions? Of course, they should be modified to point to the same address as the original.

; Original "kernel32.dll!IsProcessorFeaturePresent" in x64 mode
0x771BD130: 83F9 03           CMP ECX, 0x3
0x771BD133: 7414              JE 0x771BD149
; Trampoline
; (Became a little complex, because 64 bit version of JE doesn't exist)
0x77069860: 83F9 03           CMP ECX, 0x3
0x77069863: 74 02             JE 0x77069867
0x77069865: EB 06             JMP 0x7706986D
0x77069867: FF25 1BE1FEFF     JMP QWORD NEAR [0x77057988 (RIP-0x11EE5)]
0x7706986D: FF25 1DE1FEFF     JMP QWORD NEAR [0x77057990 (RIP-0x11EE3)]
; Address Table
0x77057988: 49D11B7700000000  ; Where the original JE points.
0x77057990: 35D11B7700000000  ; Address of the Target Function +5 (for resuming)

; Original "gdi32.DLL!GdiFlush" in x86 mode
0x76479FF4: E8 DDFFFFFF       CALL 0x76479FD6
; Trampoline
0x00147D64: E8 6D223376       CALL 0x76479FD6
0x00147D69: E9 8B223376       JMP 0x76479FF9

; Original "kernel32.dll!CloseProfileUserMapping" in x86 mode
0x763B7918: 33C0              XOR EAX, EAX
0x763B791A: 40                INC EAX
0x763B791B: C3                RET
0x763B791C: 90                NOP
; Trampoline (Additional jump is not required, because this is a perfect function)
0x0014585C: 33C0              XOR EAX, EAX
0x0014585E: 40                INC EAX
0x0014585F: C3                RET 

The RIP relative addressing mode is also a problem in the x64 mode. Their relative addresses should be modified to point to the same addresses.

; Original "kernel32.dll!GetConsoleInputWaitHandle" in x64 mode
0x771B27F0: 488B05 11790C00   MOV RAX, [0x7727A108 (RIP+0xC7911)]
; Trampoline
0x77067EB8: 488B05 49222100   MOV RAX, [0x7727A108 (RIP+0x212249)]
0x77067EBF: FF25 4BE3FEFF     JMP QWORD NEAR [0x77056210 (RIP-0x11CB5)]
; Address Table
0x77056210: F7271B7700000000  ; Address of the Target Function +7 (for resuming)

; Original "user32.dll!TileWindows" in x64 mode
0x770E023C: 4883EC 38         SUB RSP, 0x38
0x770E0240: 488D05 71FCFFFF   LEA RAX, [0x770DFEB8 (RIP-0x38F)]
; Trampoline
0x77064A80: 4883EC 38         SUB RSP, 0x38
0x77064A84: 488D05 2DB40700   LEA RAX, [0x770DFEB8 (RIP+0x7B42D)]
0x77064A8B: FF25 CFE8FEFF     JMP QWORD NEAR [0x77053360 (RIP-0x11731)]
; Address Table
0x77053360: 47020E7700000000 ; Address of the Target Function +11 (for resuming)

Conclusion

Though this library is small and simple, I think it’s practical enough. Please enjoy!

History

  • 8 Jan, 2017: Updated the source to v1.3.3.
    1. Added a helper function MH_CreateHookApiEx. (Thanks to asm256)
    2. Support Visual Studio 2017 RC.
  • 1 Nov, 2015: Updated the source to v1.3.2.
    1. Support Visual Studio 2015.
    2. Support MinGW.
  • 18 May, 2015: Updated the source to v1.3.2-beta2.
    1. Fixed some subtle bugs. (Thanks to RaMMicHaeL)
    2. Added a helper function MH_StatusToString. (Thanks to Jan Klass)
  • 12 May, 2015: Updated the source to v1.3.2-beta.
    1. Fixed a possible thread deadlock in x64 mode. (Thanks to Aleh Kazakevich)
    2. Reduced the footprint a little more.
    3. Support Visual Studio 2015 RC. (Experimental)
  • 19 Mar, 2015: Updated the source to v1.3.1.
    1. No major changes from v1.3.1-beta.
  • 11 Mar, 2015: Updated the source to v1.3.1-beta.
    1. Added the MH_CreateHookApi function.
    2. Fixed a false memory leak reported by some tools.
    3. Fixed a degradated compatibility issue.
  • 13 Sep, 2014: Updated the source to v1.3.
    1. No major changes from v1.3-beta3.
  • 31 Jul, 2014: Updated the source to v1.3-beta3.
    1. Fixed some small bugs.
    2. Improved the memory management.
  • 21 Jul, 2014: Updated the source to v1.3-beta2.
    1. Changed the parameters to Windows-friendly types. (void* to LPVOID)
    2. Fixed some small bugs.
    3. Reorganized the source files.
    4. Reduced the footprint a little more.
  • 17 Jul, 2014: Updated the source to v1.3-beta.
    1. Rewrote in plain C to reduce the footprint and memory usage. (suggested by Andrey Unis)
    2. Simplified the overall code base to make it more readable and maintainable.
    3. Changed the license from 3-clause to 2-clause BSD License.
  • 21 Jun, 2014: Updated the source to v1.2.2.
    1. Fixed compilation with Express Editions.
    2. Reduced the size of static libraries.
  • 18 Jun, 2014: Updated the source to v1.2.1c.
    1. Translated the Japanese comments into English.
    2. Converted the source files from Shift-JIS to UTF-8.
  • 16 Jun, 2014: Updated the source and binary files to v1.2.1.
    1. A lot of bug fixes and improvements. (thanks to jarredholman and RaMMicHaeL)
    2. Fixed compilation with VC2008, 2010, 2012 and 2013.
  • 26 Nov, 2009: Updated the source, binary files and sample code
    1. Fixed a serious bug (thanks to xliqz)
    2. Changed the interface with the bug fix
  • 23 Nov, 2009: Updated the source and binary files
    1. Fixed small bugs (internal type mismatch etc)
    2. Separated the .LIBs from the .DLLs
    3. Added the sample executables
  • 22 Nov, 2009: Initial post

Created

Updated

The Minimalistic x86/x64 API Hooking Library for Windows.

  • https://github.com/TsudaKageyu/minhook

# License

# Supported Platforms

windows & !uwp & !arm

  • windows-x64
  • windows-x86
  • ❌ linux
  • ❌ osx
  • ❌ uwp
  • ❌ windows-arm64

# Features

No features defined.

# Dependencies

No dependencies.

# Host Dependencies

# Dependents

No dependents.

# Host Dependents

No dependents.

# Contributors

# Changelog

  • af1bb18 [minhook] fix build error on CMake 4.0 (#44574)

  • 27fb19b [many ports] Fix URLS of download patch (#33309)

  • e62d136 [vcpkg] Add Supports: field. Use contents of triplets instead of names for dependency resolution. (#8601)

# Source

dotnet add package minhook --version 1.3.3
                    
                

NuGet\Install-Package minhook -Version 1.3.3
                    
                

This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module’s version of Install-Package.

<PackageReference Include="minhook" Version="1.3.3" />
                    
                

For projects that support PackageReference, copy this XML node into the project file to reference the package.

<PackageVersion Include="minhook" Version="1.3.3" />
                    

Directory.Packages.props

<PackageReference Include="minhook" />
                    

Project file

For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.

paket add minhook --version 1.3.3
                    
                

The NuGet Team does not provide support for this client. Please contact its maintainers for support.

#r "nuget: minhook, 1.3.3"
                    
                

#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.

#addin nuget:?package=minhook&version=1.3.3
                    

Install minhook as a Cake Addin

#tool nuget:?package=minhook&version=1.3.3
                    

Install minhook as a Cake Tool

The NuGet Team does not provide support for this client. Please contact its maintainers for support.

Понравилась статья? Поделить с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
  • Как добавить рабочий стол в избранное на windows 10
  • Шаблон ошибки windows 8
  • Windows keylogger бесплатно usd49 win
  • Uhd graphics 605 драйвера windows 10
  • Просмотр изображений windows 10 расположение