这是刚开始学习HOOK的第二个方法,第一个是Windows自带的一个函数,SetWindowsHookEx,好像是这个。但是程序很容易被干死。后来又翻各大论坛,发现了一个JMP函数入口。反正是没研究透,但是会用。不过据说不太稳定。不知道是不是代码写的有问题还是怎样,后来又看了下Windows提供的detour吧,居然收费。后来又发现了mhook,这个比较稳定 。粗略看了下代码,其实也是JMP的模式,只是封装的比较好用。题外话就不多说了,主要自己动手实现HOOK代码。
#define UM_WNDTITLE WM_USER+100 //自定义消息 //全局共享变量 #pragma data_seg(".Share") HWND g_hWnd=NULL;//主窗口句柄; HHOOK hhk=NULL; //鼠标钩子句柄; HINSTANCE hInst=NULL;//本dll实例句柄; #pragma data_seg() #pragma comment(linker, "/section:.Share,rws") HANDLE hProcess=NULL; BOOL bIsInjected=FALSE; //原函数定义 typedef int (WINAPI *MsgBoxA)(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType); typedef int (WINAPI *MsgBoxW)(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType); MsgBoxA oldMsgBoxA=NULL; //用于保存原函数地址 MsgBoxW oldMsgBoxW=NULL; //用于保存原函数地址 FARPROC pfMsgBoxA=NULL;//指向原函数地址的远指针 FARPROC pfMsgBoxW=NULL;//指向原函数地址的远指针 BYTE OldCodeA[5]; //老的系统API入口代码 BYTE NewCodeA[5]; //要跳转的API代码 (jmp xxxx) BYTE OldCodeW[5]; //老的系统API入口代码 BYTE NewCodeW[5]; //要跳转的API代码 (jmp xxxx) int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType); int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType); //开启钩子的函数 void HookOn() { ASSERT(hProcess!=NULL); DWORD dwTemp=0,dwOldProtect,dwRet=0,dwWrite; //修改原API入口前五个字节为jmp xxxxxxxx //Debug版本在我这里修改失败,运行Release版本成功 VirtualProtectEx(hProcess,pfMsgBoxA,5,PAGE_READWRITE,&dwOldProtect); dwRet=WriteProcessMemory(hProcess,pfMsgBoxA,NewCodeA,5,&dwWrite); if (0==dwRet||0==dwWrite) { TRACE("啊,写入失败"); } VirtualProtectEx(hProcess,pfMsgBoxA,5,dwOldProtect,&dwTemp); //修改原API入口前五个字节为jmp xxxxxxxx //Debug版本在我这里修改失败,运行Release版本成功 VirtualProtectEx(hProcess,pfMsgBoxW,5,PAGE_READWRITE,&dwOldProtect); dwRet=WriteProcessMemory(hProcess,pfMsgBoxW,NewCodeW,5,&dwWrite); if (0==dwRet||0==dwWrite) { TRACE("啊,写入失败"); } VirtualProtectEx(hProcess,pfMsgBoxW,5,dwOldProtect,&dwTemp); } //关闭钩子的函数 void HookOff()//将所属进程中add()的入口代码恢复 { ASSERT(hProcess!=NULL); DWORD dwTemp=0,dwOldProtect=0,dwRet=0,dwWrite=0; //恢复原API入口 VirtualProtectEx(hProcess,pfMsgBoxA,5,PAGE_READWRITE,&dwOldProtect); dwRet=WriteProcessMemory(hProcess,pfMsgBoxA,OldCodeA,5,&dwWrite); if (0==dwRet||0==dwWrite) { TRACE("啊,写入失败"); } VirtualProtectEx(hProcess,pfMsgBoxA,5,dwOldProtect,&dwTemp); //恢复原API入口 VirtualProtectEx(hProcess,pfMsgBoxW,5,PAGE_READWRITE,&dwOldProtect); WriteProcessMemory(hProcess,pfMsgBoxW,OldCodeW,5,&dwWrite); if (0==dwRet||0==dwWrite) { TRACE("啊,写入失败"); } VirtualProtectEx(hProcess,pfMsgBoxW,5,dwOldProtect,&dwTemp); } void Inject() { if (!bIsInjected) { bIsInjected=TRUE;//保证只调用1次 //获取函数 HMODULE hmod=::LoadLibrary(_T("User32.dll")); oldMsgBoxA=(MsgBoxA)::GetProcAddress(hmod,"MessageBoxA"); pfMsgBoxA=(FARPROC)oldMsgBoxA; oldMsgBoxW=(MsgBoxW)::GetProcAddress(hmod,"MessageBoxW"); pfMsgBoxW=(FARPROC)oldMsgBoxW; 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; } // 将原API中的入口代码保存入OldCodeA[],OldCodeW[] _asm { lea edi,OldCodeA mov esi,pfMsgBoxA cld movsd movsb } _asm { lea edi,OldCodeW mov esi,pfMsgBoxW cld movsd movsb } NewCodeA[0]=0xe9;//实际上0xe9就相当于jmp指令 NewCodeW[0]=0xe9;//实际上0xe9就相当于jmp指令 //获取我们的API的地址 _asm { lea eax,MyMessageBoxA mov ebx,pfMsgBoxA sub eax,ebx sub eax,5 mov dword ptr [NewCodeA+1],eax } _asm { lea eax,MyMessageBoxW mov ebx,pfMsgBoxW sub eax,ebx sub eax,5 mov dword ptr [NewCodeW+1],eax } //填充完毕,现在NewCode[]里的指令相当于Jmp Myadd HookOn(); //可以开启钩子了 } } //我们的假API函数MyMessageBoxA int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType) { int nRet=0; HookOff();//调用原函数之前,记得先恢复HOOK呀,不然是调用不到的 //如果不恢复HOOK,就调用原函数,会造成死循环 //毕竟调用的还是我们的函数,从而造成堆栈溢出,程序崩溃。 nRet=::MessageBoxA(hWnd,"哈哈,MessageBoxA被HOOK了吧",lpCaption,uType); nRet=::MessageBoxA(hWnd,lpText,lpCaption,uType); HookOn();//调用完原函数后,记得继续开启HOOK,不然下次会HOOK不到哦。 return nRet; } //我们的假API函数MyMessageBoxW int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType) { int nRet=0; HookOff();//调用原函数之前,记得先恢复HOOK呀,不然是调用不到的 //如果不恢复HOOK,就调用原函数,会造成死循环 //毕竟调用的还是我们的函数,从而造成堆栈溢出,程序崩溃。 nRet=::MessageBoxW(hWnd,_T("哈哈,MessageBoxW被HOOK了吧"),lpCaption,uType); nRet=::MessageBoxW(hWnd,lpText,lpCaption,uType); HookOn();//调用完原函数后,记得继续开启HOOK,不然下次会HOOK不到哦。 return nRet; } // CHookMessageBoxApp BEGIN_MESSAGE_MAP(CHookMessageBoxApp, CWinApp) END_MESSAGE_MAP() // CHookMessageBoxApp 构造 CHookMessageBoxApp::CHookMessageBoxApp() { } // 唯一的一个 CHookMessageBoxApp 对象 CHookMessageBoxApp theApp; //dll程序入口,当程序加载dll时,会执行InitInstance() BOOL CHookMessageBoxApp::InitInstance() { CWinApp::InitInstance(); hInst=AfxGetInstanceHandle(); DWORD dwPid=::GetCurrentProcessId(); hProcess=::OpenProcess(PROCESS_ALL_ACCESS,0,dwPid); Inject();//开始注入,即HOOK return TRUE; } //鼠标钩子过程,目的是加载本dll到使用鼠标的程序 //鼠标钩子的作用:当鼠标在某程序窗口中时,其就会加载我们这个dll LRESULT CALLBACK MouseProc( int nCode, // hook code WPARAM wParam, // message identifier LPARAM lParam // mouse coordinates ) { if (nCode==HC_ACTION) { //将钩子所在窗口句柄发给主程序 ::SendMessage(g_hWnd,UM_WNDTITLE,wParam,(LPARAM)(((PMOUSEHOOKSTRUCT)lParam)->hwnd)); } return CallNextHookEx(hhk,nCode,wParam,lParam); } //安装钩子 BOOL WINAPI StartHook(HWND hWnd) { g_hWnd=hWnd; hhk=::SetWindowsHookEx(WH_MOUSE,MouseProc,hInst,0); if (hhk==NULL) { return FALSE; } else { return TRUE; } } //卸载钩子 VOID WINAPI StopHook() { HookOff();//记得恢复原API入口哈 //主程序调用该函数时,恢复的只是主程序原API的入口, //其它程序的API入口还没有被恢复,所以我们必须处理 //dll退出过程,即在函数ExitInstance()中,调用恢复 //API入口的函数HookOff(),只有这样,其它程序再次调用 //原API时,才不会发生错误喔。 //当我们HOOK所有程序的某个系统API时,千万要注意在 //ExitInstance()中调用HookOff(),血的教训哈。 if (hhk!=NULL) { UnhookWindowsHookEx(hhk); FreeLibrary(hInst); } } //dll退出时 int CHookMessageBoxApp::ExitInstance() { HookOff();//dll退出时,记得恢复原API入口哈,血的教训呀。 //当我们钩所有程序的API,且dll退出没有恢复原API入口时, //那么当被钩程序再次调用该API时,会发生错误,因为我们的 //dll程序已经退出了,原来API入口被修改的前五个字节还是 //指向我们dll中的自己定义的函数地址,现在dll退出,该地址 //自然也就不存在了,程序调用该地址时,自然会发生崩溃了。 return CWinApp::ExitInstance(); }原来有代码实现的,非汇编(其实原理是一样的,只是实现语言不同)
收藏的用户(0) X
正在加载信息~
推荐阅读
最新回复 (0)
站点信息
- 文章2302
- 用户1336
- 访客10962994
每日一句
Progress starts with one brave step forward.
进步始于一次勇敢的迈步。
进步始于一次勇敢的迈步。
新会员