Click here to Skip to main content
Click here to Skip to main content

MinHook - The Minimalistic x86/x64 API Hooking Library

By , 28 Nov 2009
 

Background

As people who are interested in Windows API hooking know, there is an excellent library for it by Microsoft named 'Detours'. It's really useful, but its free edition (called 'Express') doesn't support x64. Its commercial edition (called 'Professional') supports x64, but it's too expensive for me. It costs US$ 10,000, Microsoft says.

So I decided to write my own library 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.

Using the Library

Look at the sample code below. That's all. Once, I fixed a serious bug, and have changed the interface. It hooks the MessageBoxW() function and modifies its text. It's included in the source archive. Please try it in both x64 and x86 modes.

#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<void**>(&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;
}

How It Works

The basic idea of this software is the same as Microsoft Detours and Mr. Daniel Pistelli's Hook-Engine. It replaces the prologue of the target function with the 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 overflown 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? There is a function called 'Trampoline Function' in Microsoft Detours (and called 'Bridge Function' by Mr. Pistelli). 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 creates internally in reality.

We should disassemble the original function to know the instructions boundary and the instructions to be copied. I adopted Mr. Vyacheslav Patkov's 'Hacker Disassembler Engine (HDE)' as the 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

  • 22nd November, 2009: Initial post
  • 23rd November, 2009: Updated source and binary files
    1. Fixed small bugs (internal type mismatch etc)
    2. Separated the .LIBs from the .DLLs
    3. Added the sample executables
  • 26th November, 2009: Updated source, binary files and sample code
    1. Fixed a serious bug (thanks to xliqz)
    2. Changed the interface with the bug fix

License

This article, along with any associated source code and files, is licensed under The BSD License

About the Author

Tsuda Kageyu
Software Developer
Japan Japan
In 1985, I got my first computer Casio MX-10, the cheapest one of the MSX computers. Then I began programming in BASIC and assembly language, and have experienced over ten languages from that time on.
Now, my primary languages are C++ and C#. Working for a small company in my home town, the countryside of Japan.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
NewsA fork with a number of improvements [modified]memberskhanvilkar@hpiinc.com9-May-13 12:54 
https://github.com/RaMMicHaeL/minhook[^]
 
Main differences from original v1.1
  • 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_EnableAllHooks, MH_DisableAllHooks, MH_EnableMultipleHooks, MH_DisableMultipleHooks. This is the preferred way of handling multiple hooks as every call to MH_EnableHook or MH_DisableHook suspends and resumes all threads.
  • 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).


modified 5-Jun-13 15:32pm.

GeneralRe: A fork with a number of improvementsmemberTsuda Kageyu9-May-13 15:58 
I think it's a pretty good idea to create a fork and open it to the public on GitHub.
I appreciate very much that someone takes over my work.
GeneralRe: A fork with a number of improvementsmemberskhanvilkar@hpiinc.com10-May-13 4:33 
I wasn't sure I'd hear from you, after all the library wasn't updated for more than three years.
Good to know you're approving it.
 
I'm not a C++ programmer, so I hope I'm getting things right.
 
P.S. Thanks for the library. It's probably the best hooking library around.
GeneralRe: A fork with a number of improvementsmemberTsuda Kageyu10-May-13 3:16 
I reviewed the code after a long time, and I have recalled that I wrote the comments in Japanese.
I think it's somewhat inappropriate for the open project, so want to rewrite them in English. Are you ready to accept a pull request?
GeneralRe: A fork with a number of improvementsmemberskhanvilkar@hpiinc.com10-May-13 4:36 
Sure, that would be great.
 
In fact, I thought about using Google Translate to automatically translate the comments, but of course a proper translation is much better.
GeneralRe: A fork with a number of improvementsmemberTsuda Kageyu10-May-13 5:05 
Thanks.
At that time, I was not very skilled with C++, so the code is not sophisticated as a C++ program.
I want to give an overall review, but I'm a little busy now. But I will do it sooner or later.
GeneralRe: A fork with a number of improvementsprofessionalskhanvilkar@hpiinc.com4-Jun-13 9:48 
Updated
  • Made the MH_CreateHook function return MH_ERROR_UNSUPPORTED_FUNCTION when the target function is too small and is not padded with zero bytes, nops, or INT3 commands.
  • If the target function begins with a short jump, MinHook considers the jump destination as the target (Obble). This fixes an issue on Windows 7 x64 with the patched jump overwriting code of a different function.

