Açık Kaynak Antivirüsle Gerçek Zamanlı Koruma Yapımı

Şu an yanlış pozitif çok verse de tespit oranı ClamAV’a kıyasla çok iyi fakat aşırı fazla karışık tespit mekanizması var. Tek takıldığım nokta gerçek zamanlı koruma yapımı. Açık kaynak olacak. Gerçek zamanlı koruma kodunu göstermeden önce neden python seçtiğimi anlatayım. Python’da API desteği çok iyi. Yavaş gözükse de optimize edince sorun kalmıyor. Kodlaması ve anlaşılması gayet kolay. Neyse meselemize dönelim. Ben kodu paylaşayım: `import os
import win32file
import win32con
import win32gui
import win32api
import win32process
from parseJson import ParseJson
import pygetwindow as gw
import pynput.mouse
import threading
from queue import Queue

FILE_ACTION_ADDED = 0x00000001
FILE_ACTION_REMOVED = 0x00000002
FILE_ACTION_MODIFIED = 0x00000003

def systemWatcher(XylentScanner, SYSTEM_DRIVE, thread_resume):
XYLENT_SCAN_CACHE = ParseJson(‘./config’, ‘xylent_scancache’, {})
XYLENT_CACHE_MAXSIZE = 500000 # 500KB
file_queue = Queue()

def on_mouse_click(x, y, button, pressed):
    if pressed:
        path_to_scan = get_file_path_from_click(x, y)
        print(f"Mouse clicked at ({x}, {y}) on file: {path_to_scan}")

        # Add file to the queue for processing in the main thread
        file_queue.put(path_to_scan)

def get_file_path_from_click(x, y):
    hwnd = win32gui.WindowFromPoint((x, y))
    pid = win32process.GetWindowThreadProcessId(hwnd)[1]
    handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | win32con.PROCESS_VM_READ, False, pid)
    return win32process.GetModuleFileNameEx(handle, 0)

def process_file_queue():
    while thread_resume.is_set():
        try:
            path_to_scan = file_queue.get(timeout=1)  # Timeout to avoid blocking indefinitely
            print(f"Processing file: {path_to_scan}")

            try:
                if os.path.isfile(path_to_scan):
                    verdict = XylentScanner.scanFile(path_to_scan)
                    XYLENT_SCAN_CACHE.setVal(path_to_scan, verdict)
            except Exception as e:
                print(e)
                print(f"Error scanning {path_to_scan}")

        except Queue.Empty:
            pass  # Queue is empty, continue checking

        if os.path.getsize(XYLENT_SCAN_CACHE.PATH) >= XYLENT_CACHE_MAXSIZE:
            XYLENT_SCAN_CACHE.purge()
            print("Purging")

def file_monitor():
    while thread_resume.is_set():
        # File monitoring
        path_to_watch = SYSTEM_DRIVE + "\\"
        hDir = win32file.CreateFile(
            path_to_watch,
            1,
            win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE | win32con.FILE_SHARE_DELETE,
            None,
            win32con.OPEN_EXISTING,
            win32con.FILE_FLAG_BACKUP_SEMANTICS,
            None
        )

        results = win32file.ReadDirectoryChangesW(
            hDir,
            1024,
            True,
            win32con.FILE_NOTIFY_CHANGE_FILE_NAME |
            win32con.FILE_NOTIFY_CHANGE_DIR_NAME |
            win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES |
            win32con.FILE_NOTIFY_CHANGE_SIZE |
            win32con.FILE_NOTIFY_CHANGE_LAST_WRITE |
            win32con.FILE_NOTIFY_CHANGE_SECURITY |
            FILE_ACTION_ADDED |
            FILE_ACTION_MODIFIED |
            FILE_ACTION_REMOVED,
            None,
            None
        )

        for action, file in results:
            path_to_scan = os.path.join(path_to_watch, file)
            print(path_to_scan)  # Print the path for debugging purposes

            # Add file to the queue for processing in the main thread
            file_queue.put(path_to_scan)

        if os.path.getsize(XYLENT_SCAN_CACHE.PATH) >= XYLENT_CACHE_MAXSIZE:
            XYLENT_SCAN_CACHE.purge()
            print("Purging")

mouse_listener = threading.Thread(target=lambda: pynput.mouse.Listener(on_click=on_mouse_click).start())
mouse_listener.start()

monitor_thread = threading.Thread(target=file_monitor)
monitor_thread.start()

process_queue_thread = threading.Thread(target=process_file_queue)
process_queue_thread.start()

mouse_listener.join()  # Wait for mouse listener to finish (shouldn't happen in this case)
monitor_thread.join()  # Wait for file monitor to finish
process_queue_thread.join()  # Wait for file processing thread to finish

print("RTP waiting to start...")`Şimdi ben buna explorer.exe yani Windows Gezgininde olan mevcut bulunduğum klasörü tespit edip tarayacak veya tıkladığım dosyaları tarayacak. Bunu yapmaya çalıştım ama daha yeni geliştirdiğim için bitmedi. Başka dil kullanın diyorlar ama ben şunu fark ettim python'da gayet mümkünmüş. En kötü watchdog kullanırım gerçek zamanlı koruma için. Birde ClamAV dokümasyonuna girdim fakat şu an onu geliştirmiyorum. Şu an Xylent'i gelişitiriyorum. Bu konuyu açmamın sebebi bana yardım edecek birisini arıyorum.

