import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
import random
import string
import hashlib
import os
import base64
import time
import winreg
import shutil
import datetime
import ctypes
class DLLProtectorApp:
def __init__(self, root):
self.root = root
self.root.title("DLL保护工具 - 加密、混淆与授权激活系统")
self.root.geometry("1000x800")
self.root.configure(bg='#2c3e50')
# 创建标签页
self.tab_control = ttk.Notebook(root)
# 加密标签页
self.encrypt_tab = ttk.Frame(self.tab_control)
self.tab_control.add(self.encrypt_tab, text='DLL加密')
# 混淆标签页
self.obfuscate_tab = ttk.Frame(self.tab_control)
self.tab_control.add(self.obfuscate_tab, text='代码混淆')
# 授权标签页
self.license_tab = ttk.Frame(self.tab_control)
self.tab_control.add(self.license_tab, text='授权管理')
self.tab_control.pack(expand=1, fill="both", padx=10, pady=10)
# 初始化UI
self.create_encrypt_tab()
self.create_obfuscate_tab()
self.create_license_tab()
# 初始化状态变量
self.encrypt_files = []
self.obfuscate_files = []
self.license_key = ""
self.activation_date = None # 激活时间
self.expiry_date = None # 到期时间
self.usage_count = 0 # 功能使用次数计数器
self.max_usage_count = 0 # 最大使用次数
self.time_limit_days = 0 # 时间限制天数
self.permanent_license_shown = False # 标记永久授权是否已显示
self.machine_id = "" # 存储机器码
# 创建状态栏
self.status_var = tk.StringVar()
self.status_var.set("就绪")
self.status_bar = tk.Label(root, textvariable=self.status_var, bd=1,
relief=tk.SUNKEN, anchor=tk.W, bg='#34495e', fg='white')
self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
def create_encrypt_tab(self):
tab = self.encrypt_tab
# 标题
title = tk.Label(tab, text="DLL文件加密", font=("Arial", 16, "bold"), bg='#2c3e50', fg='#ecf0f1')
title.pack(pady=15)
# 文件选择区域 - 支持多文件选择
file_frame = tk.LabelFrame(tab, text="选择DLL文件 (可多选)", bg='#2c3e50', fg='#ecf0f1')
file_frame.pack(fill=tk.X, padx=20, pady=10)
# 使用ScrolledText显示选中的文件列表
self.encrypt_file_listbox = scrolledtext.ScrolledText(file_frame, height=5,
bg='#34495e', fg='#ecf0f1', insertbackground='white')
self.encrypt_file_listbox.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
self.encrypt_file_listbox.config(state=tk.DISABLED)
# 文件操作按钮
btn_frame = tk.Frame(file_frame, bg='#2c3e50')
btn_frame.pack(fill=tk.X, pady=5)
browse_btn = tk.Button(btn_frame, text="添加文件...", command=self.browse_encrypt_files,
bg='#3498db', fg='white')
browse_btn.pack(side=tk.LEFT, padx=5)
clear_btn = tk.Button(btn_frame, text="清空列表", command=self.clear_encrypt_file_list,
bg='#e74c3c', fg='white')
clear_btn.pack(side=tk.LEFT, padx=5)
# 加密选项区域
options_frame = tk.LabelFrame(tab, text="加密选项", bg='#2c3e50', fg='#ecf0f1')
options_frame.pack(fill=tk.X, padx=20, pady=10)
tk.Label(options_frame, text="加密强度:", bg='#2c3e50', fg='#ecf0f1').grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
self.encryption_level = tk.StringVar(value="AES-256")
levels = ["AES-128", "AES-192", "AES-256", "Blowfish", "Twofish"]
level_menu = ttk.Combobox(options_frame, textvariable=self.encryption_level,
values=levels, state="readonly", width=15)
level_menu.grid(row=0, column=1, padx=5, pady=5, sticky=tk.W)
tk.Label(options_frame, text="输出目录:", bg='#2c3e50', fg='#ecf0f1').grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
self.encrypt_output_dir = tk.StringVar(value=os.path.join(os.path.expanduser("~"), "encrypted"))
output_entry = tk.Entry(options_frame, textvariable=self.encrypt_output_dir, width=50)
output_entry.grid(row=1, column=1, padx=5, pady=5, sticky=tk.W)
browse_dir_btn = tk.Button(options_frame, text="浏览...", command=self.browse_encrypt_output_dir,
bg='#3498db', fg='white')
browse_dir_btn.grid(row=1, column=2, padx=5, pady=5)
# 加密按钮
encrypt_btn = tk.Button(tab, text="批量加密文件", command=self.encrypt_files,
bg='#2ecc71', fg='white', font=("Arial", 12), height=2, width=20)
encrypt_btn.pack(pady=20)
# 状态显示
self.encrypt_status = tk.Label(tab, text="", bg='#2c3e50', fg='#e74c3c')
self.encrypt_status.pack(pady=10)
def create_obfuscate_tab(self):
tab = self.obfuscate_tab
# 标题
title = tk.Label(tab, text="代码混淆", font=("Arial", 16, "bold"), bg='#2c3e50', fg='#ecf0f1')
title.pack(pady=15)
# 文件选择区域 - 支持多文件选择
file_frame = tk.LabelFrame(tab, text="选择DLL文件 (可多选)", bg='#2c3e50', fg='#ecf0f1')
file_frame.pack(fill=tk.X, padx=20, pady=10)
# 使用ScrolledText显示选中的文件列表
self.obfuscate_file_listbox = scrolledtext.ScrolledText(file_frame, height=5,
bg='#34495e', fg='#ecf0f1', insertbackground='white')
self.obfuscate_file_listbox.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
self.obfuscate_file_listbox.config(state=tk.DISABLED)
# 文件操作按钮
btn_frame = tk.Frame(file_frame, bg='#2c3e50')
btn_frame.pack(fill=tk.X, pady=5)
browse_btn = tk.Button(btn_frame, text="添加文件...", command=self.browse_obfuscate_files,
bg='#3498db', fg='white')
browse_btn.pack(side=tk.LEFT, padx=5)
clear_btn = tk.Button(btn_frame, text="清空列表", command=self.clear_obfuscate_file_list,
bg='#e74c3c', fg='white')
clear_btn.pack(side=tk.LEFT, padx=5)
# 混淆选项
options_frame = tk.LabelFrame(tab, text="混淆设置", bg='#2c3e50', fg='#ecf0f1')
options_frame.pack(fill=tk.X, padx=20, pady=10)
# 混淆方法
tk.Label(options_frame, text="混淆方法:", bg='#2c3e50', fg='#ecf0f1').grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
self.obf_method = tk.StringVar(value="名称混淆")
methods = ["名称混淆", "控制流混淆", "字符串加密", "指令替换", "全混淆模式"]
method_menu = ttk.Combobox(options_frame, textvariable=self.obf_method,
values=methods, state="readonly", width=15)
method_menu.grid(row=0, column=1, padx=5, pady=5, sticky=tk.W)
method_menu.bind("<<ComboboxSelected>>", self.update_preview)
# 混淆强度
tk.Label(options_frame, text="混淆强度:", bg='#2c3e50', fg='#ecf0f1').grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
self.obf_strength = tk.IntVar(value=5)
strength_scale = tk.Scale(options_frame, variable=self.obf_strength, from_=1, to=10, orient=tk.HORIZONTAL,
bg='#2c3e50', fg='#ecf0f1', highlightbackground='#2c3e50', command=lambda e: self.update_preview())
strength_scale.grid(row=1, column=1, padx=5, pady=5, sticky=tk.W)
# 输出目录
tk.Label(options_frame, text="输出目录:", bg='#2c3e50', fg='#ecf0f1').grid(row=2, column=0, padx=5, pady=5, sticky=tk.W)
self.obfuscate_output_dir = tk.StringVar(value=os.path.join(os.path.expanduser("~"), "obfuscated"))
output_entry = tk.Entry(options_frame, textvariable=self.obfuscate_output_dir, width=50)
output_entry.grid(row=2, column=1, padx=5, pady=5, sticky=tk.W)
browse_dir_btn = tk.Button(options_frame, text="浏览...", command=self.browse_obfuscate_output_dir,
bg='#3498db', fg='white')
browse_dir_btn.grid(row=2, column=2, padx=5, pady=5)
# 混淆按钮
obfuscate_btn = tk.Button(tab, text="批量混淆文件", command=self.obfuscate_files,
bg='#9b59b6', fg='white', font=("Arial", 12), height=2, width=20)
obfuscate_btn.pack(pady=20)
# 混淆预览
preview_frame = tk.LabelFrame(tab, text="混淆预览", bg='#2c3e50', fg='#ecf0f1')
preview_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
self.preview_text = tk.Text(preview_frame, height=10, bg='#34495e', fg='#ecf0f1', insertbackground='white')
self.preview_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# 设置初始预览
self.update_preview()
def create_license_tab(self):
tab = self.license_tab
# 标题
title = tk.Label(tab, text="授权管理系统", font=("Arial", 16, "bold"), bg='#2c3e50', fg='#ecf0f1')
title.pack(pady=15)
# 授权信息区域
info_frame = tk.LabelFrame(tab, text="授权信息", bg='#2c3e50', fg='#ecf0f1')
info_frame.pack(fill=tk.X, padx=20, pady=10)
tk.Label(info_frame, text="授权密钥:", bg='#2c3e50', fg='#ecf0f1').grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
self.license_entry = tk.Entry(info_frame, width=50)
self.license_entry.grid(row=0, column=1, padx=5, pady=5, sticky=tk.W)
generate_btn = tk.Button(info_frame, text="生成密钥", command=self.generate_license,
bg='#3498db', fg='white')
generate_btn.grid(row=0, column=2, padx=5, pady=5)
# 机器码输入
tk.Label(info_frame, text="机器码:", bg='#2c3e50', fg='#ecf0f1').grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
self.machine_id_var = tk.StringVar()
# 提供默认值作为示例
self.machine_id_var.set("输入机器码,如: 2A3B4C5D6E7F8G9H")
machine_entry = tk.Entry(info_frame, textvariable=self.machine_id_var, width=50, fg='#95a5a6')
machine_entry.grid(row=1, column=1, padx=5, pady=5, sticky=tk.W)
# 添加绑定当前机器按钮
bind_current_btn = tk.Button(info_frame, text="绑定当前机器", command=self.bind_current_machine,
bg='#9b59b6', fg='white')
bind_current_btn.grid(row=1, column=2, padx=5, pady=5)
tk.Label(info_frame, text="授权类型:", bg='#2c3e50', fg='#ecf0f1').grid(row=2, column=0, padx=5, pady=5, sticky=tk.W)
self.license_type = tk.StringVar(value="永久")
license_frame = tk.Frame(info_frame, bg='#2c3e50')
license_frame.grid(row=2, column=1, padx=5, pady=5, sticky=tk.W)
# 永久授权单选按钮
permanent_radio = tk.Radiobutton(license_frame, text="永久授权", variable=self.license_type,
value="永久", bg='#2c3e50', fg='#ecf0f1', selectcolor='#34495e')
permanent_radio.pack(side=tk.LEFT, padx=10)
# 试用期单选按钮
trial_radio = tk.Radiobutton(license_frame, text="试用期", variable=self.license_type,
value="试用期", bg='#2c3e50', fg='#ecf0f1', selectcolor='#34495e')
trial_radio.pack(side=tk.LEFT, padx=10)
# 试用期天数输入框
self.trial_days = tk.StringVar(value="3")
self.trial_days_entry = tk.Entry(license_frame, textvariable=self.trial_days, width=5, state=tk.NORMAL)
self.trial_days_entry.pack(side=tk.LEFT, padx=5)
# 添加天数标签
tk.Label(license_frame, text="天", bg='#2c3e50', fg='#ecf0f1').pack(side=tk.LEFT)
# 绑定授权类型改变事件
self.license_type.trace_add("write", self.update_license_type_ui)
# 授权功能区域
func_frame = tk.LabelFrame(tab, text="授权功能", bg='#2c3e50', fg='#ecf0f1')
func_frame.pack(fill=tk.X, padx=20, pady=10)
bind_btn = tk.Button(func_frame, text="绑定机器", command=self.bind_to_machine,
bg='#e67e22', fg='white', width=15)
bind_btn.grid(row=0, column=0, padx=10, pady=10)
embed_btn = tk.Button(func_frame, text="嵌入授权", command=self.embed_license,
bg='#1abc9c', fg='white', width=15)
embed_btn.grid(row=0, column=1, padx=10, pady=10)
check_btn = tk.Button(func_frame, text="检查授权", command=self.check_license,
bg='#f1c40f', fg='white', width=15)
check_btn.grid(row=0, column=2, padx=10, pady=10)
# 新增使用功能按钮
use_feature_btn = tk.Button(func_frame, text="使用功能", command=self.use_feature,
bg='#3498db', fg='white', width=15)
use_feature_btn.grid(row=0, column=3, padx=10, pady=10)
# 授权日志
log_frame = tk.LabelFrame(tab, text="授权日志", bg='#2c3e50', fg='#ecf0f1')
log_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
self.log_text = tk.Text(log_frame, height=10, bg='#34495e', fg='#ecf0f1', insertbackground='white')
self.log_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
self.log_text.insert(tk.END, "系统启动...\n")
self.log_text.insert(tk.END, "就绪\n")
self.log_text.config(state=tk.DISABLED)
def browse_encrypt_files(self):
file_paths = filedialog.askopenfilenames(
title="选择DLL文件",
filetypes=[("DLL Files", "*.dll"), ("All Files", "*.*")]
)
if file_paths:
self.encrypt_files = list(file_paths)
self.update_encrypt_file_list()
self.status_var.set(f"已添加 {len(file_paths)} 个加密文件")
def browse_obfuscate_files(self):
file_paths = filedialog.askopenfilenames(
title="选择DLL文件",
filetypes=[("DLL Files", "*.dll"), ("All Files", "*.*")]
)
if file_paths:
self.obfuscate_files = list(file_paths)
self.update_obfuscate_file_list()
self.status_var.set(f"已添加 {len(file_paths)} 个混淆文件")
def browse_encrypt_output_dir(self):
dir_path = filedialog.askdirectory(title="选择输出目录")
if dir_path:
self.encrypt_output_dir.set(dir_path)
def browse_obfuscate_output_dir(self):
dir_path = filedialog.askdirectory(title="选择输出目录")
if dir_path:
self.obfuscate_output_dir.set(dir_path)
def clear_encrypt_file_list(self):
self.encrypt_files = []
self.update_encrypt_file_list()
self.status_var.set("加密文件列表已清空")
def clear_obfuscate_file_list(self):
self.obfuscate_files = []
self.update_obfuscate_file_list()
self.status_var.set("混淆文件列表已清空")
def update_encrypt_file_list(self):
self.encrypt_file_listbox.config(state=tk.NORMAL)
self.encrypt_file_listbox.delete(1.0, tk.END)
if self.encrypt_files:
for i, file_path in enumerate(self.encrypt_files, 1):
self.encrypt_file_listbox.insert(tk.END, f"{i}. {file_path}\n")
else:
self.encrypt_file_listbox.insert(tk.END, "没有选择文件\n")
self.encrypt_file_listbox.insert(tk.END, "请点击'添加文件'按钮选择DLL文件")
self.encrypt_file_listbox.config(state=tk.DISABLED)
def update_obfuscate_file_list(self):
self.obfuscate_file_listbox.config(state=tk.NORMAL)
self.obfuscate_file_listbox.delete(1.0, tk.END)
if self.obfuscate_files:
for i, file_path in enumerate(self.obfuscate_files, 1):
self.obfuscate_file_listbox.insert(tk.END, f"{i}. {file_path}\n")
else:
self.obfuscate_file_listbox.insert(tk.END, "没有选择文件\n")
self.obfuscate_file_listbox.insert(tk.END, "请点击'添加文件'按钮选择DLL文件")
self.obfuscate_file_listbox.config(state=tk.DISABLED)
def simple_aes_encrypt(self, data, key):
"""简单的AES加密实现"""
key_hash = hashlib.sha256(key).digest()
iv = os.urandom(16)
cipher = hashlib.pbkdf2_hmac('sha256', key_hash, iv, 100000, dklen=32)
encrypted = bytearray()
for i in range(len(data)):
encrypted.append(data[i] ^ cipher[i % len(cipher)])
return iv + bytes(encrypted)
def encrypt_files(self):
if not self.encrypt_files:
messagebox.showerror("错误", "请先选择至少一个DLL文件")
return
output_dir = self.encrypt_output_dir.get()
if not output_dir:
messagebox.showerror("错误", "请指定输出目录")
return
# 确保输出目录存在
if not os.path.exists(output_dir):
os.makedirs(output_dir)
try:
# 创建加密子目录
encrypted_dir = os.path.join(output_dir, "encrypted")
if not os.path.exists(encrypted_dir):
os.makedirs(encrypted_dir)
encryption_method = self.encryption_level.get()
success_count = 0
self.encrypt_status.config(text="批量加密中...", fg='#f39c12')
self.root.update()
for file_path in self.encrypt_files:
try:
# 获取原文件名
base_name = os.path.basename(file_path)
# 生成输出路径 (在encrypted子目录下,使用原文件名)
output_path = os.path.join(encrypted_dir, base_name)
# 生成加密密钥
key = os.urandom(32)
# 读取文件内容
with open(file_path, 'rb') as f:
data = f.read()
# 加密数据
encrypted_data = self.simple_aes_encrypt(data, key)
# 保存加密后的文件
with open(output_path, 'wb') as f:
f.write(encrypted_data)
# 保存密钥
key_file = os.path.join(encrypted_dir, f"{base_name}.key")
with open(key_file, 'wb') as f:
f.write(key)
success_count += 1
self.log_action(f"已加密: {base_name} -> {output_path}")
except Exception as e:
self.log_action(f"加密失败 {os.path.basename(file_path)}: {str(e)}")
self.encrypt_status.config(
text=f"批量加密完成!成功: {success_count}/{len(self.encrypt_files)} 个文件",
fg='#2ecc71' if success_count > 0 else '#e74c3c'
)
self.status_var.set(
f"批量加密完成 - 成功: {success_count}/{len(self.encrypt_files)}"
)
if success_count > 0:
messagebox.showinfo(
"批量加密完成",
f"成功加密 {success_count} 个文件\n输出目录: {encrypted_dir}"
)
else:
messagebox.showerror(
"加密失败",
"所有文件加密失败,请查看日志"
)
except Exception as e:
messagebox.showerror("加密错误", str(e))
self.encrypt_status.config(text="批量加密失败", fg='#e74c3c')
def update_preview(self, event=None):
"""根据混淆设置更新预览"""
method = self.obf_method.get()
strength = self.obf_strength.get()
self.preview_text.config(state=tk.NORMAL)
self.preview_text.delete(1.0, tk.END)
# 原始代码示例
self.preview_text.insert(tk.END, "// 原始代码示例\n")
self.preview_text.insert(tk.END, "public int Calculate(int a, int b) {\n")
self.preview_text.insert(tk.END, " return a * b + 10;\n")
self.preview_text.insert(tk.END, "}\n\n")
# 混淆后代码示例
self.preview_text.insert(tk.END, f"// 混淆后代码示例 ({method}, 强度: {strength}/10)\n")
# 根据混淆方法和强度生成不同的混淆代码
if method == "名称混淆":
self.preview_text.insert(tk.END, f"public int {self.generate_obf_name('Calculate', strength)}(int {self.generate_obf_name('a', strength)}, int {self.generate_obf_name('b', strength)}) {{\n")
self.preview_text.insert(tk.END, f" return {self.generate_obf_name('a', strength)} * {self.generate_obf_name('b', strength)} + 10;\n")
self.preview_text.insert(tk.END, "}\n")
elif method == "控制流混淆":
self.preview_text.insert(tk.END, "public int Calculate(int a, int b) {\n")
self.preview_text.insert(tk.END, " int result;\n")
self.preview_text.insert(tk.END, " if (a > 0) {\n")
if strength > 5:
self.preview_text.insert(tk.END, " int temp = b;\n")
self.preview_text.insert(tk.END, " for (int i = 0; i < 1; i++) {\n")
self.preview_text.insert(tk.END, " temp = a * temp;\n")
self.preview_text.insert(tk.END, " }\n")
self.preview_text.insert(tk.END, " result = temp + 10;\n")
else:
self.preview_text.insert(tk.END, " result = a * b + 10;\n")
self.preview_text.insert(tk.END, " } else {\n")
self.preview_text.insert(tk.END, " result = b * a + 10;\n")
self.preview_text.insert(tk.END, " }\n")
self.preview_text.insert(tk.END, " return result;\n")
self.preview_text.insert(tk.END, "}\n")
elif method == "字符串加密":
self.preview_text.insert(tk.END, "public int Calculate(int a, int b) {\n")
self.preview_text.insert(tk.END, " // 字符串被加密\n")
self.preview_text.insert(tk.END, " string debugInfo = DecryptString(\"0x4A3F2B1C\");\n")
self.preview_text.insert(tk.END, " return a * b + 10;\n")
self.preview_text.insert(tk.END, "}\n")
elif method == "指令替换":
self.preview_text.insert(tk.END, "public int Calculate(int a, int b) {\n")
self.preview_text.insert(tk.END, " // 指令被替换\n")
if strength > 7:
self.preview_text.insert(tk.END, " int result = (a << 2) - a + b * 3 + 10;\n")
else:
self.preview_text.insert(tk.END, " int result = a * b + 10;\n")
self.preview_text.insert(tk.END, " return result;\n")
self.preview_text.insert(tk.END, "}\n")
else: # 全混淆模式
self.preview_text.insert(tk.END, f"public int {self.generate_obf_name('Calculate', strength)}(int {self.generate_obf_name('a', strength)}, int {self.generate_obf_name('b', strength)}) {{\n")
self.preview_text.insert(tk.END, " // 全混淆模式\n")
self.preview_text.insert(tk.END, " int result;\n")
self.preview_text.insert(tk.END, " if (a > 0) {\n")
self.preview_text.insert(tk.END, " result = a * b + 10;\n")
self.preview_text.insert(tk.END, " } else {\n")
self.preview_text.insert(tk.END, " result = b * a + 10;\n")
self.preview_text.insert(tk.END, " }\n")
self.preview_text.insert(tk.END, " // 添加垃圾指令\n")
self.preview_text.insert(tk.END, " int unused = 0;\n")
self.preview_text.insert(tk.END, " for (int i = 0; i < 10; i++) {\n")
self.preview_text.insert(tk.END, " unused += i;\n")
self.preview_text.insert(tk.END, " }\n")
self.preview_text.insert(tk.END, " return result;\n")
self.preview_text.insert(tk.END, "}\n")
self.preview_text.config(state=tk.DISABLED)
def generate_obf_name(self, base_name, strength):
"""生成混淆后的名称"""
# 根据混淆强度增加名称的复杂度
prefix = "obf_" if strength < 5 else "mangled_"
suffix = f"_{random.randint(100, 999)}" if strength > 3 else ""
# 高混淆强度使用随机字符串
if strength > 7:
return ''.join(random.choices(string.ascii_letters, k=8))
return f"{prefix}{base_name}{suffix}"
def obfuscate_files(self):
if not self.obfuscate_files:
messagebox.showerror("错误", "请先选择至少一个DLL文件")
return
output_dir = self.obfuscate_output_dir.get()
if not output_dir:
messagebox.showerror("错误", "请指定输出目录")
return
# 确保输出目录存在
if not os.path.exists(output_dir):
os.makedirs(output_dir)
try:
# 获取混淆设置
method = self.obf_method.get()
strength = self.obf_strength.get()
success_count = 0
# 创建结果显示窗口
result_window = tk.Toplevel(self.root)
result_window.title("混淆处理结果")
result_window.geometry("400x300")
result_window.resizable(False, False)
result_window.transient(self.root)
result_window.grab_set()
# 创建结果显示文本区域
result_frame = tk.Frame(result_window)
result_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
result_label = tk.Label(result_frame, text="批量混淆完成", font=("Arial", 14, "bold"))
result_label.pack(pady=10)
result_text = scrolledtext.ScrolledText(result_frame, height=10)
result_text.pack(fill=tk.BOTH, expand=True)
# 添加处理结果
result_text.insert(tk.END, f"成功处理: 0/{len(self.obfuscate_files)} 个文件\n")
result_text.insert(tk.END, "------------------------------------\n")
result_text.see(tk.END)
result_text.config(state=tk.DISABLED)
# 处理文件
for idx, file_path in enumerate(self.obfuscate_files):
try:
# 获取原文件名
base_name = os.path.basename(file_path)
# 生成输出路径 (使用原文件名)
output_path = os.path.join(output_dir, base_name)
# 模拟混淆过程
self.log_action(f"开始混淆: {base_name}")
self.log_action(f"混淆方法: {method}, 强度: {strength}/10")
# 这里应该是实际的混淆代码
# 为了演示,我们只是复制文件并添加日志
shutil.copy(file_path, output_path)
self.log_action(f"混淆完成! 输出文件: {output_path}")
success_count += 1
# 更新结果窗口
result_text.config(state=tk.NORMAL)
result_text.insert(tk.END, f"成功: {base_name}\n")
result_text.see(tk.END)
result_text.config(state=tk.DISABLED)
result_text.update()
except Exception as e:
self.log_action(f"混淆失败 {base_name}: {str(e)}")
# 更新结果窗口
result_text.config(state=tk.NORMAL)
result_text.insert(tk.END, f"失败: {base_name} - {str(e)}\n")
result_text.see(tk.END)
result_text.config(state=tk.DISABLED)
result_text.update()
# 更新结果标题
result_label.config(text=f"批量混淆完成! 成功: {success_count}/{len(self.obfuscate_files)}")
# 添加确定按钮
ok_btn = tk.Button(result_window, text="确定", width=10, command=result_window.destroy)
ok_btn.pack(pady=10)
self.status_var.set(f"混淆完成: {success_count}/{len(self.obfuscate_files)}")
self.log_action(f"批量混淆完成! 成功处理 {success_count}/{len(self.obfuscate_files)} 个文件")
except Exception as e:
messagebox.showerror("混淆错误", str(e))
self.log_action(f"批量混淆失败: {str(e)}")
def generate_license(self):
key = ''.join(random.choices(string.ascii_uppercase + string.digits, k=25))
key = '-'.join([key[i:i+5] for i in range(0, len(key), 5)])
self.license_key = key
self.license_entry.delete(0, tk.END)
self.license_entry.insert(0, key)
self.activation_date = time.time()
license_type = self.license_type.get()
self.log_action(f"已生成{license_type}授权密钥: {key}")
def get_machine_id(self):
"""获取当前机器标识符"""
try:
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Cryptography")
machine_guid, _ = winreg.QueryValueEx(key, "MachineGuid")
winreg.CloseKey(key)
return hashlib.sha256(machine_guid.encode()).hexdigest()[:16].upper()
except Exception:
return hashlib.sha256(b"fallback_machine_id").hexdigest()[:16].upper()
def bind_current_machine(self):
"""绑定当前机器"""
machine_id = self.get_machine_id()
self.machine_id_var.set(machine_id)
self.machine_id = machine_id # 保存机器码
self.log_action(f"已获取当前机器码: {machine_id}")
def update_license_type_ui(self, *args):
"""根据选择的授权类型更新UI"""
license_type = self.license_type.get()
if license_type == "试用期":
self.trial_days_entry.config(state=tk.NORMAL)
else:
self.trial_days_entry.config(state=tk.NORMAL)
def bind_to_machine(self):
if not self.license_key:
messagebox.showerror("错误", "请先生成授权密钥")
return
machine_id = self.machine_id_var.get()
if not machine_id or machine_id == "输入机器码,如: 2A3B4C5D6E7F8G9H":
messagebox.showerror("错误", "请输入有效的机器码")
return
license_type = self.license_type.get()
self.activation_date = time.time()
# 重置使用次数
self.usage_count = 0
# 获取授权设置
if license_type == "试用期":
try:
self.time_limit_days = int(self.trial_days.get())
if self.time_limit_days < 1:
messagebox.showerror("错误", "试用期天数必须大于0")
return
self.expiry_date = self.activation_date + self.time_limit_days * 24 * 3600
except:
messagebox.showerror("错误", "请输入有效的试用期天数")
return
else: # 永久授权
self.expiry_date = None
self.time_limit_days = 0
self.permanent_license_shown = False # 重置永久授权显示标记
self.machine_id = machine_id # 保存机器码
self.log_action(f"授权密钥已绑定到机器: {machine_id}")
self.log_action(f"授权类型: {license_type}")
if license_type == "试用期":
expiry_date_str = time.strftime("%Y-%m-%d %H:%M", time.localtime(self.expiry_date))
message = f"试用期授权已绑定\n机器码: {machine_id}\n激活时间: {time.strftime('%Y-%m-%d %H:%M', time.localtime(self.activation_date))}\n到期时间: {expiry_date_str}\n有效期: {self.time_limit_days}天"
else:
message = f"永久授权已绑定\n机器码: {machine_id}\n激活时间: {time.strftime('%Y-%m-%d %H:%M', time.localtime(self.activation_date))}"
messagebox.showinfo("成功", message)
def generate_license_module(self, output_dir):
"""生成授权检查模块的Python代码"""
license_code = f'''# -*- coding: utf-8 -*-
import ctypes
import os
import sys
import time
import hashlib
import winreg
class LicenseManager:
def __init__(self):
self.license_key = "{self.license_key}"
self.machine_id = "{self.machine_id}"
self.license_type = "{self.license_type.get()}"
self.activation_date = {self.activation_date}
self.expiry_date = {self.expiry_date if self.expiry_date else 'None'}
# CAD运行时自动检查授权
self.check_license_on_cad_start()
def get_current_machine_id(self):
"""获取当前机器标识符"""
try:
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\\\\Microsoft\\\\Cryptography")
machine_guid, _ = winreg.QueryValueEx(key, "MachineGuid")
winreg.CloseKey(key)
return hashlib.sha256(machine_guid.encode()).hexdigest()[:16].upper()
except Exception:
return hashlib.sha256(b"fallback_machine_id").hexdigest()[:16].upper()
def check_license_on_cad_start(self):
"""CAD启动时自动检查授权"""
current_machine_id = self.get_current_machine_id()
# 检查机器码是否匹配
if current_machine_id != self.machine_id:
self.show_message("授权错误", "机器码不匹配!\\n当前机器: " + current_machine_id)
return False
# 检查试用期是否过期
if self.license_type == "试用期":
current_time = time.time()
if current_time > self.expiry_date:
self.show_message("授权过期", "试用期已结束!")
return False
# 显示授权信息
self.show_license_info()
return True
def show_license_info(self):
"""显示授权信息"""
if self.license_type == "试用期":
# 计算剩余时间
current_time = time.time()
remaining_seconds = self.expiry_date - current_time
remaining_days = int(remaining_seconds // (24 * 3600))
remaining_seconds %= (24 * 3600)
remaining_hours = int(remaining_seconds // 3600)
remaining_seconds %= 3600
remaining_minutes = int(remaining_seconds // 60)
message = (
"试用期授权已激活\\n"
f"机器码: {self.machine_id}\\n"
f"激活时间: {time.strftime('%Y-%m-%d %H:%M', time.localtime(self.activation_date))}\\n"
f"到期时间: {time.strftime('%Y-%m-%d %H:%M', time.localtime(self.expiry_date))}\\n"
f"剩余时间: {remaining_days}天 {remaining_hours}小时 {remaining_minutes}分钟"
)
self.show_message("授权信息", message)
else:
message = (
"永久授权已激活\\n"
f"机器码: {self.machine_id}\\n"
f"激活时间: {time.strftime('%Y-%m-%d %H:%M', time.localtime(self.activation_date))}"
)
self.show_message("授权信息", message)
def show_message(self, title, message):
"""在CAD中显示消息框"""
# 使用ctypes创建Windows消息框
ctypes.windll.user32.MessageBoxW(0, message, title, 0)
# CAD加载时自动执行
if __name__ == "__main__":
license_mgr = LicenseManager()
'''
# 保存授权模块
license_path = os.path.join(output_dir, "dll_license_checker.py")
with open(license_path, 'w', encoding='utf-8') as f:
f.write(license_code)
return license_path
def embed_license(self):
if not self.license_key:
messagebox.showerror("错误", "请先生成授权密钥")
return
if not self.obfuscate_files:
messagebox.showerror("错误", "请先选择要嵌入授权的DLL文件")
return
try:
# 获取输出目录
output_dir = self.obfuscate_output_dir.get()
if not output_dir:
messagebox.showerror("错误", "请指定输出目录")
return
# 确保输出目录存在
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# 生成授权检查模块
license_module_path = self.generate_license_module(output_dir)
# 初始化剩余天数
remaining_days = 0
# 模拟嵌入授权信息
license_type = self.license_type.get()
machine_id = self.machine_id
self.log_action("正在将授权信息嵌入DLL...")
self.log_action(f"授权模块已生成: {os.path.basename(license_module_path)}")
# 在试用期情况下,正确计算剩余天数
if license_type == "试用期":
# 确保有到期时间
if self.expiry_date is None:
self.log_action("错误:试用期授权,但到期时间为空!")
messagebox.showerror("错误", "试用期授权,但到期时间为空!")
return
# 计算剩余时间
current_time = time.time()
remaining_seconds = self.expiry_date - current_time
# 如果剩余秒数小于0,则按0处理
if remaining_seconds < 0:
remaining_seconds = 0
# 计算剩余天数
remaining_days = int(remaining_seconds // (24 * 3600))
self.log_action(f"授权类型: {license_type}, 天数: {self.time_limit_days}, 剩余天数: {remaining_days}")
else:
self.log_action(f"授权类型: {license_type}")
if self.activation_date:
activation_time = time.strftime('%Y-%m-%d %H:%M', time.localtime(self.activation_date))
self.log_action(f"激活时间: {activation_time}")
self.log_action(f"机器码: {machine_id}")
# 为每个文件嵌入授权信息
for file_path in self.obfuscate_files:
base_name = os.path.basename(file_path)
# 在实际应用中,这里应该修改DLL文件嵌入授权信息
# 为演示目的,我们创建一个同名的.lic文件
lic_file = os.path.join(output_dir, f"{base_name}.lic")
with open(lic_file, 'w') as f:
f.write(f"LicenseKey: {self.license_key}\n")
f.write(f"MachineID: {machine_id}\n")
f.write(f"Type: {license_type}\n")
f.write(f"Activation: {self.activation_date}\n")
if self.expiry_date:
f.write(f"Expiry: {self.expiry_date}\n")
self.log_action(f"已为 {base_name} 创建授权文件: {os.path.basename(lic_file)}")
self.log_action("授权信息嵌入完成!")
messagebox.showinfo(
"成功",
f"授权信息已成功嵌入 {len(self.obfuscate_files)} 个DLL文件\n"
f"授权检查模块: dll_license_checker.py\n"
"在CAD中加载DLL时会自动显示授权信息"
)
except Exception as e:
messagebox.showerror("嵌入错误", str(e))
def use_feature(self):
"""使用功能(消耗使用次数)"""
if not self.license_key:
messagebox.showerror("错误", "请先生成授权密钥")
return
if not self.activation_date:
messagebox.showwarning("警告", "授权尚未激活,请先绑定机器")
return
license_type = self.license_type.get()
# 检查试用期是否过期
if license_type == "试用期":
current_time = time.time()
if current_time > self.expiry_date:
messagebox.showerror("错误", "试用期已过期!")
return
# 增加使用次数
self.usage_count += 1
# 显示授权信息弹窗
self.show_license_reminder()
self.log_action(f"功能使用成功!使用次数: {self.usage_count}")
messagebox.showinfo("成功", "功能使用成功!")
def show_license_reminder(self):
"""显示授权信息弹窗"""
license_type = self.license_type.get()
if license_type == "试用期":
# 计算剩余时间
current_time = time.time()
remaining_seconds = self.expiry_date - current_time
# 计算剩余天数、小时和分钟
remaining_days = int(remaining_seconds // (24 * 3600))
remaining_seconds %= (24 * 3600)
remaining_hours = int(remaining_seconds // 3600)
remaining_seconds %= 3600
remaining_minutes = int(remaining_seconds // 60)
# 创建弹窗
reminder = tk.Toplevel(self.root)
reminder.title("授权信息")
reminder.geometry("400x300")
reminder.resizable(False, False)
reminder.transient(self.root)
reminder.grab_set()
# 设置背景颜色
bg_color = '#f9f9f9'
header_color = '#3498db'
text_color = '#2c3e50'
warning_color = '#e74c3c'
reminder.configure(bg=bg_color)
# 创建标题
title_label = tk.Label(reminder, text="试用期授权", font=("Arial", 16, "bold"),
bg=header_color, fg='white', padx=10, pady=10)
title_label.pack(fill=tk.X)
# 创建内容区域
content_frame = tk.Frame(reminder, bg=bg_color, padx=20, pady=20)
content_frame.pack(fill=tk.BOTH, expand=True)
# 显示机器码
machine_label = tk.Label(content_frame, text=f"机器码: {self.machine_id}",
bg=bg_color, fg=text_color, anchor='w', justify='left')
machine_label.pack(fill=tk.X, pady=5)
# 显示激活时间
activation_label = tk.Label(content_frame,
text=f"激活时间: {time.strftime('%Y-%m-%d %H:%M', time.localtime(self.activation_date))}",
bg=bg_color, fg=text_color, anchor='w', justify='left')
activation_label.pack(fill=tk.X, pady=5)
# 显示到期时间
expiry_label = tk.Label(content_frame,
text=f"到期时间: {time.strftime('%Y-%m-%d %H:%M', time.localtime(self.expiry_date))}",
bg=bg_color, fg=text_color, anchor='w', justify='left')
expiry_label.pack(fill=tk.X, pady=5)
# 显示剩余时间
remaining_label = tk.Label(content_frame,
text=f"剩余时间: {remaining_days}天 {remaining_hours}小时 {remaining_minutes}分钟",
bg=bg_color, fg=warning_color, font=("Arial", 12, "bold"),
anchor='w', justify='left')
remaining_label.pack(fill=tk.X, pady=10)
# 添加确定按钮
ok_btn = tk.Button(reminder, text="确定", width=10,
command=reminder.destroy, bg='#3498db', fg='white')
ok_btn.pack(pady=10)
elif license_type == "永久" and not self.permanent_license_shown:
# 创建永久授权弹窗
reminder = tk.Toplevel(self.root)
reminder.title("授权信息")
reminder.geometry("400x300")
reminder.resizable(False, False)
reminder.transient(self.root)
reminder.grab_set()
# 设置背景颜色
bg_color = '#f9f9f9'
header_color = '#2ecc71'
text_color = '#2c3e50'
reminder.configure(bg=bg_color)
# 创建标题
title_label = tk.Label(reminder, text="永久授权", font=("Arial", 16, "bold"),
bg=header_color, fg='white', padx=10, pady=10)
title_label.pack(fill=tk.X)
# 创建内容区域
content_frame = tk.Frame(reminder, bg=bg_color, padx=20, pady=20)
content_frame.pack(fill=tk.BOTH, expand=True)
# 添加成功图标(使用文本模拟)
success_icon = tk.Label(content_frame, text="✓", font=("Arial", 48),
fg=header_color, bg=bg_color)
success_icon.pack(pady=10)
# 显示成功消息
success_label = tk.Label(content_frame, text="永久授权已激活",
font=("Arial", 14, "bold"), bg=bg_color, fg=text_color)
success_label.pack(pady=5)
# 显示机器码
machine_label = tk.Label(content_frame, text=f"机器码: {self.machine_id}",
bg=bg_color, fg=text_color)
machine_label.pack(pady=5)
# 显示激活时间
activation_label = tk.Label(content_frame,
text=f"激活时间: {time.strftime('%Y-%m-%d %H:%M', time.localtime(self.activation_date))}",
bg=bg_color, fg=text_color)
activation_label.pack(pady=5)
# 添加确定按钮
ok_btn = tk.Button(reminder, text="确定", width=10,
command=reminder.destroy, bg=header_color, fg='white')
ok_btn.pack(pady=10)
# 标记永久授权已显示
self.permanent_license_shown = True
def check_license(self):
if not self.license_key:
messagebox.showerror("错误", "请先生成授权密钥")
return
if not self.activation_date:
messagebox.showwarning("警告", "授权尚未激活,请先绑定机器")
return
# 获取当前时间
current_time = time.time()
license_type = self.license_type.get()
activation_time_str = time.strftime('%Y-%m-%d %H:%M', time.localtime(self.activation_date))
self.log_action("正在检查授权状态...")
self.log_action(f"授权密钥: {self.license_key}")
self.log_action(f"授权类型: {license_type}")
self.log_action(f"激活时间: {activation_time_str}")
# 根据授权类型检查状态
if license_type == "试用期":
# 计算剩余时间
expiry_time = self.expiry_date
remaining_seconds = expiry_time - current_time
if remaining_seconds <= 0:
status = "已过期"
self.log_action("授权状态: 已过期")
message = f"试用期授权已过期!"
else:
# 计算剩余天数、小时和分钟
remaining_days = int(remaining_seconds // (24 * 3600))
remaining_seconds %= (24 * 3600)
remaining_hours = int(remaining_seconds // 3600)
remaining_seconds %= 3600
remaining_minutes = int(remaining_seconds // 60)
status = f"有效 (剩余 {remaining_days}天 {remaining_hours}小时 {remaining_minutes}分钟)"
self.log_action(f"授权状态: {status}")
expiry_date_str = time.strftime("%Y-%m-%d %H:%M", time.localtime(expiry_time))
# 显示总天数
total_days = self.time_limit_days
message = f"试用期授权有效\n激活时间: {activation_time_str}\n到期时间: {expiry_date_str}\n总天数: {total_days}天\n剩余时间: {remaining_days}天 {remaining_hours}小时 {remaining_minutes}分钟"
else: # 永久授权
status = "永久有效"
self.log_action("授权状态: 永久有效")
message = "永久授权有效\n激活时间: " + activation_time_str
# 显示检查结果
messagebox.showinfo("授权检查", message)
def log_action(self, message):
self.log_text.config(state=tk.NORMAL)
self.log_text.insert(tk.END, message + "\n")
self.log_text.see(tk.END)
self.log_text.config(state=tk.DISABLED)
if __name__ == "__main__":
root = tk.Tk()
app = DLLProtectorApp(root)
root.mainloop()
”授权管理”中点击”嵌入授权”显示失败
最新发布