DEV Community

Mate Technologies
Mate Technologies

Posted on

Build a Python Risk Scanner: Step-by-Step Beginner-Friendly Guide

Ever wanted to create a tool that scans your files for potential risks like suspicious names, dangerous extensions, or malware-like patterns? In this tutorial, we’ll build RiskScan, a Python app with a GUI that detects risky files and provides detailed recommendations.

This guide is beginner-friendly and shows how to structure your app, handle scanning logic, and build a responsive interface with Tkinter.

Step 1: Import Required Modules

First, we need some Python modules for file handling, GUI, and threading:

import sys
import os
import subprocess
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import threading
import random
Enter fullscreen mode Exit fullscreen mode

Explanation:

os and sys → For file operations and paths.

subprocess → To open file locations.

tkinter → For creating the GUI.

threading → To run scans without freezing the GUI.

random → To pick random reasons for file risk reporting.

Step 2: Define App Theme and Rules

Set up some colors and rules for detecting risky files:

# Theme
APP_BG = "#121212"
PANEL_BG = "#1F1F1F"
BTN_BG = "#2C2C2C"
ACCENT = "#FF6F61"
TEXT_CLR = "#E0E0E0"

# File scanning rules
DANGEROUS_EXT = [".exe", ".bat", ".cmd", ".ps1", ".vbs", ".js", ".scr", ".dll"]
SUSPICIOUS_NAMES = ["crack", "keygen", "loader", "hack", "trojan", "virus"]
SUSPICIOUS_DIRS = ["appdata", "temp", "startup"]
SMALL_EXEC_LIMIT = 15 * 1024  # 15 KB
Enter fullscreen mode Exit fullscreen mode

Explanation:

DANGEROUS_EXT → File types that can run system-level commands.

SUSPICIOUS_NAMES → Common malware/hacking tool patterns.

SMALL_EXEC_LIMIT → Very small files can sometimes be malware droppers.

Step 3: Professional Threat Knowledge Base

We’ll create a small database of rules with weights, reasons, MITRE ATT&CK references, and fixes:

THREAT_DB = {
    "DANGEROUS_EXT": {
        "weight": 30,
        "mitre": "T1059",
        "reasons": [
            "Executable files can directly run system-level instructions",
            "This file type is frequently abused to deliver malware payloads"
        ],
        "fix": "Avoid running unknown executables. Scan with trusted antivirus software."
    },
    "SUSPICIOUS_DIR": {
        "weight": 25,
        "mitre": "T1547",
        "reasons": [
            "Malware commonly hides in user or temporary directories",
            "This directory is often abused to maintain persistence"
        ],
        "fix": "Review startup locations and remove unauthorized programs."
    }
    # Add DOUBLE_EXT, SMALL_EXEC, SUSPICIOUS_NAME similarly
}
Enter fullscreen mode Exit fullscreen mode

Explanation:

Each rule has a weight to determine severity.

mitre refers to MITRE ATT&CK ID for cybersecurity context.

reasons explain why a file is risky.

fix suggests remediation.

Step 4: Utility Function to Handle Resources

If you later convert this Python script to an EXE, we need a function to locate bundled files:

def resource_path(file_name):
    """
    Get absolute path to resources, works with PyInstaller.
    """
    base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, file_name)
Enter fullscreen mode Exit fullscreen mode

Step 5: Create the GUI App Class

We’ll use Tkinter to create the GUI. Start by defining the main class:

class ProblemFinderApp:
    def __init__(self, root):
        self.root = root
        root.title("RiskScan - Problem File Finder")
        root.geometry("1200x600")
        root.configure(bg=APP_BG)

        self.target = None  # File or folder to scan
        self.total_files = 0
        self.stats = {"LOW": 0, "MEDIUM": 0, "HIGH": 0}
        self.high_risk = []
        self.medium_risk = []

        # Scan controls
        self.scan_thread = None
        self.scan_paused = False
        self.scan_stopped = False
Enter fullscreen mode Exit fullscreen mode

Explanation:

self.target → The file or folder the user selects.

self.stats → Tracks counts of low, medium, and high-risk files.

self.high_risk and self.medium_risk → Lists to store results for reporting.

