// HookMsgBox.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "windows.h" #include#include using namespace std; // MessageBoxW函数原型 // int WINAPI MessageBoxW(__in_opt HWND hWnd,__in_opt LPCWSTR lpText,__in_opt LPCWSTR lpCaption,__in UINT uType); typedef int (WINAPI* MsgBox)(HWND, LPCWSTR, LPCWSTR, UINT); MsgBox SysMsgBox = NULL; // 指向user32下的MessageBox FARPROC fpSysMsgBox = NULL; // FARPROC 是一个4字节指针,指向一个函数的内存地址 BYTE byteSysMsgOEP[5]; // 系统MessageBox入口代码 BYTE byteMyMsgOEP[5]; // 自定义MessageBox入口代码 HANDLE hProcess = NULL; // 本应用程序句柄 HINSTANCE hInstance = NULL; // dll文件句柄 // 初始化得到本应用程序句柄 void Init() { DWORD dPid = GetCurrentProcessId(); hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dPid); } /// 开始hook void StartHook(); /// 停止hook void StopHook(); /// 获得系统MessageBox入口代码 void GetSysMsgBoxOEP(); /// 获得自定义MessageBox入口代码 void GetMySmgBoxOEP(); wchar_t* ANSIToUnicode(const string& str) { int len = 0; len = str.length(); int unicodeLen = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0); wchar_t * pUnicode; pUnicode = new wchar_t[unicodeLen + 1]; memset(pUnicode, 0, (unicodeLen + 1)*sizeof(wchar_t)); ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, (LPWSTR)pUnicode, unicodeLen); //wstring rt; //rt = (wchar_t*)pUnicode; return pUnicode; //return rt;//注意内存泄漏 } LPCWSTR stringToLPCWSTR(string orig) { size_t origsize = orig.length(); wchar_t* tTarget = new wchar_t[origsize + 1]; //const size_t newsize = 100; //size_t convertedChars = 0; //wchar_t *wcstring = (wchar_t *)malloc(sizeof(wchar_t) *(orig.length() - 1)); //mbstowcs_s(&convertedChars, wcstring, origsize, orig.c_str(), _TRUNCATE); MultiByteToWideChar(CP_ACP, 0, orig.c_str(), origsize, tTarget, origsize*sizeof(wchar_t)); return tTarget; // 抽出来比较好,不然会内存泄漏 //return wcstring; } int WINAPI MyMsgBox(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) { StopHook(); int nRet = MessageBox(hWnd, _T("hook成功"), _T("hook测试"), 0); StartHook(); return nRet; } int main() { cout << "请输入编号:1(开启hook) 2.(关闭hook) 3.退出" << endl; // 1.初始化得到本应用程序句柄 Init(); // 2.得到系统MessageBox入口代码 GetSysMsgBoxOEP(); // 3.得到自定义MessageBox入口代码 GetMySmgBoxOEP(); int n; while (cin >> n) { switch (n) { case 1: StartHook(); break; case 2: StopHook(); break; default: return 0; break; } cout << "请输入你期待的弹出框显示的内容" << endl; string sText; cin >> sText; LPCWSTR lpText = ANSIToUnicode(sText); MessageBox(0, lpText, _T("hook测试"), 0); cout << endl << "请输入编号:1(开启hook) 2.(关闭hook) 3.退出" << endl; } return 0; } void StartHook() { DWORD dOldProtect; DWORD dTmpprotect; // VirtualProtectEx函数可以改变在特定进程中内存区域的保护属性 /* BOOL VirtualProtectEx( HANDLE hProcess, // 要修改内存的进程句柄 LPVOID lpAddress, // 要修改内存的起始地址 DWORD dwSize, // 页区域大小 DWORD flNewProtect, // 新访问方式 PDWORD lpflOldProtect // 原访问方式 用于保存改变前的保护属性 易语言要传址 ); */ /* BOOL WriteProcessMemory( HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesWritten ); 参数: hProcess 由OpenProcess返回的进程句柄。 如参数传数据为 INVALID_HANDLE_VALUE 【即-1】目标进程为自身进程 lpBaseAddress 要写的内存首地址 再写入之前,此函数将先检查目标地址是否可用,并能容纳待写入的数据。 lpBuffer 指向要写的数据的指针。 nSize 要写入的字节数。 返回值 非零值代表成功。 */ VirtualProtectEx(hProcess, fpSysMsgBox, 5, PAGE_READWRITE, &dOldProtect); WriteProcessMemory(hProcess, fpSysMsgBox, byteMyMsgOEP, 5, NULL); VirtualProtectEx(hProcess, fpSysMsgBox, 5, dOldProtect, &dTmpprotect); } void StopHook() { DWORD dOldProtect; DWORD dTmpprotect; VirtualProtectEx(hProcess, fpSysMsgBox, 5, PAGE_READWRITE, &dOldProtect); WriteProcessMemory(hProcess, fpSysMsgBox, byteSysMsgOEP, 5, NULL); VirtualProtectEx(hProcess, fpSysMsgBox, 5, dOldProtect, &dTmpprotect); } void GetSysMsgBoxOEP() { // 获得基地址 HMODULE hBaseAddr = LoadLibrary(_T("user32.dll")); // 获得系统MsgBox的偏移地址 SysMsgBox = (MsgBox)GetProcAddress(hBaseAddr, ("MessageBoxW")); fpSysMsgBox = (FARPROC)SysMsgBox; if (fpSysMsgBox != NULL) { _asm { lea edi, byteSysMsgOEP // 获取保存系统msgbox的数组地址 mov esi, fpSysMsgBox // 得到系统msgbox函数地址 cld // 方向标记位,控制数据的流向 movsd // 复制从esi所指地址处的前dword4字节数据到edi所指地址中 movsb // 复制从esi所指地址处的第5个字节数据到edi所指地址中 } } } void GetMySmgBoxOEP() { // 使用jmp近跳,跳的是偏移地址 // 偏移量 = 自定义函数地址 - 系统函数地址 - jmp命令的5字节(jmp指令为1字节,地址为4字节) byteMyMsgOEP[0] = 0XE9; // jmp指令 _asm { lea eax, MyMsgBox // 得到自定义函数的地址 mov ebx, fpSysMsgBox // 得到系统msgbox函数地址 sub eax, ebx sub eax, 5 mov dword ptr[byteMyMsgOEP + 1], eax } }