GeneralRe: A fork with a number of improvementsmemberRaMMicHaeL5-Jun-13 9:37 
Updated
  • Added:
    If the target function is too small to be patched with a jump, MinHook tries to place the jump above the function.
  • Reverted:
    If the target function begins with a short jump, MinHook considers the jump destination as the target.
 
See this post[^] for more details.
GeneralRe: A fork with a number of improvementsmemberwinest16-Jun-13 22:08 
Hi,
 
Thanks for your great work!
I just found a project setting missed so that when using
VS 2012 to compile Debug x64 version, MinHook will never be generated.
GeneralRe: A fork with a number of improvementsmemberRaMMicHaeL14-Jun-13 3:56 
Fixed in the repository.
Questionvtable hookingmemberBig Muscle13-Jan-13 22:20 
Hello, does your library work for hooking vtables (i.e. hooking function of specific object?).
 
I know I can change the address of the function directly in vtable but the process where I inject to periodically restores vtable to original state. Therefor I would rather inject some JMP instruction into the original function. And I need a simple solution for x64. Thanks in advance.
AnswerRe: vtable hookingmemberColdbird13-Apr-13 2:30 
Seen from a technical point of view (after looking at the MinHook code myself) there should be no issue with hooking a V-Table function.
 
To do so you need to...
 
1. Read the V-Table yourself and figure out which offset / function in it is interesting to you...
 
2. Get the function address from that V-Table offset and place a hook on it like you would do normally with MinHook.
 
3. In your replacement function add a new leading argument corresponding to the type of the class you are hooking into.
 
So if you were hooking into lets say...
 
DummyClass::YourDummyMethod(int a, int b, int c)
 
... then your replacement hook function would have to be...
 
MyDummyMethodReplacement(DummyClass * objectReference, int a, int b, int c)
 
Thats all there is to it. Happy Hooking.
GeneralRe: vtable hookingmemberBig Muscle19-Apr-13 10:17 
Thanks. I already managed to do it for x64. Problem is that it does not work in 32-bit for functions declared with __thiscall convention. The function hooks properly but the problem is that in many cases I need to call the original function. And this simply crashes because "objectReference" reference must be passed in ecx. Is it possible to store it in ecx without using inline assembler?
GeneralRe: vtable hookingmemberskhanvilkar@hpiinc.com9-May-13 12:20 
If __thiscall doesn't work, you can try using __fastcall as a workaround. Just add an extra variable for edx.
 
e.g.:
void __fastcall func(void *this, size_t _edx_var, int a, int whatever)
{
}

QuestionDoesn't work in a DLL?memberT3rm130-Nov-12 3:13 
If I copy and paste the code into a DLL (DLL_PROCESS_ATTACH) I get lots of compile errors (unresolved external symbol).
 
The code wokred in a console application. But that's pretty useless. I want to inject the DLL.
AnswerRe: Doesn't work in a DLL?memberColdbird13-Apr-13 2:31 
Probably because you arent linking boost into it correctly.
 
But dont worry, in one of the comments here you find a patch to fully remove Boost Dependencies.
 
