低头不是认输,是要看清自己的路。仰头不是骄傲,是看见自己的天空。——致自己
Hook,是Windows消息处理机制的一个平台,应用程序可以在上面设置子程序以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。简单来说,如下图所示(个人理解,如有错误请留言):
现在开始简单的编写一个程序,简单的实现下hook,以notepad.exe为例(因为它比较简单,hook它不用考虑权限其他啥的),对其进行hook,拦截其键盘消息。首先编写一个安装钩子的程序。
#include<stdio.h>
#include<conio.h>
#include<windows.h>#define DLL_NAME "HookKeyBoard.dll"
#define HOOK_START "HookStart"
#define HOOK_STOP "HookStop"typedef void(*PFN_HOOKSTART)();
typedef void(*PFN_HOOKSTOP)();int main()
{HMODULE hDll =NULL;PFN_HOOKSTART HookStart = NULL;PFN_HOOKSTOP HookStop = NULL;char ch = 0;//加载dllhDll = LoadLibraryA(DLL_NAME);//获取导出函数的地址HookStart = (PFN_HOOKSTART)GetProcAddress(hDll,HOOK_START);HookStop = (PFN_HOOKSTOP)GetProcAddress(hDll,HOOK_STOP);//开始hookHookStart();//输入Q退出hookprintf("输入Q退出hook!\n");while(1){char h = getch();putch(h);if( h == 'Q')break;}//结束hookHookStop();//卸载dllFreeLibrary(hDll);return 0;
}
可以看到,我加载了一个HookKeyBoard.dll,并使用了它的两个导出函数HookStart和HookStop,一个用来hook,一个用来Unhook,下面开始写HookKeyBoard.dll(注意写的是dll)。
#include<stdio.h>
#include<windows.h>#define HOOK_PROCESS_NAME "notepad.exe"HINSTANCE hInstance = NULL;
HHOOK hHook = NULL;
HWND hWnd = NULL;BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD dwReason, LPVOID IpvReserved)
{switch( dwReason ){case DLL_PROCESS_ATTACH: hInstance = hinstDLL;break;case DLL_PROCESS_DETACH: break;}return TRUE;
}LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)
{char szPath[MAX_PATH]={0,};CHAR *p = NULL;if(!(lParam & 0x80000000))//释放按键时{GetModuleFileNameA(NULL,szPath,MAX_PATH);p = strrchr(szPath,'\\');//比较进程名称if(!_stricmp(p+1,HOOK_PROCESS_NAME)){//MessageBox(NULL,TEXT("hook成功"),TEXT("MY"),MB_OK);return 1;}}//不是hook的程序,则传递到出去return CallNextHookEx(hHook,nCode,wParam,lParam);
}
extern "C" __declspec(dllexport) void HookStart()
{hHook = SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,hInstance,0);//MessageBox(NULL,TEXT("hook成功"),TEXT("MY"),MB_OK);
}extern "C" __declspec(dllexport) void HookStop()
{if(hHook){UnhookWindowsHookEx(hHook);hHook = NULL;}
}
消息钩子注入原理是利用Windows 系统中SetWindowsHookEx()这个API,他可以拦截目标进程的消息到指定的DLL中导出的函数,利用这个特性,我们可以将DLL注入到指定进程中。(msdn没搜到这个函数,msdn只列出了A版和W版的函数,他们的区别就是A字符串用ascii编码,W 宽字符,字符串用Unicode编码,所以区别不大)。
看下参数
可以看到,我挂钩KeyboardProc这个系统函数。
程序写完了,代码比较简单,有点编程基础的应该都能看懂,现在开始进行测试。测试之前,先将HookKeyBoard.dll拷贝到工程生成hook.exe的目录下,否则它找不到DLL,就会出现下面的情况。详细原因请参考之前我写的这篇博客DLL搜索的目录顺序。
然后测试,第一步先打开notepad.exe,然后点击hook.exe
然后打开Process Explorer进程监视器,查看加载的DLL,然后尝试在notepad.exe里面输入东西,可以看到HookKeyBoard.dll被notepad.exe加载了,并且在notepad.exe输入任何东西都不能显示出来(被hook了),其他地方则可以正常显示。