钩子编程
示例代码 > 使用跳转指令的API/函数钩子拦截

下述例子使用JMP（英语：）指令，修改windows API中的MessageBoxW函数的前6个字节执行其他代码。这段代码编译为DLL文件，采用DLL注入技术让应用程序使用。微软提供了封装好的Detours库用于此目的。
/*
 This idea is based on chrom-lib approach, Distributed under GNU LGPL License.
 Source chrom-lib: https://github.com/linuxexp/chrom-lib
 Copyright (C) 2011  Raja Jamwal
*/
#include <windows.h>  
#define SIZE 6

 typedef int (WINAPI *pMessageBoxW)(HWND, LPCWSTR, LPCWSTR, UINT);  // Messagebox prototype
 int WINAPI MyMessageBoxW(HWND, LPCWSTR, LPCWSTR, UINT);            // Our detour

 void BeginRedirect(LPVOID);                                        
 pMessageBoxW pOrigMBAddress = NULL;                                // address of original
 BYTE oldBytes[SIZE] = {0};                                         // backup
 BYTE JMP[SIZE] = {0};                                              // 6 byte JMP instruction
 DWORD oldProtect, myProtect = PAGE_EXECUTE_READWRITE;

 INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)  
 {  
   switch(Reason)  
   {  
   case DLL_PROCESS_ATTACH:                                        // if attached
     pOrigMBAddress = (pMessageBoxW)                      
       GetProcAddress(GetModuleHandle("user32.dll"),               // get address of original 
               "MessageBoxW");  
     if(pOrigMBAddress != NULL)  
       BeginRedirect(MyMessageBoxW);                               // start detouring
     break;

   case DLL_PROCESS_DETACH:  
     memcpy(pOrigMBAddress, oldBytes, SIZE);                       // restore backup

   case DLL_THREAD_ATTACH:  
   case DLL_THREAD_DETACH:  
     break;  
   }  
   return TRUE;  
 }

 void BeginRedirect(LPVOID newFunction)  
 {  
   BYTE tempJMP[SIZE] = {0xE9, 0x90, 0x90, 0x90, 0x90, 0xC3};         // 0xE9 = JMP 0x90 = NOP 0xC3 = RET
   memcpy(JMP, tempJMP, SIZE);                                        // store jmp instruction to JMP
   DWORD JMPSize = ((DWORD)newFunction - (DWORD)pOrigMBAddress - 5);  // calculate jump distance
   VirtualProtect((LPVOID)pOrigMBAddress, SIZE,                       // assign read write protection
           PAGE_EXECUTE_READWRITE, &oldProtect);  
   memcpy(oldBytes, pOrigMBAddress, SIZE);                            // make backup
   memcpy(&JMP[1], &JMPSize, 4);                              // fill the nop's with the jump distance (JMP,distance(4bytes),RET)
   memcpy(pOrigMBAddress, JMP, SIZE);                                 // set jump instruction at the beginning of the original function
   VirtualProtect((LPVOID)pOrigMBAddress, SIZE, oldProtect, NULL);    // reset protection
 }

 int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uiType)  
 {  
   VirtualProtect((LPVOID)pOrigMBAddress, SIZE, myProtect, NULL);     // assign read write protection
   memcpy(pOrigMBAddress, oldBytes, SIZE);                            // restore backup
   int retValue = MessageBoxW(hWnd, lpText, lpCaption, uiType);       // get return value of original function
   memcpy(pOrigMBAddress, JMP, SIZE);                                 // set the jump instruction again
   VirtualProtect((LPVOID)pOrigMBAddress, SIZE, oldProtect, NULL);    // reset protection
   return retValue;                                                   // return original return value
 }