Windows消息钩取
消息钩子
消息钩子:钩取OS发送给应用程序的消息。
以键盘消息为例,常规的Windows消息流:
- 发生键盘输入事件时,WM_KEYDOWN消息将被添加到[OS message queue]
- OS判断发生事件的应用程序,从[OS message queue]取出消息,添加到相应应用程序的[application message queue]中
- 应用程序监听自己的[application message queue],发现新添加的WM_KEYDOWN消息后,处理该消息
SetWindowsHookEx()
使用SetWindowsHookEx() API可以很容易地实现消息钩子:
HHOOK SetWindowsHookEx(
int idHook, //hook type
HOOKPROC lpfn, //hook procedure
HINSTANCE hMod, //hook procedure所属的DLL句柄
DWORD dwThreadId //想要挂钩的线程ID,0则为全局钩子
);
安装消息“钩子”时,“钩子”过程需要存在于某个DLL内部。
示例代码
HookMain.exe的源文件:
#include "stdio.h"
#include "conio.h"
#include "windows.h"
#define DEF_DLL_NAME "KeyHook.dll"
#define DEF_HOOKSTART "HookStart"
#define DEF_HOOKSTOP "HookStop"
typedef void(*PFN_HOOKSTART)();
typedef void(*PFN_HOOKSTOP)();
void main(){
HMODULE hDll=NULL;
PFN_HOOKSTART HookStart=NULL;
PFN_HOOKSTOP HookStop=NULL;
//加载KeyHook.dll
hDll=LoadLibraryA(DEF_DLL_NAME);
//获取导出函数地址
HookStart=(PFN_HOOKSTART)GetProcAddress(hDll,DEF_HOOKSTART);
HookStop=(PFN_HOOKSTOP)GetProcAddress(hDll,DEF_HOOKSTOP);
//开始钩取
HookStart();
//等待用户输入“q”
printf("press 'q' to quit!\n");
while(_getch()!='q');
//终止钩取
HookStop();
//卸载KeyHook.dll
FreeLibrary(hDll);
}
KeyHook.dll的源码:
#include "stdio.h"
#include "windows.h"
#define DEF_PROCESS_NAME "notepad.exe"
HINSTANCE g_hInstance=NULL;
HHOOK g_hHook=NULL;
HWND g_hWnd=NULL;
BOOL WINAPI DLLMain(HINATANCE hinstDll, DWORD dwReason, LPVOID lpvReserved){
switch(dwReason){
case DLL_PROCESS_ATTACH:
g_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(nCode=0){
//0=key press, 1=key release
if(!(lParam & 0x80000000)){ //释放键盘按钮时
GetModuleFileNameA(NULL, szPath, MAX_PATH);
p=strrchr(szPath,'\\');
//比较当前进程名,若为notepad.exe则消息不会传递给应用程序
if(!_stricmp(p+1, DEF_PROCESS_NAME))
return 1;
}
}
//若非notepad.exe,则调用CallNextHookEx()函数,将消息传给应用程序
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
#ifdef __cplusplus
extern "C" {
#endif
__ declspec(dllexport) void HookStart(){
g_hHook=SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0);
}
__declspec(dllexport) void HookStop(){
if(g_hHook){
UnhookWindowsHookEx(g_hHook);
g_hHook=NULL;
}
}
#ifdef __cplusplus
}
#endif
参考文献
《逆向工程核心原理》