import tkinter as tk from tkinter import ttk, filedialog, messagebox, scrolledtext import os import sys import json import pyperclip from database import LicenseDatabase from encryptor import EXEEncryptor from machine_code import get_machine_code class EXEEncryptionTool(tk.Tk): def __init__(self): super().__init__() self.title("EXE文件加密保护系统 v2.0") self.geometry("900x700") self.minsize(900, 700) # 数据库配置 self.db_config = { 'host': '', 'database': 'license_system', 'user': '', 'password': '' } # 初始化数据库连接 self.db = None # 创建界面 self.create_widgets() # 加载保存的配置 self.load_config() # 自动查找validator.exe self.auto_find_validator() def create_widgets(self): """创建界面组件""" # 创建标签页 tab_control = ttk.Notebook(self) # 数据库配置标签页 self.tab_db_config = ttk.Frame(tab_control) tab_control.add(self.tab_db_config, text="数据库配置") # 卡密生成标签页 self.tab_key_gen = ttk.Frame(tab_control) tab_control.add(self.tab_key_gen, text="卡密生成") # EXE加密标签页 self.tab_encrypt = ttk.Frame(tab_control) tab_control.add(self.tab_encrypt, text="EXE加密") # 卡密管理标签页 self.tab_key_manage = ttk.Frame(tab_control) tab_control.add(self.tab_key_manage, text="卡密管理") # 测试工具标签页 self.tab_test = ttk.Frame(tab_control) tab_control.add(self.tab_test, text="测试工具") tab_control.pack(expand=1, fill="both") # 初始化各个标签页 self.init_db_config_tab() self.init_key_gen_tab() self.init_encrypt_tab() self.init_key_manage_tab() self.init_test_tab() # 状态栏 self.status_var = tk.StringVar(value="就绪") status_bar = ttk.Label(self, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W) status_bar.pack(side=tk.BOTTOM, fill=tk.X) def init_db_config_tab(self): """初始化数据库配置标签页""" frame = ttk.LabelFrame(self.tab_db_config, text="数据库连接设置") frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 表单布局 grid_frame = ttk.Frame(frame) grid_frame.pack(padx=10, pady=10, fill=tk.X) # 主机 ttk.Label(grid_frame, text="主机:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W) self.entry_db_host = ttk.Entry(grid_frame) self.entry_db_host.grid(row=0, column=1, padx=5, pady=5, sticky=tk.EW) # 数据库名 ttk.Label(grid_frame, text="数据库:").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W) self.entry_db_name = ttk.Entry(grid_frame) self.entry_db_name.grid(row=1, column=1, padx=5, pady=5, sticky=tk.EW) self.entry_db_name.insert(0, "license_system") # 用户名 ttk.Label(grid_frame, text="用户名:").grid(row=2, column=0, padx=5, pady=5, sticky=tk.W) self.entry_db_user = ttk.Entry(grid_frame) self.entry_db_user.grid(row=2, column=1, padx=5, pady=5, sticky=tk.EW) # 密码 ttk.Label(grid_frame, text="密码:").grid(row=3, column=0, padx=5, pady=5, sticky=tk.W) self.entry_db_password = ttk.Entry(grid_frame, show="*") self.entry_db_password.grid(row=3, column=1, padx=5, pady=5, sticky=tk.EW) # 按钮 button_frame = ttk.Frame(frame) button_frame.pack(padx=10, pady=10, fill=tk.X) self.btn_connect_db = ttk.Button(button_frame, text="连接数据库", command=self.connect_db) self.btn_connect_db.pack(side=tk.LEFT, padx=5) self.btn_create_tables = ttk.Button(button_frame, text="创建数据库表", command=self.create_db_tables) self.btn_create_tables.pack(side=tk.LEFT, padx=5) self.btn_save_db_config = ttk.Button(button_frame, text="保存配置", command=self.save_db_config) self.btn_save_db_config.pack(side=tk.RIGHT, padx=5) # 连接状态 self.label_db_status = ttk.Label(frame, text="未连接数据库", foreground="red") self.label_db_status.pack(anchor=tk.W, padx=10, pady=5) # 日志区域 log_frame = ttk.LabelFrame(frame, text="操作日志") log_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) self.text_db_log = scrolledtext.ScrolledText(log_frame, height=10) self.text_db_log.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) self.text_db_log.config(state=tk.DISABLED) # 设置网格权重 grid_frame.columnconfigure(1, weight=1) def init_key_gen_tab(self): """初始化卡密生成标签页""" frame = ttk.LabelFrame(self.tab_key_gen, text="卡密生成设置") frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 配置区域 config_frame = ttk.Frame(frame) config_frame.pack(fill=tk.X, padx=10, pady=10) # 有效期 ttk.Label(config_frame, text="有效期(天):").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W) self.entry_valid_days = ttk.Entry(config_frame, width=10) self.entry_valid_days.grid(row=0, column=1, padx=5, pady=5) self.entry_valid_days.insert(0, "30") # 生成数量 ttk.Label(config_frame, text="生成数量:").grid(row=0, column=2, padx=5, pady=5, sticky=tk.W) self.entry_key_count = ttk.Entry(config_frame, width=10) self.entry_key_count.grid(row=0, column=3, padx=5, pady=5) self.entry_key_count.insert(0, "1") # 生成按钮 self.btn_generate_keys = ttk.Button(config_frame, text="生成卡密", command=self.generate_keys) self.btn_generate_keys.grid(row=0, column=4, padx=20, pady=5) # 卡密列表 list_frame = ttk.LabelFrame(frame, text="生成的卡密") list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) self.text_keys = scrolledtext.ScrolledText(list_frame) self.text_keys.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) # 操作按钮 button_frame = ttk.Frame(frame) button_frame.pack(fill=tk.X, padx=10, pady=10) self.btn_copy_keys = ttk.Button(button_frame, text="复制所有卡密", command=self.copy_keys) self.btn_copy_keys.pack(side=tk.LEFT, padx=5) self.btn_export_keys = ttk.Button(button_frame, text="导出卡密到文件", command=self.export_keys) self.btn_export_keys.pack(side=tk.LEFT, padx=5) # 设置网格权重 config_frame.columnconfigure(5, weight=1) def init_encrypt_tab(self): """初始化EXE加密标签页""" frame = ttk.LabelFrame(self.tab_encrypt, text="EXE文件加密") frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 源文件 source_frame = ttk.Frame(frame) source_frame.pack(fill=tk.X, padx=10, pady=5) ttk.Label(source_frame, text="源EXE文件:").pack(side=tk.LEFT, padx=5) self.entry_source_file = ttk.Entry(source_frame) self.entry_source_file.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5) self.btn_browse_source = ttk.Button(source_frame, text="浏览...", command=self.browse_source_file) self.btn_browse_source.pack(side=tk.LEFT, padx=5) # 目标文件 dest_frame = ttk.Frame(frame) dest_frame.pack(fill=tk.X, padx=10, pady=5) ttk.Label(dest_frame, text="加密后文件:").pack(side=tk.LEFT, padx=5) self.entry_dest_file = ttk.Entry(dest_frame) self.entry_dest_file.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5) self.btn_browse_dest = ttk.Button(dest_frame, text="浏览...", command=self.browse_dest_file) self.btn_browse_dest.pack(side=tk.LEFT, padx=5) # 验证程序 validator_frame = ttk.Frame(frame) validator_frame.pack(fill=tk.X, padx=10, pady=5) ttk.Label(validator_frame, text="验证程序:").pack(side=tk.LEFT, padx=5) self.entry_validator = ttk.Entry(validator_frame) self.entry_validator.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5) self.btn_browse_validator = ttk.Button(validator_frame, text="浏览...", command=self.browse_validator) self.btn_browse_validator.pack(side=tk.LEFT, padx=5) self.btn_auto_find_validator = ttk.Button(validator_frame, text="自动查找", command=self.auto_find_validator) self.btn_auto_find_validator.pack(side=tk.LEFT, padx=2) # 加密按钮和测试按钮 button_frame = ttk.Frame(frame) button_frame.pack(fill=tk.X, padx=10, pady=10) self.btn_encrypt = ttk.Button(button_frame, text="加密EXE文件", command=self.encrypt_exe) self.btn_encrypt.pack(side=tk.LEFT, padx=5) self.btn_test_encrypted = ttk.Button(button_frame, text="测试加密文件", command=self.test_encrypted_file) self.btn_test_encrypted.pack(side=tk.LEFT, padx=5) # 加密日志 log_frame = ttk.LabelFrame(frame, text="加密日志") log_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) self.text_encrypt_log = scrolledtext.ScrolledText(log_frame, height=12) self.text_encrypt_log.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) self.text_encrypt_log.config(state=tk.DISABLED) def init_key_manage_tab(self): """初始化卡密管理标签页""" frame = ttk.LabelFrame(self.tab_key_manage, text="卡密管理") frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 搜索区域 search_frame = ttk.Frame(frame) search_frame.pack(fill=tk.X, padx=10, pady=5) ttk.Label(search_frame, text="搜索卡密:").pack(side=tk.LEFT, padx=5) self.entry_key_search = ttk.Entry(search_frame) self.entry_key_search.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5) self.btn_search_keys = ttk.Button(search_frame, text="搜索", command=self.search_keys) self.btn_search_keys.pack(side=tk.LEFT, padx=5) self.btn_refresh_keys = ttk.Button(search_frame, text="刷新", command=self.load_all_keys) self.btn_refresh_keys.pack(side=tk.LEFT, padx=5) # 卡密列表 list_frame = ttk.Frame(frame) list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5) columns = ("id", "key_code", "machine_code", "start_time", "end_time", "status", "created_at") self.tree_keys = ttk.Treeview(list_frame, columns=columns, show="headings") # 设置列标题 self.tree_keys.heading("id", text="ID") self.tree_keys.heading("key_code", text="卡密") self.tree_keys.heading("machine_code", text="机器码") self.tree_keys.heading("start_time", text="开始时间") self.tree_keys.heading("end_time", text="结束时间") self.tree_keys.heading("status", text="状态") self.tree_keys.heading("created_at", text="创建时间") # 设置列宽 self.tree_keys.column("id", width=50) self.tree_keys.column("key_code", width=150) self.tree_keys.column("machine_code", width=120) self.tree_keys.column("start_time", width=120) self.tree_keys.column("end_time", width=120) self.tree_keys.column("status", width=80) self.tree_keys.column("created_at", width=120) # 添加滚动条 scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.tree_keys.yview) self.tree_keys.configure(yscroll=scrollbar.set) self.tree_keys.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 操作按钮 button_frame = ttk.Frame(frame) button_frame.pack(fill=tk.X, padx=10, pady=10) self.btn_ban_key = ttk.Button(button_frame, text="封禁选中卡密", command=self.ban_selected_key) self.btn_ban_key.pack(side=tk.LEFT, padx=5) self.btn_unban_key = ttk.Button(button_frame, text="解封选中卡密", command=self.unban_selected_key) self.btn_unban_key.pack(side=tk.LEFT, padx=5) # 机器码显示 info_frame = ttk.LabelFrame(frame, text="系统信息") info_frame.pack(fill=tk.X, padx=10, pady=5) machine_frame = ttk.Frame(info_frame) machine_frame.pack(fill=tk.X, padx=5, pady=5) ttk.Label(machine_frame, text="当前机器码:").pack(side=tk.LEFT) self.label_machine_code = ttk.Label(machine_frame, text=get_machine_code(), foreground="blue") self.label_machine_code.pack(side=tk.LEFT, padx=10) btn_copy_machine = ttk.Button(machine_frame, text="复制", command=lambda: pyperclip.copy(get_machine_code())) btn_copy_machine.pack(side=tk.LEFT, padx=5) def init_test_tab(self): """初始化测试工具标签页""" frame = ttk.LabelFrame(self.tab_test, text="测试工具") frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 测试加密文件完整性 test_frame = ttk.LabelFrame(frame, text="加密文件完整性测试") test_frame.pack(fill=tk.X, padx=10, pady=10) file_frame = ttk.Frame(test_frame) file_frame.pack(fill=tk.X, padx=10, pady=5) ttk.Label(file_frame, text="加密文件:").pack(side=tk.LEFT, padx=5) self.entry_test_file = ttk.Entry(file_frame) self.entry_test_file.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5) self.btn_browse_test_file = ttk.Button(file_frame, text="浏览...", command=self.browse_test_file) self.btn_browse_test_file.pack(side=tk.LEFT, padx=5) test_button_frame = ttk.Frame(test_frame) test_button_frame.pack(fill=tk.X, padx=10, pady=5) self.btn_test_integrity = ttk.Button(test_button_frame, text="测试完整性", command=self.test_file_integrity) self.btn_test_integrity.pack(side=tk.LEFT, padx=5) self.btn_extract_info = ttk.Button(test_button_frame, text="提取信息", command=self.extract_file_info) self.btn_extract_info.pack(side=tk.LEFT, padx=5) # 测试日志 log_frame = ttk.LabelFrame(frame, text="测试日志") log_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) self.text_test_log = scrolledtext.ScrolledText(log_frame, height=15) self.text_test_log.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) self.text_test_log.config(state=tk.DISABLED) # 数据库相关方法 def log(self, text, widget=None): """添加日志信息""" if not widget: widget = self.text_db_log widget.config(state=tk.NORMAL) widget.insert(tk.END, text + "\n") widget.see(tk.END) widget.config(state=tk.DISABLED) self.update_idletasks() def connect_db(self): """连接到数据库""" self.db_config['host'] = self.entry_db_host.get() self.db_config['database'] = self.entry_db_name.get() self.db_config['user'] = self.entry_db_user.get() self.db_config['password'] = self.entry_db_password.get() self.log(f"尝试连接到数据库: {self.db_config['host']}/{self.db_config['database']}") self.db = LicenseDatabase( self.db_config['host'], self.db_config['database'], self.db_config['user'], self.db_config['password'] ) if self.db.connect(): self.label_db_status.config(text="已连接到数据库", foreground="green") self.log("数据库连接成功") messagebox.showinfo("成功", "数据库连接成功") # 连接成功后加载卡密列表 self.load_all_keys() else: self.label_db_status.config(text="数据库连接失败", foreground="red") self.log("数据库连接失败") messagebox.showerror("错误", "无法连接到数据库,请检查配置") def create_db_tables(self): """创建数据库表""" if not self.db or not self.db.connection.is_connected(): if not self.connect_db(): return self.log("尝试创建数据库表...") if self.db.create_tables(): self.log("数据库表创建成功") messagebox.showinfo("成功", "数据库表创建成功") else: self.log("数据库表创建失败") messagebox.showerror("错误", "数据库表创建失败") def save_db_config(self): """保存数据库配置""" self.db_config['host'] = self.entry_db_host.get() self.db_config['database'] = self.entry_db_name.get() self.db_config['user'] = self.entry_db_user.get() self.db_config['password'] = self.entry_db_password.get() try: with open('db_config.json', 'w') as f: json.dump(self.db_config, f) self.log("数据库配置保存成功") messagebox.showinfo("成功", "数据库配置已保存") except Exception as e: self.log(f"保存配置失败: {str(e)}") messagebox.showerror("错误", f"保存配置失败: {str(e)}") def load_config(self): """加载保存的配置""" try: if os.path.exists('db_config.json'): with open('db_config.json', 'r') as f: config = json.load(f) self.entry_db_host.insert(0, config.get('host', '')) self.entry_db_name.delete(0, tk.END) self.entry_db_name.insert(0, config.get('database', 'license_system')) self.entry_db_user.insert(0, config.get('user', '')) self.entry_db_password.insert(0, config.get('password', '')) except Exception as e: print(f"加载配置失败: {e}") # 卡密生成相关方法 def generate_keys(self): """生成卡密""" if not self.db or not self.db.connection.is_connected(): messagebox.showerror("错误", "请先连接数据库") return try: days = int(self.entry_valid_days.get()) count = int(self.entry_key_count.get()) if days <= 0 or count <= 0: messagebox.showerror("错误", "有效期和数量必须为正数") return self.text_keys.delete(1.0, tk.END) self.log(f"开始生成 {count} 个有效期为 {days} 天的卡密...", self.text_keys) keys = [] for i in range(count): key = self.db.generate_key(days) if key: keys.append(key) self.text_keys.insert(tk.END, key + "\n") self.text_keys.see(tk.END) self.update_idletasks() self.log(f"\n成功生成 {len(keys)} 个卡密", self.text_keys) messagebox.showinfo("成功", f"成功生成 {len(keys)} 个卡密") # 刷新卡密列表 self.load_all_keys() except ValueError: messagebox.showerror("错误", "请输入有效的数字") except Exception as e: messagebox.showerror("错误", f"生成卡密失败: {str(e)}") def copy_keys(self): """复制卡密到剪贴板""" keys = self.text_keys.get(1.0, tk.END).strip() if keys: pyperclip.copy(keys) messagebox.showinfo("成功", "卡密已复制到剪贴板") else: messagebox.showinfo("提示", "没有可复制的卡密") def export_keys(self): """导出卡密到文件""" keys = self.text_keys.get(1.0, tk.END).strip() if not keys: messagebox.showinfo("提示", "没有可导出的卡密") return file_path = filedialog.asksaveasfilename( defaultextension=".txt", filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")] ) if file_path: try: with open(file_path, 'w') as f: f.write(keys) messagebox.showinfo("成功", f"卡密已导出到 {file_path}") except Exception as e: messagebox.showerror("错误", f"导出失败: {str(e)}") # EXE加密相关方法 def auto_find_validator(self): """自动查找validator.exe""" possible_paths = [ "validator.exe", "dist/validator.exe", "dist/final/validator.exe", os.path.join(os.path.dirname(os.path.abspath(__file__)), "validator.exe"), os.path.join(os.path.dirname(os.path.abspath(__file__)), "dist", "validator.exe"), ] for path in possible_paths: if os.path.exists(path): self.entry_validator.delete(0, tk.END) self.entry_validator.insert(0, path) self.log(f"自动找到验证程序: {path}", self.text_encrypt_log) return True self.log("未找到validator.exe,请手动选择", self.text_encrypt_log) return False def browse_source_file(self): """浏览源文件""" file_path = filedialog.askopenfilename( filetypes=[("EXE文件", "*.exe"), ("所有文件", "*.*")] ) if file_path: self.entry_source_file.delete(0, tk.END) self.entry_source_file.insert(0, file_path) # 自动填充目标文件路径 dir_name, file_name = os.path.split(file_path) name, ext = os.path.splitext(file_name) dest_file = os.path.join(dir_name, f"{name}_encrypted{ext}") self.entry_dest_file.delete(0, tk.END) self.entry_dest_file.insert(0, dest_file) def browse_dest_file(self): """浏览目标文件""" file_path = filedialog.asksaveasfilename( defaultextension=".exe", filetypes=[("EXE文件", "*.exe"), ("所有文件", "*.*")] ) if file_path: self.entry_dest_file.delete(0, tk.END) self.entry_dest_file.insert(0, file_path) def browse_validator(self): """浏览验证程序""" file_path = filedialog.askopenfilename( filetypes=[("EXE文件", "*.exe"), ("所有文件", "*.*")] ) if file_path: self.entry_validator.delete(0, tk.END) self.entry_validator.insert(0, file_path) def encrypt_exe(self): """加密EXE文件""" source_path = self.entry_source_file.get() dest_path = self.entry_dest_file.get() validator_path = self.entry_validator.get() # 检查文件路径 if not source_path or not os.path.exists(source_path): messagebox.showerror("错误", "请选择有效的源文件") return if not dest_path: messagebox.showerror("错误", "请选择目标文件路径") return if not validator_path or not os.path.exists(validator_path): messagebox.showerror("错误", "请选择有效的验证程序") return # 检查数据库连接 if not self.db or not self.db.connection.is_connected(): if not self.connect_db(): return # 执行加密 self.log("开始加密文件...", self.text_encrypt_log) self.log(f"源文件: {source_path}", self.text_encrypt_log) self.log(f"验证程序: {validator_path}", self.text_encrypt_log) try: encryptor = EXEEncryptor() success, msg = encryptor.encrypt_file( source_path, dest_path, validator_path, self.db_config ) self.log(msg, self.text_encrypt_log) if success: self.log(f"加密后的文件已保存到: {dest_path}", self.text_encrypt_log) # 自动测试加密文件 self.log("自动测试加密文件完整性...", self.text_encrypt_log) test_success, test_msg = encryptor.test_encrypted_file(dest_path) self.log(f"完整性测试结果: {test_msg}", self.text_encrypt_log) if test_success: messagebox.showinfo("成功", f"文件加密成功并通过完整性测试\n保存到: {dest_path}") else: messagebox.showwarning("警告", f"文件加密成功但完整性测试失败\n{test_msg}\n保存到: {dest_path}") else: messagebox.showerror("错误", msg) except Exception as e: error_msg = f"加密过程出错: {str(e)}" self.log(error_msg, self.text_encrypt_log) messagebox.showerror("错误", error_msg) def test_encrypted_file(self): """测试加密文件""" dest_path = self.entry_dest_file.get() if not dest_path or not os.path.exists(dest_path): messagebox.showerror("错误", "请先加密文件或选择有效的加密文件") return try: encryptor = EXEEncryptor() success, msg = encryptor.test_encrypted_file(dest_path) self.log(f"测试结果: {msg}", self.text_encrypt_log) if success: messagebox.showinfo("测试成功", "加密文件完整性测试通过") else: messagebox.showerror("测试失败", f"加密文件完整性测试失败\n{msg}") except Exception as e: error_msg = f"测试过程出错: {str(e)}" self.log(error_msg, self.text_encrypt_log) messagebox.showerror("错误", error_msg) # 卡密管理相关方法 def load_all_keys(self): """加载所有卡密""" if not self.db or not self.db.connection.is_connected(): return # 清空现有列表 for item in self.tree_keys.get_children(): self.tree_keys.delete(item) try: keys = self.db.get_all_keys() for key in keys: # 格式化日期时间 start_time = key['start_time'].strftime("%Y-%m-%d") if key['start_time'] else "" end_time = key['end_time'].strftime("%Y-%m-%d") if key['end_time'] else "" created_at = key['created_at'].strftime("%Y-%m-%d") if key['created_at'] else "" self.tree_keys.insert("", tk.END, values=( key['id'], key['key_code'], key['machine_code'] or "", start_time, end_time, key['status'], created_at )) # 根据状态设置行颜色 item = self.tree_keys.get_children()[-1] if key['status'] == 'active': self.tree_keys.item(item, tags=('active',)) elif key['status'] == 'expired': self.tree_keys.item(item, tags=('expired',)) elif key['status'] == 'banned': self.tree_keys.item(item, tags=('banned',)) # 设置标签样式 self.tree_keys.tag_configure('active', foreground='green') self.tree_keys.tag_configure('expired', foreground='gray') self.tree_keys.tag_configure('banned', foreground='red') except Exception as e: print(f"加载卡密列表失败: {e}") def search_keys(self): """搜索卡密""" if not self.db or not self.db.connection.is_connected(): return search_text = self.entry_key_search.get().strip().lower() if not search_text: self.load_all_keys() return # 清空现有列表 for item in self.tree_keys.get_children(): self.tree_keys.delete(item) try: keys = self.db.get_all_keys() for key in keys: # 检查是否匹配搜索文本 if (search_text in key['key_code'].lower() or search_text in key['status'].lower() or (key['machine_code'] and search_text in key['machine_code'].lower())): # 格式化日期时间 start_time = key['start_time'].strftime("%Y-%m-%d") if key['start_time'] else "" end_time = key['end_time'].strftime("%Y-%m-%d") if key['end_time'] else "" created_at = key['created_at'].strftime("%Y-%m-%d") if key['created_at'] else "" self.tree_keys.insert("", tk.END, values=( key['id'], key['key_code'], key['machine_code'] or "", start_time, end_time, key['status'], created_at )) except Exception as e: print(f"搜索卡密失败: {e}") def get_selected_key_code(self): """获取选中的卡密""" selected_items = self.tree_keys.selection() if not selected_items: messagebox.showinfo("提示", "请先选择一个卡密") return None item = selected_items[0] key_code = self.tree_keys.item(item, "values")[1] return key_code def ban_selected_key(self): """封禁选中的卡密""" key_code = self.get_selected_key_code() if not key_code: return if messagebox.askyesno("确认", f"确定要封禁卡密 {key_code} 吗?"): if self.db.update_key_status(key_code, 'banned'): messagebox.showinfo("成功", "卡密已封禁") self.load_all_keys() else: messagebox.showerror("错误", "封禁卡密失败") def unban_selected_key(self): """解封选中的卡密""" key_code = self.get_selected_key_code() if not key_code: return if messagebox.askyesno("确认", f"确定要解封卡密 {key_code} 吗?"): # 检查原状态是未使用还是已激活 try: selected_items = self.tree_keys.selection() item = selected_items[0] machine_code = self.tree_keys.item(item, "values")[2] # 如果有机器码说明之前已激活,解封后应该是active状态 # 如果没有机器码说明之前未使用,解封后应该是unused状态 new_status = 'active' if machine_code else 'unused' if self.db.update_key_status(key_code, new_status): messagebox.showinfo("成功", "卡密已解封") self.load_all_keys() else: messagebox.showerror("错误", "解封卡密失败") except Exception as e: messagebox.showerror("错误", f"操作失败: {str(e)}") # 测试工具相关方法 def browse_test_file(self): """浏览测试文件""" file_path = filedialog.askopenfilename( filetypes=[("EXE文件", "*.exe"), ("所有文件", "*.*")] ) if file_path: self.entry_test_file.delete(0, tk.END) self.entry_test_file.insert(0, file_path) def test_file_integrity(self): """测试文件完整性""" file_path = self.entry_test_file.get() if not file_path or not os.path.exists(file_path): messagebox.showerror("错误", "请选择有效的文件") return try: self.log(f"开始测试文件: {file_path}", self.text_test_log) encryptor = EXEEncryptor() success, msg = encryptor.test_encrypted_file(file_path) self.log(f"测试结果: {msg}", self.text_test_log) if success: messagebox.showinfo("测试成功", "文件完整性测试通过") else: messagebox.showerror("测试失败", f"文件完整性测试失败\n{msg}") except Exception as e: error_msg = f"测试过程出错: {str(e)}" self.log(error_msg, self.text_test_log) messagebox.showerror("错误", error_msg) def extract_file_info(self): """提取文件信息""" file_path = self.entry_test_file.get() if not file_path or not os.path.exists(file_path): messagebox.showerror("错误", "请选择有效的文件") return try: self.log(f"开始提取文件信息: {file_path}", self.text_test_log) with open(file_path, 'rb') as f: data = f.read() self.log(f"文件大小: {len(data)} 字节", self.text_test_log) # 查找分隔符 separator = b"<>" separators = [] start = 0 while True: pos = data.find(separator, start) if pos == -1: break separators.append(pos) start = pos + len(separator) self.log(f"找到 {len(separators)} 个分隔符", self.text_test_log) if len(separators) >= 3: # 提取数据库配置 db_config_start = separators[0] + len(separator) db_config_end = separators[1] db_config_str = data[db_config_start:db_config_end].decode('utf-8') config_parts = db_config_str.split('|') if len(config_parts) == 4: self.log(f"数据库主机: {config_parts[0]}", self.text_test_log) self.log(f"数据库名: {config_parts[1]}", self.text_test_log) self.log(f"数据库用户: {config_parts[2]}", self.text_test_log) self.log(f"数据库密码: {'*' * len(config_parts[3])}", self.text_test_log) # 提取密钥信息 key_start = separators[1] + len(separator) key_end = separators[2] key = data[key_start:key_end] self.log(f"加密密钥长度: {len(key)} 字节", self.text_test_log) # 提取加密数据信息 encrypted_data_start = separators[2] + len(separator) encrypted_data = data[encrypted_data_start:] self.log(f"加密数据长度: {len(encrypted_data)} 字节", self.text_test_log) # 计算各部分大小占比 validator_size = separators[0] config_size = separators[1] - separators[0] - len(separator) key_size = separators[2] - separators[1] - len(separator) data_size = len(data) - separators[2] - len(separator) self.log(f"验证程序大小: {validator_size} 字节 ({validator_size / len(data) * 100:.1f}%)", self.text_test_log) self.log(f"配置数据大小: {config_size} 字节", self.text_test_log) self.log(f"密钥大小: {key_size} 字节", self.text_test_log) self.log(f"加密数据大小: {data_size} 字节 ({data_size / len(data) * 100:.1f}%)", self.text_test_log) messagebox.showinfo("成功", "文件信息提取完成,请查看测试日志") else: self.log("文件格式不正确,可能不是加密文件", self.text_test_log) messagebox.showwarning("警告", "文件格式不正确,可能不是加密文件") except Exception as e: error_msg = f"提取信息过程出错: {str(e)}" self.log(error_msg, self.text_test_log) messagebox.showerror("错误", error_msg) if __name__ == "__main__": # 设置高DPI支持 try: from ctypes import windll windll.shcore.SetProcessDpiAwareness(1) except: pass app = EXEEncryptionTool() app.mainloop()