[toc]

设置全局Hook

用C语言写一个程序捕获键盘消息来判断A是否被按下

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
#include <windows.h>
#include <stdio.h>

HHOOK hKeyboardHook;

// 钩子过程
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
KBDLLHOOKSTRUCT* pKeyboard = (KBDLLHOOKSTRUCT*)lParam;
if (wParam == WM_KEYDOWN) {
if (pKeyboard->vkCode == 'A') { // 检查是否按下 "A" 键
printf("Key Pressed: A\n");
}
}
}
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}

int main() {
// 设置钩子
hKeyboardHook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardProc, NULL, 0);
if (hKeyboardHook == NULL) {
printf("Failed to set hook!\n");
return 1;
}

// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

// 卸载钩子
UnhookWindowsHookEx(hKeyboardHook);
return 0;
}

2.用C语言写一个程序捕获键盘消息来判断A-Z是否被按下,并且判断大小写

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
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <windows.h>
#include <stdio.h>

HHOOK hKeyboardHook;

// 钩子过程
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
KBDLLHOOKSTRUCT* pKeyboard = (KBDLLHOOKSTRUCT*)lParam;

// 只处理按下的键
if (wParam == WM_KEYDOWN) {
char keyChar = (char)pKeyboard->vkCode;

// 处理字母 A-Z
if (keyChar >= 'A' && keyChar <= 'Z') {
if (GetKeyState(VK_CAPITAL) & 0x0001) { // Caps Lock 开启
if (GetKeyState(VK_SHIFT) & 0x8000) { // Shift 键按下
printf("Key Pressed: %c (Lowercase via Shift with Caps Lock)\n", keyChar + 32); // 转换为小写
}
else {
printf("Key Pressed: %c (Uppercase via Caps Lock)\n", keyChar);
}
}
else {
if (GetKeyState(VK_SHIFT) & 0x8000) { // Shift 键按下
printf("Key Pressed: %c (Uppercase via Shift)\n", keyChar);
}
else {
printf("Key Pressed: %c (Lowercase)\n", keyChar + 32); // 转换为小写
}
}
}
}
}
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}

int main() {
// 设置钩子
hKeyboardHook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardProc, NULL, 0);
if (hKeyboardHook == NULL) {
printf("Failed to set hook!\n");
return 1;
}

// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

// 卸载钩子
UnhookWindowsHookEx(hKeyboardHook);
return 0;
}

3.用C语言写一个程序捕获鼠标消息来判断在屏幕上的坐标位置

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <windows.h>
#include <stdio.h>

HHOOK hMouseHook;
float scaleFactor; // 全局变量来存储缩放因子

// 获取缩放因子
float GetScaleFactor() {
HDC hdc = GetDC(NULL);
int dpiX = GetDeviceCaps(hdc, LOGPIXELSX);
ReleaseDC(NULL, hdc);
return dpiX / 96.0f; // 96 DPI 是 100% 缩放
}

// 获取实际屏幕分辨率
void GetScreenResolution(int* width, int* height) {
DEVMODE dm;
dm.dmSize = sizeof(dm);
if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm)) {
*width = dm.dmPelsWidth;
*height = dm.dmPelsHeight;
}
else {
*width = 0;
*height = 0;
}
}

// 鼠标钩子过程
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
MSLLHOOKSTRUCT* pMouse = (MSLLHOOKSTRUCT*)lParam;

// 只处理按下的键
if (wParam == WM_MOUSEMOVE) {
int x = pMouse->pt.x;
int y = pMouse->pt.y;

// 获取实际屏幕的宽度和高度
int screenWidth, screenHeight;
GetScreenResolution(&screenWidth, &screenHeight);

// 调整坐标
x = (int)(x / scaleFactor);
y = (int)(y / scaleFactor);

// 检查坐标是否在有效范围内
if (x < 0 || y < 0 || x >= screenWidth || y >= screenHeight) {
printf("Mouse Move: Invalid Position (X=%d, Y=%d)\n", x, y);
}
else {
printf("Mouse Move: X=%d, Y=%d\n", x, y);
}
}
// 其他鼠标事件处理...
}
return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}

int main() {
// 获取缩放因子
scaleFactor = GetScaleFactor();

// 设置鼠标钩子
hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, NULL, 0);
if (hMouseHook == NULL) {
printf("Failed to set mouse hook!\n");
return 1;
}

// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

// 卸载钩子
UnhookWindowsHookEx(hMouseHook);
return 0;
}

设置非全局Hook

1.只捕获本进程的消息(此程序无法捕获terminal中的消息),管理员权限启动的是console而非terminal可以正常运行

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
46
47
48
49
50
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>

