How keyloggers works: a simple example of keyboard hooking using Python
Keyloggers are often used by malicious softwares to steal sensitive data and login credentials.
During a malware analysis process is useful to know how a keylogger works.
A keylogger can be implemented simply setting a hook on the keydown event that saves every key pressed by the user.
What is a “hook”?
A hook is a point in the system message-handling mechanism where an application can install a subroutine to monitor the message traffic in the system and process certain types of messages before they reach the target window procedure.
So, on windows systems it is possible to set a “hook” using the SetWindowsHookExA function provided by user32.dll.
This mechanism is functionally implemented as a hook procedure set to one hook type (mouse clicks, keyboard input) and manages these via a hook chain (a list of pointers to the hook procedure).
Here a simple example coded with python:
Some comments about this code
- Lines 6,7: Declare the variables for the user32 and kernel32 type using the windll.
When using a function that the DLL provides, it can be used as “user32.API name” or “kernel32.API name”.
- Lines 18-28: Hook setting function using the SetWindowsHookExA function that user32 DLL provides.
The hook procedure monitors the WH_KEYBOARD_LL events of all threads that are running on the operating system.
- Lines 30-34: Release the hook using the UnhookWindowsHookEx function that user32 DLL provides. Since hook results in a high load on the system, after the objective is achieved, it must always be released.
- Lines 36-38: To register the hook procedure, you must pass the pointer of that function. The ctypes provide the CFUNCTYPE function that allows you to find the function pointer.
- Lines 40-49: The hook procedure is the callback function that is responsible to process events at the user level. The Hook procedure prints the value of the incoming message that corresponds to the WM_KEYDOWN on the screen, and when the incoming message corresponds to the “CTRL” key, it removes the hook. When all of the processing has been completed, the Hook procedure passes control to the other hook procedure in the hook chain. (CallNextHookEx)
- Lines 51-53: The GetMessageA function monitors the queue, and if the queue message is coming in, the GetMessageA function sends a message to the first hook that is registered in the hook chain.
- Lines 55-60: Create a KeyLogger class, set the hook by calling the installHookProc function, at the same time register the hook procedure. Finally call the startKeyLog function in order to transmit the incoming messages into the queue to the hook chain.
This code can be cross-compiled on a linux box using this method: How to cross-compile a Python script into a Windows executable on Linux.
Here the keylogger in action on a Windows 7 VM:
But, an antivirus is able to identify this software?
Actually, the code is not really malicious. So, an antivirus solution can identify this tool only with the euristic engine, because the activity of keyboard hooking is often related to malicious softwares.
Here the output of virustotal: 6 engines (over a total of 67) identify the software as suspicious.