Global Hook does not necessarily need to use Dll, such as global mouse hook, keyboard hook do not need Dll, but to hook the API, you need the assistance of Dll, put Dll's code directly below: (Note that MFC DLL is used here)
// Test_Dll(mfc).cpp: An initialization routine for defining DLLs. // #include "stdafx.h" #include "Test_Dll(mfc).h" #ifdef _DEBUG #define new DEBUG_NEW #endif #pragma region My code #define UM_WNDTITLE WM_USER+100 // Custom messages (message identifiers for private window classes) // Global shared variables (shared data between multiple processes) #pragma data_seg(".Share") HWND g_hWnd = NULL; // Main window handle HHOOK hhk = NULL; // Mouse hook handle HINSTANCE hInst = NULL; // This dll instance handle #pragma data_seg() #pragma comment(linker, "/section:.Share,rws") // global variable HANDLE hProcess=NULL; // process handle BOOL bIsInjected=FALSE; // Is injection complete typedef int (WINAPI *MsgBoxA)(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType); // Declare an alias MsgBox A typedef int (WINAPI *MsgBoxW)(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType); // Declare an alias MsgBox W MsgBoxA oldMsgBoxA=NULL; // Save the address of the original function MsgBoxW oldMsgBoxW=NULL; // Save the address of the original function FARPROC pfMsgBoxA=NULL; // A remote pointer to the address of the original function FARPROC pfMsgBoxW=NULL; // A remote pointer to the address of the original function BYTE OldCodeA[5]; // Old system API entry code BYTE NewCodeA[5]; // API code to jump (jmp xxx) BYTE OldCodeW[5]; // Old system API entry code BYTE NewCodeW[5]; // API code to jump (jmp xxx) int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType); // Our own MesageBox A function int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType); // Our own MesageBox W function // Open the hook (modify the first 5 bytes of the API) void HookOn() { // Verify that the process handle is empty ASSERT(hProcess!=NULL); DWORD dwTemp = 0, // Modified memory protection properties dwOldProtect, // Previous memory protection properties dwRet = 0, // Memory write success flag, 0 unsuccessful, 1 successful dwWrite; // Number of bytes written to process memory // Change virtual memory protection VirtualProtectEx( hProcess, // process handle pfMsgBoxA, // A pointer to the address of the protected area 5, // The byte size of the area to be changed PAGE_READWRITE, // Memory protection type, PAGE_READWRITE: Readable and Writable &dwOldProtect // Receive the original memory protection properties ); // Determine whether memory was successfully written dwRet = WriteProcessMemory( hProcess, // process handle pfMsgBoxA, // A pointer to a write address NewCodeA, // Pointer to the buffer where the written content is stored 5, // Number of bytes written &dwWrite // The number of bytes received to the process ); if (0==dwRet||0==dwWrite){ TRACE("NewCodeA Write failure"); // Logging information } // Recovery of memory protection status VirtualProtectEx(hProcess,pfMsgBoxA,5,dwOldProtect,&dwTemp); // Ibid., operate on the remaining Message Box W VirtualProtectEx(hProcess,pfMsgBoxW,5,PAGE_READWRITE,&dwOldProtect); dwRet=WriteProcessMemory(hProcess,pfMsgBoxW,NewCodeW,5,&dwWrite); if (0==dwRet||0==dwWrite){TRACE("NewCodeW Write failure");} VirtualProtectEx(hProcess,pfMsgBoxW,5,dwOldProtect,&dwTemp); } // Close the hook (modify the first 5 bytes of the API) void HookOff() { // Verify that the process handle is empty ASSERT(hProcess!=NULL); DWORD dwTemp = 0, // Modified memory protection properties dwOldProtect = 0, // Previous memory protection properties dwRet = 0, // Memory write success flag, 0 unsuccessful, 1 successful dwWrite = 0; // Number of bytes written to process memory // Change virtual memory protection VirtualProtectEx( hProcess, // process handle pfMsgBoxA, // A pointer to the address of the protected area 5, // The byte size of the area to be changed PAGE_READWRITE, // Memory protection type, PAGE_READWRITE: Readable and Writable &dwOldProtect // Receive the original memory protection properties ); dwRet = WriteProcessMemory( hProcess, // process handle pfMsgBoxA, // A pointer to a write address OldCodeA, // Pointer to the buffer where the written content is stored 5, // Number of bytes written &dwWrite // The number of bytes received to the process ); if (0==dwRet||0==dwWrite){ TRACE("OldCodeA Write failure"); // Logging information } // Recovery of memory protection status VirtualProtectEx(hProcess,pfMsgBoxA,5,dwOldProtect,&dwTemp); // Ibid., operate on the remaining Message Box W VirtualProtectEx(hProcess,pfMsgBoxW,5,PAGE_READWRITE,&dwOldProtect); WriteProcessMemory(hProcess,pfMsgBoxW,OldCodeW,5,&dwWrite); if (0==dwRet||0==dwWrite){TRACE("OldCodeW Write failure");} VirtualProtectEx(hProcess,pfMsgBoxW,5,dwOldProtect,&dwTemp); } // Code injection void Inject() { // If not injected if (!bIsInjected){ //Guarantee that only one call is made bIsInjected=TRUE; // Get the function address HMODULE hmod=::LoadLibrary(_T("User32.dll")); oldMsgBoxA=(MsgBoxA)::GetProcAddress(hmod,"MessageBoxA"); // The original Message Box A address pfMsgBoxA=(FARPROC)oldMsgBoxA; // A pointer to the original Message Box A address oldMsgBoxW=(MsgBoxW)::GetProcAddress(hmod,"MessageBoxW"); // The original Message Box W address pfMsgBoxW=(FARPROC)oldMsgBoxW; // A pointer to the original Message Box W address // If the pointer is empty, the run will end if (pfMsgBoxA==NULL){MessageBox(NULL,_T("cannot get MessageBoxA()"),_T("error"),0);return;} if (pfMsgBoxW==NULL){MessageBox(NULL,_T("cannot get MessageBoxW()"),_T("error"),0);return;} // Save the entry code in the original API to OldCodeA[], OldCodeW[] _asm { lea edi,OldCodeA ; hold OldCodeA Address to edi mov esi,pfMsgBoxA ; hold MessageBoxA Address to esi cld ; Directional Sign Position Reset movsd ; Duplication of twins movsb ; Copy byte } _asm { lea edi,OldCodeW ; Operate in the same way MessageBoxW mov esi,pfMsgBoxW cld movsd movsb } // Change the first byte of the original API to jmp NewCodeA[0]=0xe9; NewCodeW[0]=0xe9; // Compute the address to follow after jmp _asm { lea eax,MyMessageBoxA ; take MyMessageBoxA Address to eax mov ebx,pfMsgBoxA ; take MessageBoxA Address to ebx sub eax,ebx ; Calculation jmp The address to follow sub eax,5 mov dword ptr [NewCodeA+1],eax } _asm { lea eax,MyMessageBoxW ; Operate in the same way MessageBoxW mov ebx,pfMsgBoxW sub eax,ebx sub eax,5 mov dword ptr [NewCodeW+1],eax } // Start Hook HookOn(); } } // Fake Message Box A int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType) { int nRet = 0; // Restore Hook first, or it will cause a dead cycle HookOff(); // Verify that MessageBox A fails (failure returns 0) nRet = ::MessageBoxA(hWnd,"Hook MessageBoxA",lpCaption,uType); //NRet=:: MessageBox A (hWnd, lpText, lpCaption, uType); // Call the original function (if you want to operate in a dark box) // HookOn again, or only once HookOn(); return nRet; } // Fake Message Box W int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType) { int nRet = 0; // Restore Hook first, or it will cause a dead cycle HookOff(); // Verify whether Message Box W failed (failure returns 0) nRet = ::MessageBoxW(hWnd,_T("Hook MessageBoxW"),lpCaption,uType); //NRet=:: Message Box W (hWnd, lpText, lpCaption, uType); // Call the original function (if you want to operate in a dark box) // HookOn again, or only once HookOn(); return nRet; } #pragma endregion #pragma region Ignore // //TODO: If this DLL is dynamically linked relative to MFC DLL, // Any calls exported from this DLL // MFC functions must add AFX_MANAGE_STATE macros // The front of the function. // // For example: // // extern "C" BOOL PASCAL EXPORT ExportedFunction() // { // AFX_MANAGE_STATE(AfxGetStaticModuleState()); // // Here is the body of ordinary functions. // } // // This macro precedes any MFC call // It's important to appear in every function. This means // It must be the first statement in a function // Appear, even before all object variables are declared, // This is because their constructors may generate MFC // DLL call. // // For other details, // Refer to MFC Technical Notes 33 and 58. // // CTest_DllmfcApp BEGIN_MESSAGE_MAP(CTest_DllmfcApp, CWinApp) END_MESSAGE_MAP() // Construction of CTest_DllmfcApp CTest_DllmfcApp::CTest_DllmfcApp() { // TODO: Add the construction code here. // Place all the important initializations in InitInstance } // The only CTest_DllmfcApp object CTest_DllmfcApp theApp; #pragma endregion // Program entry BOOL CTest_DllmfcApp::InitInstance() { CWinApp::InitInstance(); #pragma region My code // Get the dll instance handle itself hInst = AfxGetInstanceHandle(); // Get the process ID for calling dll DWORD dwPid = ::GetCurrentProcessId(); // Get the process handle for calling dll hProcess = ::OpenProcess(PROCESS_ALL_ACCESS,0,dwPid); // Start injection Inject(); #pragma endregion return TRUE; } // Program export int CTest_DllmfcApp::ExitInstance() { // TODO: Adding dedicated code and/or calling base classes here #pragma region My code // Restore API s for other processes HookOff(); #pragma endregion return CWinApp::ExitInstance(); } #pragma region My code // Mouse hook callback LRESULT CALLBACK MouseProc( int nCode, // Hook code WPARAM wParam, // Message Identifier LPARAM lParam // Coordinates of cursors ){ if (nCode==HC_ACTION){ // Send the window handle where the hook is located to the main program ::SendMessage( g_hWnd, // Window handle for receiving messages UM_WNDTITLE, // Messages sent wParam, // Additional message information (LPARAM)(((PMOUSEHOOKSTRUCT)lParam)->hwnd) // Additional message information, here is the window handle of the window in which the mouse is located ); /* typedef struct tagMOUSEHOOKSTRUCT { // Mouse event information structure passed to WH_MOUSE POINT pt; // xy coordinates of cursors HWND hwnd; // Window handle corresponding to cursor UINT wHitTestCode; // Whether to hit or not ULONG_PTR dwExtraInfo; // Message correlation } MOUSEHOOKSTRUCT, *PMOUSEHOOKSTRUCT, *LPMOUSEHOOKSTRUCT; */ } // Tell the message to the next hook return CallNextHookEx( hhk, // Hook handle, mouse hook here nCode, wParam, lParam ); } // Installation hook BOOL WINAPI StartHook(HWND hWnd) { // Get the main window handle where the mouse is located g_hWnd = hWnd; // Get the mouse hook handle hhk = ::SetWindowsHookEx( WH_MOUSE, // Hook Type MouseProc, // Pointer to callback function hInst, // dll handle, here is the instance handle for this dll NULL // Represents all threads associated with your desktop ); // Determine whether SetWindows HookEx was successfully executed if (hhk==NULL){return FALSE;} else{return TRUE;} } // Unloading hook VOID WINAPI StopHook() { // Here only the API itself is restored. HookOff(); if (hhk!=NULL) { // UnHook mouse hook UnhookWindowsHookEx(hhk); // Uninstall dll FreeLibrary(hInst); } } #pragma endregion
Because there's no code folding here, so it's not very intuitive. I'll put a folded picture here:
Add an export function to the. def file: (usually just below the. cpp file)
; Test_Dll(mfc).def : statement DLL Module parameters. LIBRARY EXPORTS StartHook StopHook ; This can be an explicit export
Then start writing the code that calls Dll: (MFC project is used here, because the global mouse hook needs m_hWnd in CWnd)
Because I think most of the global HOOK needs to hide themselves and then silently execute, which conflicts with the style of window interaction mode of MFC, so I hide the window of MFC here. Specific methods can be referred to: https://blog.csdn.net/Simon798/article/details/99063945
HINSTANCE g_hInst; // Global variable, same as HMODULE void CTest_MFCDlg::HOOK() { // TODO: Add control notification handler code here // Loading DLL (depending on the actual path of your dll, relative path is recommended) g_hInst = ::LoadLibrary(_T("E:\\MyFiles\\Programing\\vs2012\\MyPrograms\\Test_Dll(mfc)\\Debug\\Test_Dll(mfc).dll")); // Determine whether loading is successful if (g_hInst==NULL){AfxMessageBox(_T("Load dll fail"));} // alias declarations typedef BOOL (WINAPI* StartHook)(HWND hWnd); // Call the export function StartHook in dll StartHook Hook = (StartHook)::GetProcAddress(g_hInst,"StartHook"); // Determine whether the derived function was successfully invoked if (Hook==NULL){AfxMessageBox(_T("StartHook Call failed"));} // Start Hook Hook(m_hWnd); } void CTest_MFCDlg::UNHOOK() { // TODO: Add control notification handler code here // Check whether UnHook is required if (g_hInst==NULL){return;} // alias declarations typedef VOID (WINAPI* StopHook)(); // Call the derived function StopHook in dll StopHook UnHook = (StopHook)::GetProcAddress(g_hInst,"StopHook"); // Determine whether the derived function was successfully invoked if (UnHook==NULL){AfxMessageBox(_T("StopHook Call failed"));return;} // Start UnHook UnHook(); // Uninstall dll FreeLibrary(g_hInst); // Reset g_hInst to facilitate the next UnHook judgment g_hInst=NULL; } // Form creation events int CTest_MFCDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CDialogEx::OnCreate(lpCreateStruct) == -1) return -1; // TODO: Add your dedicated creation code here // When the program is opened, the HOOK() function is executed. UNHOOK is not demonstrated here. HOOK(); } void CTest_MFCDlg::OnWindowPosChanging(WINDOWPOS* lpwndpos) { CDialogEx::OnWindowPosChanging(lpwndpos); // TODO: Add message handler code here // Hide form lpwndpos->flags &= ~SWP_SHOWWINDOW; CDialog::OnWindowPosChanging(lpwndpos); }
Design sketch: