ArticleReplaceBatch/deepseek-clien/main.py
2025-08-06 15:57:14 +08:00

888 lines
36 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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"<<EXE_ENCRYPTED_DATA>>"
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()