888 lines
36 KiB
Python
888 lines
36 KiB
Python
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() |