Windows消息钩取
作者:互联网
1.消息钩子
简单理解:在消息从OS移动到应用程序的时候,我们利用消息钩子在此期间偷看这些信息
钩链:多个相同的消息钩子,按照设置顺序依次调用这些钩子,组成的链条就被称为钩链
消息钩子实现的API:SetwindowsHookEx()
HHOOK SetWindowsHookEx(
int idHook, // hook type
HOOKpROC lpfn, // hook procedure
HINSTANCE hMod, //hook procedure所属的DLL句柄
DWORD dwThreadId //需要挂钩的线程ID,为0时表示为全局钩子(Global Hook)
);
hook proceduce是由操作系统调用的回调函数;安装消息钩子时,钩子过程需要存在于某个DLL内部,且该DLL的示例句柄即为hMod。
若其他进程(如图中所示)发生键盘输入事件,OS就会强制将KeyHook.dll加载到像一个进程的内存,然后调用KeyboardProc()函数。
2.键盘消息钩子实例HookMain.exe
KeyHook.dll中含有钩子API函数(KeyboardProc),通过HookMain.exe加载KeyHook.dll并使用(SetwindowsHookEx)安装键盘钩子(KeyboardProc)
LRESULT CALLBACK KeyboardProc(
int code, // hook code
WPARAM wParam, // virtual-key code
LPARAM lParam // keystroke-message information
);
运行 HookMain.exe,再运行Notepad,看到KeyHook.dll已经加载其中
3、源代码分析
1. HookMain.cpp
HookMain程序的主要源代码如下所示:
点击查看代码
#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;
char ch = 0;
// 加载KeyHook.dll
hDll = LoadLibraryA(DEF_DLL_NAME);
if( hDll == NULL )
{
printf("LoadLibrary(%s) failed!!! [%d]", DEF_DLL_NAME, GetLastError());
return;
}
// 获取导出函数地址
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(HINSTANCE 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 )
{
// bit 31 : 0 => press, 1 => 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
总体上代码相对简单,调用导出函数HookStart()时,SetWindowsHookEx()函数就会将KetyboardProc()添加到键盘钩链。
代码执行流程分析
安装好键盘钩子后,无论在哪个进程中,只要发生了键盘输入事件,OS就会强制将KeyHook.dll注入到进程中,加载了KeyHook.dll的进程,发生键盘事件时会首先调用执行KeyHook.KetyboardProc()。
KetyboardProc()函数中发生键盘输入事件时,会比较当前进程的名称与“notepad.exe”是否相同,相同返回1,终止KetyboardProc()函数,意味着截获并删除了消息,这样键盘消息就不会传递到notepad.exe程序的消息队列。
标签:NULL,DLL,Windows,钩子,dll,消息,钩取,DEF,KeyHook 来源: https://www.cnblogs.com/Azh3n/p/15986544.html