Hallettim o kodu ama entegrasyon lazım. `import os
import psutil
import time
import json
from notifypy import Notify
import win32evtlog
import concurrent.futures

CONFIG_FOLDER = “config”
NEW_PROCESSES_FILE = os.path.join(CONFIG_FOLDER, “new_processes.json”)

Ensure the config folder exists

if not os.path.exists(CONFIG_FOLDER):
os.makedirs(CONFIG_FOLDER)

def load_new_processes():
try:
with open(NEW_PROCESSES_FILE, “r”) as file:
return json.load(file)
except (FileNotFoundError, json.JSONDecodeError):
return

def save_new_processes(new_processes):
with open(NEW_PROCESSES_FILE, “w”) as file:
json.dump(new_processes, file)

def get_running_processes():
processes = set()
for p in psutil.process_iter([‘name’, ‘exe’, ‘cmdline’, ‘pid’, ‘ppid’]):
try:
if p.info is not None and ‘name’ in p.info and ‘exe’ in p.info:
name = p.info[‘name’]
exe = p.info[‘exe’]
cmdline = tuple(p.info.get(‘cmdline’, ))
pid = p.pid
ppid = p.ppid()
processes.add((name, exe, cmdline, pid, ppid))
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass # Skip processes that are inaccessible or no longer exist
except Exception as e:
print(f"Error getting process info: {e}")
return processes

def get_parent_process_info(pid):
try:
parent_pid = psutil.Process(pid).ppid()
parent_process = psutil.Process(parent_pid)
return {
‘name’: parent_process.name(),
‘exe’: parent_process.exe(),
‘cmdline’: parent_process.cmdline(),
‘pid’: parent_process.pid,
}
except (psutil.NoSuchProcess, psutil.AccessDenied) as e:
pass
except Exception as e:
print(f"An unexpected error occurred while getting parent process info: {e}")
return None

def get_user_from_event_log(process_name):
try:
# Open the Security event log
handle = win32evtlog.OpenEventLog(None, “Security”)

    # Set the starting record to the end of the log
    flags = win32evtlog.EVENTLOG_BACKWARDS_READ | win32evtlog.EVENTLOG_SEQUENTIAL_READ
    total_records = win32evtlog.GetNumberOfEventLogRecords(handle)
    starting_record = total_records

    while True:
        # Read a batch of records
        events = win32evtlog.ReadEventLog(handle, flags, starting_record)

        if not events:
            break

        for event in events:
            # Check if the event is a process creation event (Event ID 4688)
            if event.EventID == 4688:
                data = event.StringInserts

                # Check if the process name matches the target process
                if process_name.lower() in data[5].lower():
                    return "Unknown"

        # Update the starting record for the next batch
        starting_record -= len(events)

    # Close the event log handle
    win32evtlog.CloseEventLog(handle)
except Exception as e:
    print(f"Error retrieving username from event log: {e}")
    return "Unknown"

def send_notification(title, message):
notification = Notify()
notification.title = title
notification.message = message
notification.send()

def process_checker(process_info, printed_processes):
name, exe, cmdline, pid, parent_pid = process_info

if exe not in printed_processes:
    # Print the running file only once
    print(f"Running File: {exe}")
    printed_processes.add(exe)

parent_process_info = get_parent_process_info(pid)
if parent_process_info is None or parent_process_info.get('exe') is None:
    return  # Skip processing if parent process info is None or has no executable information

parent_path = parent_process_info['exe']

# Check if parent and child have the same location
if parent_path != "Unknown" and exe.startswith(parent_path):
    return  # Skip processing if they have the same location

# Check if parent and child have the same full path
if os.path.abspath(exe) == os.path.abspath(parent_path):
    return  # Skip processing if they have the same full path

# Retrieve the username from Windows logs
user = get_user_from_event_log(exe)

message = f"Path: {exe}, Parent Process Path: {parent_path}, Command Line: {cmdline}"

# Print to the console
print("New Process Detected:", message)

# Send notification
send_notification("New Process Detected", message)

def main_program():
previous_list = set()
new_processes = load_new_processes()
printed_processes = set()

while True:
    # Get current running processes
    current_list = get_running_processes()

    # Compare with the previous list and find new processes
    newly_started_processes = current_list - previous_list
    new_processes.extend(newly_started_processes)

    if newly_started_processes:
        with concurrent.futures.ThreadPoolExecutor() as executor:
            executor.map(lambda info: process_checker(info, printed_processes), newly_started_processes)

    # Update the previous list
    previous_list = current_list

    # Save the updated new processes list to the file
    save_new_processes(new_processes)

    # Wait for a short period before checking again
    time.sleep(0.1)

if name == “main”:
# Print the initially running processes
print(“Initially running processes:”)
print(get_running_processes())

# Run the main program
main_program()` Bu kodu o koda eklemem lazım. Bu kod çalışıyor ama bazı sorunlar var.  \??\C:\Windows\system32\conhost.exe olarak print ettiği oluyor Command Line kısmını. Fakat hal olur. Biraz daha hızlı yaptım kodu ThreadPoolExecutor ile. Çalıştığının kanıtı şu: New Process Detected: Path: C:\Windows\System32\wscript.exe, Parent Process Path: C:\Windows\explorer.exe, Command Line: ('C:\Windows\System32\WScript.exe', 'C:\Users\victim\Desktop\prank.vbs')

Entegre ettim ama kodu düzeltmem lazım. İstediğim gibi çalışmıyor. Mesela virüsü açınca onu baya geç fark ediyor.

Tamam her şey halloldu.