HHOOK hKeyboardHook;
DWORD currentProcessId; // 本进程的 ID

// 键盘钩子过程
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
KBDLLHOOKSTRUCT* pKeyboard = (KBDLLHOOKSTRUCT*)lParam;

// 获取当前活动窗口的进程 ID
DWORD foregroundProcessId;
HWND hwnd = GetForegroundWindow();
GetWindowThreadProcessId(hwnd, &foregroundProcessId);

// 检查是否是本进程
if (foregroundProcessId == currentProcessId) {
if (wParam == WM_KEYDOWN && pKeyboard->vkCode == 'A') {
printf("'A' key pressed in this program!\n");
}
}
}
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}

int main() {
// 获取本进程的 ID
currentProcessId = GetCurrentProcessId();

// 设置键盘钩子
hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, NULL, 0);
if (hKeyboardHook == NULL) {
printf("Failed to set keyboard hook!\n");
return 1;
}

// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

// 卸载钩子
UnhookWindowsHookEx(hKeyboardHook);
return 0;
}

2. 根据进程pid来过滤Hook消息,只捕获Notepad.exe的消息

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>

HHOOK hKeyboardHook;
DWORD targetProcessId; // 目标进程的 ID

// 获取目标进程的 ID
void GetTargetProcessId(const wchar_t* processName)
{
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32W process = { 0 };
process.dwSize = sizeof(process);

if (Process32FirstW(snapshot, &process)) {
do {
if (!wcscmp((const wchar_t*)process.szExeFile, (const wchar_t*)processName))
break;
} while (Process32NextW(snapshot, &process));
}

CloseHandle(snapshot);
targetProcessId = process.th32ProcessID;
return;
}

// 键盘钩子过程
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION) {
KBDLLHOOKSTRUCT* pKeyboard = (KBDLLHOOKSTRUCT*)lParam;

// 获取当前活动窗口的进程 ID
DWORD foregroundProcessId;
HWND hwnd = GetForegroundWindow();
GetWindowThreadProcessId(hwnd, &foregroundProcessId);
// 检查是否是目标进程
if (foregroundProcessId == targetProcessId) {
if (wParam == WM_KEYDOWN && pKeyboard->vkCode == 'A') {
printf("'A' key pressed in target process!\n");
}
}
}
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}

int main() {
// 设置目标进程名称
const wchar_t* targetProcessName = L"Notepad.exe"; // 替换为目标进程的名称
GetTargetProcessId(targetProcessName);

// 设置键盘钩子
hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, NULL, 0);
if (hKeyboardHook == NULL) {
printf("Failed to set keyboard hook!\n");
return 1;
}

// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

// 卸载钩子
UnhookWindowsHookEx(hKeyboardHook);
return 0;
}

3. C语言写一个线程钩子,用来捕获窗口消息

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <windows.h>
#include <stdio.h>

// 窗口过程
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_KEYDOWN:
if (wParam == 'A') {
printf("'A' key pressed in this program!\n");
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}

// 线程钩子过程
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
// 处理消息
KBDLLHOOKSTRUCT* pKeyboard = (KBDLLHOOKSTRUCT*)lParam;
if (wParam == WM_KEYDOWN && pKeyboard->vkCode == 'A') {
printf("Hook: 'A' key pressed!\n");
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}

// 线程函数
DWORD WINAPI ThreadFunc(LPVOID lpParam) {
// 设置线程钩子
HHOOK hHook = SetWindowsHookEx(WH_KEYBOARD, HookProc, NULL, GetCurrentThreadId());
if (hHook == NULL) {
printf("Failed to set hook!\n");
return 1;
}

// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

// 卸载钩子
UnhookWindowsHookEx(hHook);
return 0;
}

int main() {
// 注册窗口类
const char CLASS_NAME[] = "SampleWindowClass";

WNDCLASS wc = { 0 };
wc.lpfnWndProc = WindowProc;
wc.hInstance = GetModuleHandle(NULL);
wc.lpszClassName = CLASS_NAME;

RegisterClass(&wc);

// 创建窗口
HWND hwnd = CreateWindowEx(
0, CLASS_NAME, "Thread Hook Example",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 300, 200,
NULL, NULL, wc.hInstance, NULL
);

if (hwnd == NULL) {
return 0;
}

ShowWindow(hwnd, SW_SHOW);

// 创建线程来设置钩子
HANDLE hThread = CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL);
if (hThread == NULL) {
printf("Failed to create thread!\n");
return 1;
}

// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

// 等待线程结束
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
return 0;
}