低头不是认输,是要看清自己的路。仰头不是骄傲,是看见自己的天空。——致自己
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;
//加载dll
hDll = LoadLibraryA(DLL_NAME);
//获取导出函数的地址
HookStart = (PFN_HOOKSTART)GetProcAddress(hDll,HOOK_START);
HookStop = (PFN_HOOKSTOP)GetProcAddress(hDll,HOOK_STOP);
//开始hook
HookStart();
//输入Q退出hook
printf("输入Q退出hook!\n");
while(1)
{
char h = getch();
putch(h);
if( h == 'Q')
break;
}
//结束hook
HookStop();
//卸载dll
FreeLibrary(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了),其他地方则可以正常显示。