0%

应用层使用键盘钩子过滤按键(1)

应用层低级键盘钩子

在应用层可以使用 SetWindowsHookEx 挂载 低级键盘钩子 ,来实现屏蔽键盘按键的功能

1
2
3
4
5
6
HHOOK WINAPI SetWindowsHookEx(
_In_ int idHook,
_In_ HOOKPROC lpfn,
_In_ HINSTANCE hMod,
_In_ DWORD dwThreadId
);

其中参数 idhook 设置为 WH_KEYBOARD_LL 时,表明挂载 低级键盘钩子 ,参数 dwThreadId 为想要HOOK
的线程ID,设置为0时,表示HOOK所有的线程。低级键盘钩子 的回调函数为

1
2
3
4
5
LRESULT CALLBACK LowLevelKeyboardProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);

参数 nCode 的值为 HC_ACTION 时表示 wParamlParam 有效,参数 wParam 为键盘相关消息,出现
的值为 WM_KEYDOWN WM_KEYUP WM_SYSKEYDOWN WM_SYSKEYUP 几种,表明按键的行为,参数 lParam
具体按键信息,是一个 KBDLLHOOKSTRUCT 类型的结构体

1
2
3
4
5
6
7
typedef struct tagKBDLLHOOKSTRUCT {
DWORD vkCode;
DWORD scanCode;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
} KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT, *LPKBDLLHOOKSTRUCT;

参数 vkCode 表示虚拟按键码信息,可以在头文件 WinUser.h 中找到定义,这里就不再列出。

注册和卸载低级键盘钩子

当HOOK所有线程时,实际是作为DLL模块注入到所有的程序中,来进行的HOOK操作。
一般情况下,32位的DLL注入到32位程序中,64位的DLL注入到64位程序中,不能互相注入。
使用 低级键盘钩子 时,只需要写32位DLL,而64位的程序,系统通过消息处理,间接实现按键过滤。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// DLL中的共享数据块,在所有程序中公用同一段数据
#pragma data_seg(".shared")
HHOOK g_hHook = NULL; // 进行HOOK后的句柄
BOOL g_bEnable = FALSE; // 是否启用过滤功能
#pragma data_seg()
#pragma comment(linker, "/section:.shared,rws")
// 低级键盘钩子回调函数
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if ((g_bEnable) && (nCode == HC_ACTION))
{
switch (wParam)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
{
PKBDLLHOOKSTRUCT pKbd = (PKBDLLHOOKSTRUCT)lParam;
BOOL bAltPress = (pKbd->flags & LLKHF_ALTDOWN) != 0;
BOOL bCtrlPress = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
if (bAltPress && (pKbd->vkCode == VK_F4)) return TRUE; // ALT+F4
if (bAltPress && (pKbd->vkCode == VK_TAB)) return TRUE; // ALT+TAB
if (bAltPress && (pKbd->vkCode == VK_ESCAPE)) return TRUE; // ALT+ESC
if (bCtrlPress && (pKbd->vkCode == VK_ESCAPE)) return TRUE; // CTRL+ESC
if (bCtrlPress && bAltPress && (pKbd->vkCode == VK_DELETE)) return TRUE; // CTRL+ALT+DEL
}
break;
}
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
// 注册低级键盘钩子
BOOL SetKeyboardHookDll()
{
g_hHook = SetWindowsHookEx(WH_KEYBOARD_LL,
LowLevelKeyboardProc, (HINSTANCE)GetModuleHandle("KbdHook.dll"), 0);
if (g_hHook == NULL) return FALSE;
return TRUE;
}
// 卸载低级键盘钩子
BOOL UnKeyboardHookDll()
{
return UnhookWindowsHookEx(g_hHook);
}

需要注意的是,调用DLL并执行HOOK的程序,在HOOK以后不能退出,否则导致HOOK的DLL被卸载。
或者也可以把HOOK的相关函数直接写到EXE程序中,把EXE自身作为DLL模块注入到所有线程中。