如何用Python守护线程搭建含类Metasploit GUI的个人工具框架
Alright, let's tackle this problem step by step—building a Metasploit-style framework with your exact requirements is totally doable with Python. I'll break down each component and share working code you can tweak for your needs.
First, let's align on thread roles to avoid confusion:
- Main Thread: Acts as the entry point (we'll structure it to behave like a daemon by only managing the GUI thread and exiting once the GUI closes—since Python doesn't let you mark the main thread as a daemon directly).
- GUI Thread: A non-daemon thread running a terminal-like console interface (using Tkinter for simplicity) that handles command input.
- Module Threads: Each module runs as a daemon thread, so they automatically exit when the main program (GUI) closes.
framework Alias First, make launching your framework easy with a custom alias:
- Linux/macOS: Add this line to your
~/.bashrcor~/.zshrcfile:
Runalias framework='python3 /full/path/to/your/framework.py'source ~/.bashrc(or restart your terminal) to apply the change. - Windows: Use
doskeyin Command Prompt:
Or create adoskey framework=python.exe C:\full\path\to\your\framework.py.batfile with that command for persistent access.
We'll create a base module class that inherits from threading.Thread (marked as daemon by default). All your custom modules will extend this:
import threading import time class BaseModule(threading.Thread): def __init__(self): super().__init__(daemon=True) self.name = "base_module" self.description = "Template for all framework modules" def run(self): # Override this method in your custom modules to add functionality pass # Example module: Basic Port Scanner class ScanModule(BaseModule): def __init__(self): super().__init__() self.name = "scan" self.description = "Scans for open network ports" def run(self): while True: print(f"[{self.name}] Scanning open ports...") time.sleep(2) # Add more modules here (e.g., ExploitModule, EnumerateModule)
We'll use Tkinter to build a terminal-like GUI that handles use <module> and run commands. This runs in a separate non-daemon thread to keep the program alive:
import tkinter as tk from tkinter import scrolledtext, Entry class FrameworkGUI(threading.Thread): def __init__(self): super().__init__(daemon=False) # Non-daemon to keep program running self.current_module = None # Register all your modules here self.modules = { "scan": ScanModule() } def run(self): # Initialize GUI window self.root = tk.Tk() self.root.title("Framework Console") self.root.geometry("800x600") # Read-only output area self.output_box = scrolledtext.ScrolledText(self.root, wrap=tk.WORD, state="disabled") self.output_box.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) # Command input area self.input_frame = tk.Frame(self.root) self.input_frame.pack(fill=tk.X, padx=5, pady=5) self.input_entry = Entry(self.input_frame) self.input_entry.pack(side=tk.LEFT, fill=tk.X, expand=True) self.input_entry.bind("<Return>", self.process_command) self._print_welcome() self.root.mainloop() def _print_welcome(self): self._add_output("=== Framework Console ===") self._add_output("Available Commands:") self._add_output(" use <module> - Select a module to use") self._add_output(" run - Start the selected module in background") self._add_output(" exit - Close the console") self._add_output(f"Loaded modules: {', '.join(self.modules.keys())}") def _add_output(self, text): self.output_box.config(state="normal") self.output_box.insert(tk.END, f"{text}\n") self.output_box.config(state="disabled") self.output_box.see(tk.END) def process_command(self, event): command = self.input_entry.get().strip() self.input_entry.delete(0, tk.END) self._add_output(f"> {command}") if not command: return cmd_parts = command.split() main_cmd = cmd_parts[0].lower() if main_cmd == "use": if len(cmd_parts) < 2: self._add_output("Error: Specify a module name (e.g., 'use scan')") return module_name = cmd_parts[1] if module_name in self.modules: self.current_module = self.modules[module_name] self._add_output(f"Selected module: {self.current_module.name} - {self.current_module.description}") else: self._add_output(f"Error: Module '{module_name}' not found") elif main_cmd == "run": if not self.current_module: self._add_output("Error: No module selected. Use 'use <module>' first.") return if self.current_module.is_alive(): self._add_output(f"Module '{self.current_module.name}' is already running!") return self.current_module.start() self._add_output(f"Started module '{self.current_module.name}' in background") elif main_cmd == "exit": self.root.quit() else: self._add_output(f"Unknown command: '{main_cmd}'")
The main thread launches the GUI thread and waits for it to close. This setup ensures it only acts as a launcher and exits once the GUI is closed, behaving like a daemon:
def main(): # Launch the GUI thread gui_thread = FrameworkGUI() gui_thread.start() # Wait for the GUI to close before exiting gui_thread.join() if __name__ == "__main__": main()
- Daemon Modules: Each module is a daemon thread, so they'll automatically stop when the GUI closes—no need to manually terminate them.
- GUI Persistence: The GUI thread is non-daemon, so it keeps the entire program running until the user closes the window.
- Command Safety: The code checks if a module is already running before starting it, preventing duplicate threads.
- Extensibility: Add new modules by creating a subclass of
BaseModuleand registering it in theself.modulesdictionary inFrameworkGUI.
内容的提问来源于stack exchange,提问作者Mablec