That plus some manual patches and you should be ready to go.
GeneralMy vote of 5membergndnet11-Jul-12 22:19 
awesome
SuggestionPatch to remove dependency on boostmemberTim M. Angus19-Apr-12 0:42 
I've put together a small patch that removes libMinHook's dependency on boost as I found it quite annoying to have to install it and keep libMinHook pointing at it; especially with VS2010's idea about where to configure third party library directories. The patch also includes a fix for pillbug99's short jump bug (http://www.codeproject.com/Messages/4058892/Small-Bug-Found.aspx[^]).
 
libMinHook is an excellent little library that does just enough and no more Thumbs Up | :thumbsup: .
 
diff -urw MinHook_110_src.original/MinHook/libMinHook/src/buffer.cpp MinHook_110_src/MinHook/libMinHook/src/buffer.cpp
--- MinHook_110_src.original/MinHook/libMinHook/src/buffer.cpp	2009-11-25 06:42:50.000000000 +0000
+++ MinHook_110_src/MinHook/libMinHook/src/buffer.cpp	2012-04-19 11:26:47.960409100 +0100
@@ -29,7 +29,6 @@
 #include <cassert>
 #include <vector>
 #include <algorithm>
-#include <boost/foreach.hpp>
 #include <Windows.h>
 
 #include "buffer.h"
@@ -77,9 +76,10 @@
 
 	void UninitializeBuffer()
 	{
-		BOOST_FOREACH (MEMORY_BLOCK& block, gMemoryBlocks)
+		for (std::vector<MEMORY_BLOCK>::iterator block = gMemoryBlocks.begin();
+			block != gMemoryBlocks.end(); block++)
 		{
-			VirtualFree(block.pAddress, 0, MEM_RELEASE);
+			VirtualFree(block->pAddress, 0, MEM_RELEASE);
 		}
 
 		std::vector<MEMORY_BLOCK> v;
@@ -102,25 +102,27 @@
 
 	void RollbackBuffer()
 	{
-		BOOST_FOREACH (MEMORY_BLOCK& block, gMemoryBlocks)
+		for (std::vector<MEMORY_BLOCK>::iterator block = gMemoryBlocks.begin();
+			block != gMemoryBlocks.end(); block++)
 		{
-			block.usedSize = block.fixedSize;
+			block->usedSize = block->fixedSize;
 		}
 	}
 
 	void CommitBuffer()
 	{
-		BOOST_FOREACH (MEMORY_BLOCK& block, gMemoryBlocks)
+		for (std::vector<MEMORY_BLOCK>::iterator block = gMemoryBlocks.begin();
+			block != gMemoryBlocks.end(); block++)
 		{
-			if (block.usedSize == block.fixedSize)
+			if (block->usedSize == block->fixedSize)
 			{
 				continue;
 			}
 
-			void* pBuffer = reinterpret_cast<char*>(block.pAddress) + block.fixedSize;
-			size_t size = block.usedSize - block.fixedSize;
+			void* pBuffer = reinterpret_cast<char*>(block->pAddress) + block->fixedSize;
+			size_t size = block->usedSize - block->fixedSize;
 			DWORD op;
-			VirtualProtect(pBuffer, size, block.protect, &op);
+			VirtualProtect(pBuffer, size, block->protect, &op);
 		}
 	}
 }
diff -urw MinHook_110_src.original/MinHook/libMinHook/src/hook.cpp MinHook_110_src/MinHook/libMinHook/src/hook.cpp
--- MinHook_110_src.original/MinHook/libMinHook/src/hook.cpp	2009-11-25 06:47:02.000000000 +0000
+++ MinHook_110_src/MinHook/libMinHook/src/hook.cpp	2012-04-19 11:26:47.963409300 +0100
@@ -30,8 +30,6 @@
 #include <vector>
 #include <algorithm>
 #include <functional>
-#include <boost/scope_exit.hpp>
-#include <boost/foreach.hpp>
 #include <Windows.h>
 #include "pstdint.h"
 
@@ -116,14 +114,15 @@
 		}
 
 		// ‚·‚ׂẴtƒbƒN‚ð‰ðœ