Step 6: Add File and Folder Pickers

Let users select files or folders to scan:

def pick_folder(self):
    p = filedialog.askdirectory()
    if p:
        self.target = p
        self.path_label.config(text=p)

def pick_file(self):
    p = filedialog.askopenfilename()
    if p:
        self.target = p
        self.path_label.config(text=p)
Enter fullscreen mode Exit fullscreen mode

Explanation:

askdirectory() → Opens folder picker.

askopenfilename() → Opens file picker.

Step 7: Add Start, Pause, and Scan Logic

To run the scan without freezing the GUI, we use a thread:

def start_scan(self):
    if not self.target:
        messagebox.showwarning("Warning", "Please select a file or folder to scan first!")
        return

    self.total_files = 0
    self.stats = {"LOW": 0, "MEDIUM": 0, "HIGH": 0}
    self.high_risk.clear()
    self.medium_risk.clear()
    self.scan_paused = False
    self.scan_stopped = False

    self.output.config(state="normal")
    self.output.delete("1.0", "end")
    self.output.config(state="disabled")

    # Start scan in separate thread
    self.scan_thread = threading.Thread(target=self.scan, daemon=True)
    self.scan_thread.start()
Enter fullscreen mode Exit fullscreen mode

Step 8: Scan Each File

Here’s the core detection logic:

def check_file(self, path):
    name = os.path.basename(path).lower()
    ext = os.path.splitext(name)[1]
    try:
        size = os.path.getsize(path)
    except Exception:
        return

    score = 0
    reasons = []
    mitre = set()
    fixes = set()

    def apply(rule):
        nonlocal score
        data = THREAT_DB[rule]
        score += data["weight"]
        reasons.append(random.choice(data["reasons"]))
        mitre.add(data["mitre"])
        fixes.add(data["fix"])

    if ext in DANGEROUS_EXT:
        apply("DANGEROUS_EXT")
    if any(x in path.lower() for x in SUSPICIOUS_DIRS):
        apply("SUSPICIOUS_DIR")
Enter fullscreen mode Exit fullscreen mode

Explanation:

apply(rule) → Adds weight, reason, MITRE ID, and fix to the file if it matches a rule.

Files are evaluated for multiple risk factors.

Step 9: Show Results

After scanning, display the summary:

def show_summary(self):
    verdict = "LOW RISK"
    if self.stats["HIGH"] > 0:
        verdict = "HIGH RISK"
    elif self.stats["MEDIUM"] > 0:
        verdict = "MEDIUM RISK"

    self.output.config(state="normal")
    self.output.insert("end", f"Files Scanned: {self.total_files}\n")
    self.output.insert("end", f"HIGH Risk: {self.stats['HIGH']}\n")
    self.output.insert("end", f"MEDIUM Risk: {self.stats['MEDIUM']}\n")
    self.output.insert("end", f"OVERALL VERDICT: {verdict}\n")
    self.output.config(state="disabled")
Enter fullscreen mode Exit fullscreen mode

Step 10: Export Report

Allow users to save a text report:

def export_report(self):
    if not self.high_risk and not self.medium_risk:
        messagebox.showinfo("Info", "No HIGH or MEDIUM risk items to export")
        return

    f = filedialog.asksaveasfilename(defaultextension=".txt")
    if not f:
        return

    with open(f, "w", encoding="utf-8") as file:
        file.write("Problem File Finder REPORT\n\n")
        file.write(f"Files Scanned: {self.total_files}\n")
        file.write(f"HIGH Risk: {self.stats['HIGH']}\n")
        file.write(f"MEDIUM Risk: {self.stats['MEDIUM']}\n\n")
Enter fullscreen mode Exit fullscreen mode

Step 11: Run the App

Finally, run the Tkinter app:

if __name__ == "__main__":
    root = tk.Tk()
    app = ProblemFinderApp(root)
    root.mainloop()
Enter fullscreen mode Exit fullscreen mode

✅ Next Steps

Add clickable file paths to open their location.

Enhance detection with more MITRE techniques.

Package as an EXE for Windows users (e.g., using PyInstaller).

📥 Download

Free EXE: Download RiskScan EXE

Risk Scanner Tool

Top comments (0)