Working Sample On Global System-Wide Keyboard Hook...

Started by
5 comments, last by Jan Wassenberg 17 years, 6 months ago
well, it's taken me alot of work to actually find out how simple this actually is, so here's what i currently have (im working on an application to protect my family members from online stalkers etc.) as you can see, it can actually be very helpful when writing applications intended for good and not evil, but anyway - here is the code #include <windows.h> char szClassName [] = "szClassName"; char szWindowName [] = "vertulion"; HWND hWndMain; LRESULT CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK KeyboardProc (int, WPARAM, LPARAM); /* a global system-wide keylogger; this program is able to pick up any keystrokes messages; that windows sends around the system; */ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wcex; wcex.cbClsExtra = 0; wcex.cbSize = sizeof (WNDCLASSEX); wcex.cbWndExtra = 0; wcex.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH); wcex.hCursor = LoadCursor (NULL, IDC_ARROW); wcex.hIcon = LoadIcon (NULL, IDI_APPLICATION); wcex.hIconSm = LoadIcon (NULL, IDI_APPLICATION); wcex.hInstance = hInstance; wcex.lpfnWndProc = MainWndProc; wcex.lpszClassName = szClassName; wcex.lpszMenuName = NULL; wcex.style = CS_HREDRAW | CS_VREDRAW; if (!RegisterClassEx (&wcex)) return 0; hWndMain = CreateWindowEx (NULL, szClassName, szWindowName, NULL, GetSystemMetrics (SM_CXSCREEN) / 2 - 320 / 2, GetSystemMetrics (SM_CYSCREEN) / 2 - 240 / 2, 320, 240, NULL, NULL, hInstance, NULL); if (hWndMain == NULL) return 0; //ShowWindow (hWndMain, nCmdShow); //UpdateWindow (hWndMain); MSG msg; while (GetMessage (&msg, NULL, 0, 0) > 0) { TranslateMessage (&msg); DispatchMessage (&msg); } return static_cast <int> (msg.wParam); } /* HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId); SetWindowsHookEx(WH_KEYBOARD_LL, (HHOKPROC)FilterFunc, GetModuleHandle(NULL), 0); */ HHOOK hKeyHook; LRESULT CALLBACK MainWndProc (HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) { switch (uMessage) { case WM_CREATE: { hKeyHook = SetWindowsHookEx (13 /*WH_KEYBOARD_LL*/, (HOOKPROC) KeyboardProc, GetModuleHandle (NULL), 0); } break; default: { return DefWindowProc (hWnd, uMessage, wParam, lParam); } break; } return 0; } LRESULT CALLBACK KeyboardProc (int nCode, WPARAM wParam, LPARAM lParam) { switch (nCode) { case HC_ACTION: { switch (wParam) { case WM_KEYDOWN: { MessageBeep (MB_ICONERROR); } break; } } break; } //return CallNextHookEx, this is important if we want the rest of windows to see the message; return CallNextHookEx (hKeyHook, nCode, wParam, lParam); }
Advertisement
Doesn't the hook procedure need to be in a DLL for it to be globally accessable?

Also, a little off topic, but the reason things like this tend not to be easy to find is that script kiddies can just copy and paste the code to create a keylogger. Anyone with a bit more ability should be able to create a keylogger themselfs anyway without needing to copy and paste code.
<ranting>How can hooking the keyboard can be used for good (well, I know some very valid use for this, but most of the stuff I read here on gamedev is something along the line of 'omg i want to maek a bot for WoW', which is kind of useless, unfair, and a possible breach of the license terms). Moreover, as Evil Steve said, code like this should be kept far from the hands of script kiddies. At least, it shouldn't contain any word that could relate it to key, log, and er.</ranting>

Why do you create the hook in the WM_CREATE handler? Can't you just create the hook and wait for the termination of the program (ie the user press a key)?

Regards,

what the hell... it's just a random code snippet for helping beginners... stop picking on me!

and no, this is naturally a global hook because it's low level...
Quote:Original post by diluted_water
what the hell... it's just a random code snippet for helping beginners... stop picking on me!

and no, this is naturally a global hook because it's low level...
We're not picking on you, we're just saying that there's reasons that there aren't hundreds of Google results for this sort of thing.

From The MSDN:
Quote:lpfn
[in] Pointer to the hook procedure. If the dwThreadId parameter is zero or specifies the identifier of a thread created by a different process, the lpfn parameter must point to a hook procedure in a DLL. Otherwise, lpfn can point to a hook procedure in the code associated with the current process.
I was under the impression that global hooks had to be in a DLL for some reason too (Anyone know where I thought this was from? Did it used to be this way?).

EDIT: Also, this is A Bad Thing: (HOOKPROC) KeyboardProc. You should never cast a function pointer unless you know exactly what you're doing (You want to cast some parameters or something). If it doesn't compile without the cast, then there's something wrong with the function prototype, and you're likely to screw up your stack. This isn't supposed to be me moaning, I'm just commenting on the code if it's going to be used for informational purposes [smile]
Quote:Original post by Evil Steve
Quote:lpfn
[in] Pointer to the hook procedure. If the dwThreadId parameter is zero or specifies the identifier of a thread created by a different process, the lpfn parameter must point to a hook procedure in a DLL. Otherwise, lpfn can point to a hook procedure in the code associated with the current process.
I was under the impression that global hooks had to be in a DLL for some reason too (Anyone know where I thought this was from? Did it used to be this way?).

I'm not sure if I quite understand the confusion. Global hooks do need to be in a DLL. Without venturing into the minefield that is RPC, processes may not call each others code, so the hook code must find its way into every process. So beware that when installing a global hook, the DLL containing the hook's code gets loaded into every process's address space. There are dozens of horrible side-effects of this, not least being the inconsistency of variable-scope and the absence of useful global variables.
That MSDN article speaks of non DLL-borne hooks. These are process-wide hooks. It makes sense that a process may hook its own message pump without having to resort to using a DLL. This is impossible for system-wide hooks, which is certainly a good thing.

By the way, I feel it's my responsibility to agree that global hooks are bad, whatever you intentions. You may feel you are doing good, but you'll inevitably make other developers' lives less cosy.

Regards
Admiral
Ring3 Circus - Diary of a programmer, journal of a hacker.
Quote:Global hooks do need to be in a DLL.

Possibly interesting reading.

Quote:the DLL containing the hook's code gets loaded into every process's address space. There are dozens of horrible side-effects of this, not least being the inconsistency of variable-scope and the absence of useful global variables.

huh? While there are certainly disadvantages to spewing a DLL into all processes, I cannot at all understand the ones you list.
E8 17 00 42 CE DC D2 DC E4 EA C4 40 CA DA C2 D8 CC 40 CA D0 E8 40E0 CA CA 96 5B B0 16 50 D7 D4 02 B2 02 86 E2 CD 21 58 48 79 F2 C3

This topic is closed to new replies.

Advertisement