-		BOOST_FOREACH (const HOOK_ENTRY& hook, gHooks)
+		for (std::vector<HOOK_ENTRY>::const_iterator hook = gHooks.begin();
+			hook != gHooks.end(); hook++)
 		{
-			if (!hook.isEnabled)
+			if (!hook->isEnabled)
 			{
 				continue;
 			}
 			
-			MH_STATUS status = DisableHook(hook.pTarget);
+			MH_STATUS status = DisableHook(hook->pTarget);
 			if (status != MH_OK)
 			{
 				return status;
@@ -162,33 +161,26 @@
 
 		if (pHook == NULL)
 		{
-			bool committed = false;
-			BOOST_SCOPE_EXIT((&committed))
-			{
-				if (!committed)
-				{
-					RollbackBuffer();
-				}
-			}
-			BOOST_SCOPE_EXIT_END;
-
 			// ƒgƒ‰ƒ“ƒ|ƒŠƒ“ŠÖ”‚ðì¬‚·‚é
 			CREATE_TREMPOLINE_T ct = { 0 };
 			ct.pTarget = pTarget;
 			if (!CreateTrampolineFunction(ct))
 			{
+				RollbackBuffer();
 				return MH_ERROR_UNSUPPORTED_FUNCTION;
 			}
 
 			void* pTrampoline = AllocateCodeBuffer(pTarget, ct.trampoline.size());
 			if (pTrampoline == NULL)
 			{
+				RollbackBuffer();
 				return MH_ERROR_MEMORY_ALLOC;
 			}
 #if defined _M_X64
 			void* pTable = AllocateDataBuffer(pTrampoline, (ct.table.size() + 1) * sizeof(uintptr_t));
 			if (pTable == NULL)
 			{
+				RollbackBuffer();
 				return MH_ERROR_MEMORY_ALLOC;
 			}
 #endif
@@ -199,6 +191,7 @@
 #endif
 			if (!ResolveTemporaryAddresses(ct))
 			{
+				RollbackBuffer();
 				return MH_ERROR_UNSUPPORTED_FUNCTION;
 			}
 
@@ -214,6 +207,7 @@
 			void* pBackup = AllocateDataBuffer(NULL, sizeof(JMP_REL));
 			if (pBackup == NULL)
 			{
+				RollbackBuffer();
 				return MH_ERROR_MEMORY_ALLOC;
 			}
 
@@ -224,13 +218,13 @@
 			void* pRelay = AllocateCodeBuffer(pTarget, sizeof(JMP_ABS));
 			if (pRelay == NULL)
 			{
+				RollbackBuffer();
 				return MH_ERROR_MEMORY_ALLOC;
 			}
 
 			WriteAbsoluteJump(pRelay, pDetour, reinterpret_cast<uintptr_t*>(pTable) + ct.table.size());
 #endif
 			CommitBuffer();
-			committed = true;
 
 			// ƒtƒbƒNî•ñ‚Ì“o˜^
 			HOOK_ENTRY hook = { 0 };
diff -urw MinHook_110_src.original/MinHook/libMinHook/src/thread.cpp MinHook_110_src/MinHook/libMinHook/src/thread.cpp
--- MinHook_110_src.original/MinHook/libMinHook/src/thread.cpp	2009-11-21 00:29:02.000000000 +0000
+++ MinHook_110_src/MinHook/libMinHook/src/thread.cpp	2012-04-19 11:26:47.965409400 +0100
@@ -29,7 +29,6 @@
 #include <cassert>
 #include <vector>
 #include <algorithm>
-#include <boost/foreach.hpp>
 #include <windows.h>
 #include <TlHelp32.h>
 
@@ -38,7 +37,7 @@
 namespace MinHook { namespace
 {
 	// Ž©“®“I‚ÉCloseHandle‚³‚ê‚éWindowsƒnƒ“ƒhƒ‹
-	class ScopedHandle : boost::noncopyable
+	class ScopedHandle
 	{
 	private:
 		HANDLE handle_;
@@ -57,6 +56,9 @@
 		{
 			return handle_;
 		}
+	private:			
+		ScopedHandle(const ScopedHandle&);
+		const ScopedHandle& operator=(const ScopedHandle&);
 	};
 
 }}
@@ -143,9 +145,10 @@
 		static const DWORD ThreadAccess 
 			= THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT;
 		
-		BOOST_FOREACH (const DWORD& tid, threads)
+		for (std::vector<DWORD>::const_iterator tid = threads.begin();
+			tid != threads.end(); tid++)
 		{
-			ScopedHandle hThread = OpenThread(ThreadAccess, FALSE, tid);
+			ScopedHandle hThread = OpenThread(ThreadAccess, FALSE, *tid);
 			SuspendThread(hThread);
 
 			// ‘‚«Š·‚¦”͈͓à‚ŃXƒŒƒbƒh‚ª’âŽ~‚µ‚½ê‡‚́Aƒgƒ‰ƒ“ƒ|ƒŠƒ“ŠÖ”‚ɐ§Œä‚ðˆÚ‚·
@@ -176,9 +179,10 @@
 
 	void ScopedThreadExclusive::Unfreeze(const std::vector<DWORD>& threads)
 	{
-		BOOST_FOREACH (const DWORD& tid, threads)
+		for (std::vector<DWORD>::const_iterator tid = threads.begin();
+			tid != threads.end(); tid++)
 		{
-			ScopedHandle hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, tid);
+			ScopedHandle hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, *tid);
 			ResumeThread(hThread);
 		}
 	}
diff -urw MinHook_110_src.original/MinHook/libMinHook/src/thread.h MinHook_110_src/MinHook/libMinHook/src/thread.h
--- MinHook_110_src.original/MinHook/libMinHook/src/thread.h	2009-11-17 22:48:38.000000000 +0000
+++ MinHook_110_src/MinHook/libMinHook/src/thread.h	2012-04-19 11:26:47.967409500 +0100
@@ -29,7 +29,6 @@
 #pragma once
 
 #include <vector>
-#include <boost/utility.hpp>
 #include <windows.h>
 
 #include "trampoline.h"
@@ -37,16 +36,19 @@
 namespace MinHook
 {
 	// ScopedLock •t‚«ƒNƒŠƒeƒBƒJƒ‹ƒZƒNƒVƒ‡ƒ“
-	class CriticalSection : boost::noncopyable
+	class CriticalSection
 	{
 	public:
-		class ScopedLock : boost::noncopyable
+		class ScopedLock
 		{
 		private:
 			CriticalSection& cs_;
 		public:
 			ScopedLock(CriticalSection& cs);
 			~ScopedLock();
+		private:			
+			ScopedLock(const ScopedLock&);
+			const ScopedLock& operator=(const ScopedLock&);
 		};
 
 	private:
@@ -56,6 +58,9 @@
 		~CriticalSection();
 		void enter();
 		void leave();
+	private:			
+		CriticalSection(const CriticalSection&);
+		const CriticalSection& operator=(const CriticalSection&);
 	};
 
 	// “¯ˆêƒvƒƒZƒX“à‚Ì‘¼‚̃XƒŒƒbƒh‚ð‚·‚×‚Ä’âŽ~
diff -urw MinHook_110_src.original/MinHook/libMinHook/src/trampoline.cpp MinHook_110_src/MinHook/libMinHook/src/trampoline.cpp
--- MinHook_110_src.original/MinHook/libMinHook/src/trampoline.cpp	2009-11-25 06:40:56.000000000 +0000
+++ MinHook_110_src/MinHook/libMinHook/src/trampoline.cpp	2012-04-19 11:26:47.971409700 +0100
@@ -28,7 +28,6 @@
 
 #include <cassert>
 #include <vector>
-#include <boost/foreach.hpp>
 #include "pstdint.h"
 
 #if defined _M_X64
@@ -229,9 +228,10 @@
 #if defined _M_X64
 		uintptr_t* pt = reinterpret_cast<uintptr_t*>(ct.pTable); 
 #endif
-		BOOST_FOREACH (const TEMP_ADDR& ta, ct.tempAddr)
+		for (std::vector<TEMP_ADDR>::iterator ta = ct.tempAddr.begin();
+			ta != ct.tempAddr.end(); ta++)
 		{
-			if (ta.position > ct.trampoline.size() - sizeof(uint32_t))
+			if (ta->position > ct.trampoline.size() - sizeof(uint32_t))
 			{
 				return false;
 			}
@@ -245,11 +245,11 @@
 			else
 #endif
 			{
-				addr = ta.address;
+				addr = ta->address;
 			}
 
-			*reinterpret_cast<uint32_t*>(&ct.trampoline[ ta.position ]) 
-				= static_cast<uint32_t>(addr - (reinterpret_cast<uintptr_t>(ct.pTrampoline) + ta.pc));
+			*reinterpret_cast<uint32_t*>(&ct.trampoline[ ta->position ]) 
+				= static_cast<uint32_t>(addr - (reinterpret_cast<uintptr_t>(ct.pTrampoline) + ta->pc));
 		}
 
 		for (size_t i = 0; i < ct.oldIPs.size(); ++i)
@@ -266,7 +266,20 @@
 {
 	inline uintptr_t GetRelativeBranchDestination(uint8_t* pInst, const hde_t& hs)
 	{
-		return reinterpret_cast<uintptr_t>(pInst) + hs.len + static_cast<int32_t>(hs.imm.imm32);
+		int32_t imm;
+
+		if (hs.opcode == 0xEB || // JMP short
+			(hs.opcode & 0xF0) == 0x70 || // Jcc short
+			hs.opcode == 0xE3) // JECXZ short
+		{
+			imm = (int32_t)(int8_t)hs.imm.imm8;
+		}
+		else
+		{
+			imm = (int32_t)hs.imm.imm32;
+		}
+
+		return (uintptr_t)pInst + hs.len + imm;
 	}
 	
 	inline bool IsInternalJump(void* pTarget, uintptr_t dest)

GeneralRe: Patch to remove dependency on boostmemberdijedodol26-Jan-13 17:54 
one little miss on x64 build line 241,
need to change: "if (ta.address < 0x10000)" to "if (ta->address < 0x10000)"
QuestionAccess Violation with 64 bit codememberNJAS16-Apr-12 23:32 
I get a crash ( access violation ) every time hooking CreateFileA, CreateFileW etc. on Windows7 x64
 
First-chance exception at 0x61cbf10f (msvcr100d.dll) in test_ntfs_parser.exe: 0xC0000005: Access violation reading location 0x0000000000000014. having trashed the stack.
QuestionBug - LoadLibraryExW hook fails on windows 2008 r2memberGulshan Vaswani27-Dec-11 0:11 
Hi,
 
Thank you for having a look at this post.
 
I am facing a problem when I hook LoadLibraryExW function in windows 2008 r2 SP1. A crash occurs when this function is called.
 
But ANSI version (LoadLibraryExA) works fine.
 
Both versions of LoadLibraryEx work fine on windows 2008.
 
Note: I modified your sample code to hook LoadLibraryExW function (I am loading dynamically notepad.exe) process.
 
Thanks,
Gulshan
AnswerRe: Bug - LoadLibraryExW hook fails on windows 2008 r2memberamimouni10-May-13 2:31 
Can't hook LoadLibraryExW also on win7 x64 ... any help ?
the rest works fine ...
 
Thanks!
GeneralRe: Bug - LoadLibraryExW hook fails on windows 2008 r2memberskhanvilkar@hpiinc.com10-May-13 4:42 
Couldn't reproduce it on Windows 7 x64.
 
Source code:
http://pastebin.com/9Vij4mAh[^]
 
It should show a message box if the hook succeeded.
Works as expected on my machine.
GeneralRe: Bug - LoadLibraryExW hook fails on windows 2008 r2memberamimouni12-May-13 3:42 
Sorry, found out a coding issue on my side, hooking loadlibraryExW under x64 Win7 works perfect Wink | ;)
 
Thanks
GeneralRe: Bug - LoadLibraryExW hook fails on windows 2008 r2 [modified]memberObble31-May-13 6:01 
I am getting the same issue.   Although the DetourFunc will be call, any attempt to call the function pointer to the original function "pFoo" (probably casted) will crash.  
 
Basically call pFoo in DetourFunc() in Win7 x64   and it will crash, but not ExA or in 86bit mode.
 
Also, any attempt to call the original LoadLibaryExW, when hooked but not enabled, will report invalid instructions.

-- modified 31-May-13 12:13pm.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130617.1 | Last Updated 28 Nov 2009
Article Copyright 2009 by Tsuda Kageyu
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid