HOOK API(三)
—— HOOK 所有程序的 MessageBox
原文出處:http://www.cnblogs.com/fanling999/p/4595035.html
0x00 前言
本實例要實現HOOK MessageBox,包括MessageBoxA和MessageBoxW,其實現細節與HOOK API(二)中介紹的基本類似,唯一不同的是,本實例要實現對所有程序的HOOK MessageBox,即無論系統中哪一個程序調用MessageBox都會被重定向到我們實現的新的API中。
之前說過,在Windows中,每個進程都有自己的地址空間,進程不能調用別的進程中的函數。這里涉及到一個關鍵,如何讓我們實現的新的API調用地址存在於所有進程的地址空間中呢?如果這無法實現的話,其他進程就無法調用到我們所實現的API。這里涉及到的關鍵就是,如何將我們的代碼注入到別的進程中。
這里有一個實現手段,就是將我們實現的代碼隨着系統鈎子注入到目標進程中,我們在HOOK API (一)中講過鼠標鈎子,鼠標鈎子一旦啟動,就會存在於每個當前運行的進程中,實現對屏幕坐標的定位。還有一個關鍵就是,這樣的鈎子需要注入到多個目標進程中,那么這就要在動態鏈接庫(DLL)中實現,然后啟動某一主調進程將這樣一個DLL注入到目標進程中,從而實現HOOK API。
本實例介紹如何將實現了HOOK MessageBox的DLL注入到所有進程中的過程。
0x01 HOOK DLL的實現
建立一個MFC DLL工程
由於被實例的DLL用於MFC框架,因此創建的是MFC DLL,需要的話,也可以建立其他類型的DLL工程。
鼠標鈎子回調函數
我們的DLL要跟隨鼠標鈎子注入到目標進程中,而鼠標鈎子是系統鈎子,我們需要實現其鈎子回調函數。
/* 鼠標鈎子子過程,目的是加載本dll到使用鼠標的程序中。 鼠標鈎子的作用:當鼠標在某程序窗口中時,就會加載我們這個dll。 */ LRESULT CALLBACK MouseProc( int nCode, // hook code WPARAM wParam,// message identifier LPARAM lParam // mouse coordinates )
{ return CallNextHookEx(hhk,nCode,wParam,lParam); }
安裝鼠標鈎子
調用SetWindowsHookEx() API可以安裝鼠標鈎子,其中SetWindowsHookEx() 原型如下:
HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn, INSTANCE hMod,DWORD dwThreadId )
參數:
idHook表示鈎子類型,它是和鈎子函數類型一一對應的。比如,WH_KEYBOARD表示安裝的是鍵盤鈎子,WH_MOUSE表示是鼠標鈎子等等。
Lpfn是鈎子函數的地址。
HMod是鈎子函數所在的實例的句柄。對於線程鈎子,該參數為NULL;對於系統鈎子,該參數為鈎子函數所在的DLL句柄。
dwThreadId 指定鈎子所監視的線程的線程號。對於全局鈎子,該參數為NULL。
返回值:
SetWindowsHookEx返回所安裝的鈎子句柄。
// // 安裝鈎子 // BOOL WINAPI StartHook(HWND hWnd){ g_hWnd = hWnd; hhk = ::SetWindowsHookEx(WH_MOUSE,MouseProc,g_hInstance,0); if (hhk == NULL){ return FALSE; }else{ return TRUE; } }
卸載鼠標鈎子
// // 卸載鈎子 // BOOL WINAPI StopHook() { /* 卸載鈎子時,一定要記得恢復原API入口。 這里恢復的只是主程序的原API入口,其它程序的API入口還沒有被恢復。 因此我們必須處理dll退出過程,即在函數ExitInstance()中,調用恢復 API入口的函數HookOff(),只有這樣,其它程序再次調用原API時,才不 會發生錯誤。 當我們HOOK所有程序的某個系統API時,千萬要注意在ExitInstance()中 調用HookOff()!!!!! */ HookOff(); if (hhk!=NULL){ UnhookWindowsHookEx(hhk); FreeLibrary(g_hInstance); } return TRUE; }
導出我們的安裝和卸載函數
.def內容如下:
將StarHook和StopHook函數導出,一遍主程序安裝和卸載HOOK程序。
; HookDll.def : 聲明 DLL 的模塊參數。 LIBRARY "HookMessageBox" EXPORTS ; 此處可以是顯式導出 StartHook StopHook
MFC DLL的InitInstance()函數
/* dll程序入口,當程序加載dll時,會執行InitInstance() */ BOOL CHookDllApp::InitInstance(){ CWinApp::InitInstance(); g_hInstance = AfxGetInstanceHandle();// 獲取當前DLL實例句柄 AdjustPrivileges(); // 提高權限 DWORD dwPid = ::GetCurrentProcessId(); hProcess = ::OpenProcess(PROCESS_ALL_ACCESS,0,dwPid); if (hProcess == NULL){ CString str; str.Format(_T("OpenProcess fail, and error code = %d"),GetLastError()); AfxMessageBox(str); return FALSE; } Inject(); // 開始注入 return TRUE; }
MFC DLL的ExitInstance()函數
int CHookDllApp::ExitInstance(){ /* dll退出時,一定要記得恢復原API的入口!!! 我們編寫的dll會被注入到所有目標進程中,若dll退出時,沒有恢復原API入口, 那么被掛鈎的程序再次調用該API時,會發生錯誤。 因為我們的dll程序已經退出,但原API的入口仍為我們所定義的API的入口,這 時被掛鈎的程序無法找到我們實現的API,然而原API的地址又沒有被恢復,也就 調用不到原API,這時程序自然會發生崩潰了。 */ HookOff(); return CWinApp::ExitInstance(); }
HOOK API實現
-
注入函數,保存新的,原來的API的入口
該函數的主要功能是保存新的和原來的API入口,並且在最后啟動HOOK。需要注意的是,這個函數只能被調用一次,即只能進行一次注入操作。
/* 注入 */ void Inject(){ if ( TRUE == bIsInJected){ return; } bIsInJected = TRUE; // 保證只調用一次 // // 獲取函數 // HMODULE hmodle = ::LoadLibrary(_T("User32.dll")); oldMsgBoxA = (TypeMsgBoxA) ::GetProcAddress(hmodle,"MessageBoxA"); pfMsgBoxA = (FARPROC)oldMsgBoxA; oldMsgBoxW = (TypeMsgBoxW) ::GetProcAddress(hmodle,"MessageBoxW"); pfMsgBoxW = (FARPROC)oldMsgBoxW; if (pfMsgBoxA == NULL){ AfxMessageBox(_T("獲取 MessageBoxA 函數失敗")); return; } if ( pfMsgBoxW == NULL){ AfxMessageBox(_T("獲取 MessageBoxW 函數失敗")); return; } // 保存原API地址 _asm { lea edi,oldCodeA // 取數組基地址 mov esi,pfMsgBoxA // API地址 cld // 設置方向 mov ecx,CODE_LENGTH rep movsb } _asm{ lea edi,oldCodeW mov esi,pfMsgBoxW cld mov ecx,CODE_LENGTH rep movsb } // 將新地址復制到入口 newCodeA[0] = newCodeW [0] = 0xe9; // jmp 指定代碼 _asm { lea eax,MyMessageBoxA // 新API地址 mov ebx,pfMsgBoxA // 原API地址 sub eax,ebx sub eax,CODE_LENGTH // 跳轉地址 = 新API地址 - 原API地址 - 指令長度 mov dword ptr [newCodeA+1],eax // eax 32bit = 4 BYTE } _asm { lea eax,MyMessageBoxW mov ebx,pfMsgBoxW sub eax,ebx sub eax,CODE_LENGTH mov dword ptr [newCodeW + 1],eax } HookOn(); // 開始HOOK }
該函數主要完成向進程控制塊寫寫指令的任務。供HookOn()和HookOff()調用,用來將原API入口,或新的API入口寫入到進程的地址空間中。
/* 將長度為length的pcode寫入到地址lpAddress中。 */ void WriteMemory(LPVOID lpAddress,BYTE* pcode,int length){ // 保證本進程句柄不為NULL ASSERT(hProcess != NULL); DWORD dwTemp,dwOldProtect,dwRet,dwWrited; // 修改API入口前length個字節為 jmp xxxx VirtualProtectEx(hProcess,lpAddress,length,PAGE_READWRITE,&dwOldProtect); dwRet = WriteProcessMemory(hProcess,lpAddress,pcode,length,&dwWrited); if ( 0 == dwRet || 0 == dwWrited){ AfxMessageBox(_T("哭!!寫入失敗")); } VirtualProtectEx(hProcess,lpAddress,length,dwOldProtect,&dwTemp); }
/* 用新API地址替換原API地址 */ void HookOn(){ ASSERT(hProcess != NULL); DWORD dwTemp,dwOldProtect,dwRet,dwWrited; WriteMemory(pfMsgBoxA,newCodeA,CODE_LENGTH); WriteMemory(pfMsgBoxW,newCodeW,CODE_LENGTH); }
/* 恢復原API地址 */ void HookOff(){ ASSERT(hProcess != NULL); DWORD dwTemp,dwOldProtect,dwRet,dwWrited; WriteMemory(pfMsgBoxA,oldCodeA,CODE_LENGTH); WriteMemory(pfMsgBoxW,oldCodeW,CODE_LENGTH); }
/* 自己用於替換的API */ int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCation,UINT uType){ int nRet = 0; HookOff(); nRet = ::MessageBoxA(hWnd,"哈哈 ^_^,MessageBoxA 被 HOOK 咯",lpCation,uType); nRet = ::MessageBoxA(hWnd,lpText,lpCation,uType); HookOn(); return nRet; } int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCation,UINT uType){ int nRet = 0; HookOff(); nRet = ::MessageBoxW(hWnd,_T("O(∩_∩)O哈哈~,MMessageBoxW 被 HOOK 咯"),lpCation,uType); nRet = ::MessageBoxW(hWnd,lpText,lpCation,uType); HookOn(); return nRet; }
這段代碼並不是必須的,但有些時候會出現程序權限不足以獲取進程句柄的情況,這個時候需要在代碼執行前調用該函數來提高程序的權限。
/* 提升權限 */ bool AdjustPrivileges() { HANDLE hToken; TOKEN_PRIVILEGES tp; TOKEN_PRIVILEGES oldtp; DWORD dwSize=sizeof(TOKEN_PRIVILEGES); LUID luid; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) return true; else return false; } if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) { CloseHandle(hToken); return false; } ZeroMemory(&tp, sizeof(tp)); tp.PrivilegeCount=1; tp.Privileges[0].Luid=luid; tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; /* Adjust Token Privileges */ if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &oldtp, &dwSize)) { CloseHandle(hToken); return false; } // close handles CloseHandle(hToken); return true; }
0x02 HOOK 窗體實現
HINSTANCE g_hinstDll = NULL; // 開始 HOOK void CHookWindowDlg::OnBnClickedButtonStart(){ // TODO: 在此添加控件通知處理程序代碼 g_hinstDll = LoadLibrary(_T("HookDll.dll")); if ( NULL == g_hinstDll){ AfxMessageBox(_T("加載 HookDll.dll 失敗")); } typedef BOOL (CALLBACK *HookStart)(HWND hwnd); HookStart hookStart = NULL; hookStart = (HookStart)::GetProcAddress(g_hinstDll,"StartHook"); if ( NULL == hookStart){ AfxMessageBox(_T("獲取 StartHook 函數失敗")); return; } bool ret = hookStart(m_hWnd); if (ret){ m_list.InsertItem(m_list.GetItemCount(),_T("啟動鈎子成功")); m_list.EnsureVisible(m_list.GetItemCount()-1,FALSE); }else{ m_list.InsertItem(m_list.GetItemCount(),_T("啟動鈎子失敗")); m_list.EnsureVisible(m_list.GetItemCount()-1,FALSE); } }
// 終止 HOOK void CHookWindowDlg::OnBnClickedButtonStop(){ // TODO: 在此添加控件通知處理程序代碼 typedef BOOL (CALLBACK* HookStop)(); HookStop hookStop = NULL; if (NULL == g_hinstDll) // 一定要加這個判斷,若不為空的話就不需要在重新加載,否則會是不同的實例 { g_hinstDll = LoadLibrary(_T("HookDll.dll")); if (g_hinstDll == NULL){ AfxMessageBox(_T("加載 HookDll.dll 失敗")); return; } } hookStop = ::GetProcAddress(g_hinstDll,"StopHook"); if (hookStop == NULL){ AfxMessageBox(_T("獲取 StopHook 失敗")); FreeLibrary(g_hinstDll); g_hinstDll=NULL; return; } hookStop(); if (g_hinstDll!= NULL){ ::FreeLibrary(g_hinstDll); } m_list.InsertItem(m_list.GetItemCount(),_T("終止HOOK成功")); }
// MessageBoxA void CHookWindowDlg::OnBnClickedButtonMsga(){ // TODO: 在此添加控件通知處理程序代碼 MessageBoxA(m_hWnd,"這是正常的MessageBoxA...","哈哈",0); }
// MessageBoxW void CHookWindowDlg::OnBnClickedButtonMsgw(){ // TODO: 在此添加控件通知處理程序代碼 MessageBoxW(_T("這是正常的MessageBoxW..."),_T("呵呵"),0); }
0x03 測試
本實例在自己實現的API中打印一句自己的話,然后再彈出原本的對話框。測試結果如下:
可以看到,先彈出了我們自己的對話框,然后才彈出真正的對話框。
可以看到,先彈出我們的對話框,然后才彈出真正的對話框。
打開技術本,打開查找對話框,然后輸入一個字符串,"查找一下",這個時候同樣先彈出我們的對話框,然后才彈出原來的,找不到對話框。
0x04 附錄——HOOK DLL關鍵源碼
// HookDll.cpp : 定義 DLL 的初始化例程。 #include "stdafx.h" #include "HookDll.h" #include <Windows.h> #ifdef _DEBUG #define new DEBUG_NEW #endif /* 全局共享變量 */ #pragma data_seg("Share") HWND g_hWnd = NULL ; // 主窗口句柄 HINSTANCE g_hInstance = NULL; // 本dll實例句柄 HHOOK hhk = NULL; // 鼠標鈎子句柄 #pragma data_seg() #pragma comment(linker,"/section:Share,rws") HANDLE hProcess = NULL; // 當前進程 BOOL bIsInJected = FALSE; // 是否已注入標記 TCHAR* msgToMain = new TCHAR[200]; // 發給主調程序的信息 /* 原函數定義 */ typedef int (WINAPI *TypeMsgBoxA)(HWND hWnd,LPCSTR lpText, LPCSTR lpCaption,UINT uType); typedef int (WINAPI *TypeMsgBoxW)(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType); TypeMsgBoxA oldMsgBoxA = NULL; // 用於保存原函數地址 TypeMsgBoxW oldMsgBoxW = NULL; // 用於保存原楷書地址 FARPROC pfMsgBoxA = NULL; // 指向原函數地址的遠指針 FARPROC pfMsgBoxW = NULL; // 指向原函數地址的遠指針 #define CODE_LENGTH 5 BYTE oldCodeA[CODE_LENGTH]; // 保存原來API入口代碼 BYTE oldCodeW[CODE_LENGTH]; // 保存原來API入口代碼 BYTE newCodeA[CODE_LENGTH]; // 保存新API入口代碼,jmp xxxx BYTE newCodeW[CODE_LENGTH]; // 保存新API入口代碼,jmp xxxx /* 自己編寫的API */ int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCation,UINT uType); int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCation,UINT uType); /* 其它函數原型聲明 */ void HookOn(); // 開始HOOK void HookOff(); // 關閉HOOK void Inject(); // 注入 BOOL WINAPI StartHook(HWND hWnd); // 加載鈎子 BOOL WINAPI StopHook(); // 卸載鈎子 bool AdjustPrivileges(); // 提升權限 // //TODO: 如果此 DLL 相對於 MFC DLL 是動態鏈接的, // 則從此 DLL 導出的任何調入 // MFC 的函數必須將 AFX_MANAGE_STATE 宏添加到 // 該函數的最前面。 // // 例如: // // extern "C" BOOL PASCAL EXPORT ExportedFunction() // { // AFX_MANAGE_STATE(AfxGetStaticModuleState()); // // 此處為普通函數體 // } // // 此宏先於任何 MFC 調用 // 出現在每個函數中十分重要。這意味着 // 它必須作為函數中的第一個語句 // 出現,甚至先於所有對象變量聲明, // 這是因為它們的構造函數可能生成 MFC // DLL 調用。 // // 有關其他詳細信息, // 請參閱 MFC 技術說明 33 和 58。 // // CHookDllApp BEGIN_MESSAGE_MAP(CHookDllApp, CWinApp) END_MESSAGE_MAP() // CHookDllApp 構造 CHookDllApp::CHookDllApp(){ // TODO: 在此處添加構造代碼, // 將所有重要的初始化放置在 InitInstance 中 } // 唯一的一個 CHookDllApp 對象 CHookDllApp theApp; // CHookDllApp 初始化 /* dll程序入口,當程序加載dll時,會執行InitInstance() */ BOOL CHookDllApp::InitInstance(){ CWinApp::InitInstance(); g_hInstance = AfxGetInstanceHandle();// 獲取當前DLL實例句柄 AdjustPrivileges(); // 提高權限 DWORD dwPid = ::GetCurrentProcessId(); hProcess = ::OpenProcess(PROCESS_ALL_ACCESS,0,dwPid); if (hProcess == NULL){ CString str; str.Format(_T("OpenProcess fail, and error code = %d"),GetLastError()); AfxMessageBox(str); return FALSE; } Inject(); // 開始注入 return TRUE; } int CHookDllApp::ExitInstance(){ /* dll退出時,一定要記得恢復原API的入口!!! 我們編寫的dll會被注入到所有目標進程中,若dll退出時,沒有恢復原API入口, 那么被掛鈎的程序再次調用該API時,會發生錯誤。 因為我們的dll程序已經退出,但原API的入口仍為我們所定義的API的入口,這 時被掛鈎的程序無法找到我們實現的API,然而原API的地址又沒有被恢復,也就 調用不到原API,這時程序自然會發生崩潰了。 */ HookOff(); return CWinApp::ExitInstance(); } /* 提升權限 */ bool AdjustPrivileges() { HANDLE hToken; TOKEN_PRIVILEGES tp; TOKEN_PRIVILEGES oldtp; DWORD dwSize=sizeof(TOKEN_PRIVILEGES); LUID luid; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) return true; else return false; } if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) { CloseHandle(hToken); return false; } ZeroMemory(&tp, sizeof(tp)); tp.PrivilegeCount=1; tp.Privileges[0].Luid=luid; tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; /* Adjust Token Privileges */ if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &oldtp, &dwSize)) { CloseHandle(hToken); return false; } // close handles CloseHandle(hToken); return true; } /* 鼠標鈎子子過程,目的是加載本dll到使用鼠標的程序中。 鼠標鈎子的作用:當鼠標在某程序窗口中時,就會加載我們這個dll。 */ LRESULT CALLBACK MouseProc( int nCode, // hook code WPARAM wParam,// message identifier LPARAM lParam // mouse coordinates ) { return CallNextHookEx(hhk,nCode,wParam,lParam); } /* 將長度為length的pcode寫入到地址lpAddress中。 */ void WriteMemory(LPVOID lpAddress,BYTE* pcode,int length){ // 保證本進程句柄不為NULL ASSERT(hProcess != NULL); DWORD dwTemp,dwOldProtect,dwRet,dwWrited; // 修改API入口前length個字節為 jmp xxxx VirtualProtectEx(hProcess,lpAddress,length,PAGE_READWRITE,&dwOldProtect); dwRet = WriteProcessMemory(hProcess,lpAddress,pcode,length,&dwWrited); if ( 0 == dwRet || 0 == dwWrited){ AfxMessageBox(_T("哭!!寫入失敗")); } VirtualProtectEx(hProcess,lpAddress,length,dwOldProtect,&dwTemp); } /* 用新API地址替換原API地址 */ void HookOn(){ ASSERT(hProcess != NULL); DWORD dwTemp,dwOldProtect,dwRet,dwWrited; WriteMemory(pfMsgBoxA,newCodeA,CODE_LENGTH); WriteMemory(pfMsgBoxW,newCodeW,CODE_LENGTH); } /* 恢復原API地址 */ void HookOff(){ ASSERT(hProcess != NULL); DWORD dwTemp,dwOldProtect,dwRet,dwWrited; WriteMemory(pfMsgBoxA,oldCodeA,CODE_LENGTH); WriteMemory(pfMsgBoxW,oldCodeW,CODE_LENGTH); } /* 注入 */ void Inject(){ if ( TRUE == bIsInJected){ return; } bIsInJected = TRUE; // 保證只調用一次 // // 獲取函數 // HMODULE hmodle = ::LoadLibrary(_T("User32.dll")); oldMsgBoxA = (TypeMsgBoxA) ::GetProcAddress(hmodle,"MessageBoxA"); pfMsgBoxA = (FARPROC)oldMsgBoxA; oldMsgBoxW = (TypeMsgBoxW) ::GetProcAddress(hmodle,"MessageBoxW"); pfMsgBoxW = (FARPROC)oldMsgBoxW; if (pfMsgBoxA == NULL){ AfxMessageBox(_T("獲取 MessageBoxA 函數失敗")); return; } if ( pfMsgBoxW == NULL){ AfxMessageBox(_T("獲取 MessageBoxW 函數失敗")); return; } // // 保存原API地址 // _asm { lea edi,oldCodeA // 取數組基地址 mov esi,pfMsgBoxA // API地址 cld // 設置方向 mov ecx,CODE_LENGTH rep movsb } _asm { lea edi,oldCodeW mov esi,pfMsgBoxW cld mov ecx,CODE_LENGTH rep movsb } // // 將新地址復制到入口 // newCodeA[0] = newCodeW [0] = 0xe9; // jmp 指定代碼 _asm { lea eax,MyMessageBoxA // 新API地址 mov ebx,pfMsgBoxA // 原API地址 sub eax,ebx sub eax,CODE_LENGTH // 跳轉地址 = 新API地址 - 原API地址 - 指令長度 mov dword ptr [newCodeA+1],eax // eax 32bit = 4 BYTE }
_asm { lea eax,MyMessageBoxW mov ebx,pfMsgBoxW sub eax,ebx sub eax,CODE_LENGTH mov dword ptr [newCodeW + 1],eax } HookOn(); // 開始HOOK } // // 安裝鈎子 // BOOL WINAPI StartHook(HWND hWnd){ g_hWnd = hWnd; hhk = ::SetWindowsHookEx(WH_MOUSE,MouseProc,g_hInstance,0); if (hhk == NULL){ return FALSE; } else{ return TRUE; } } // // 卸載鈎子 // BOOL WINAPI StopHook(){ /* 卸載鈎子時,一定要記得恢復原API入口。 這里恢復的只是主程序的原API入口,其它程序的API入口還沒有被恢復。 因此我們必須處理dll退出過程,即在函數ExitInstance()中,調用恢復 API入口的函數HookOff(),只有這樣,其它程序再次調用原API時,才不 會發生錯誤。 當我們HOOK所有程序的某個系統API時,千萬要注意在ExitInstance()中 調用HookOff()!!!!! */ HookOff(); if (hhk!=NULL){ UnhookWindowsHookEx(hhk); FreeLibrary(g_hInstance); } return TRUE; } /* 自己用於替換的API */ int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCation,UINT uType){ int nRet = 0; HookOff(); nRet = ::MessageBoxA(hWnd,"哈哈 ^_^,MessageBoxA 被 HOOK 咯",lpCation,uType); nRet = ::MessageBoxA(hWnd,lpText,lpCation,uType); HookOn(); return nRet; } int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCation,UINT uType){ int nRet = 0; HookOff(); nRet = ::MessageBoxW(hWnd,_T("O(∩_∩)O哈哈~,MMessageBoxW 被 HOOK 咯"),lpCation,uType); nRet = ::MessageBoxW(hWnd,lpText,lpCation,uType); HookOn(); return nRet; }