[Asm] 纯文本查看 复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
注册表监视工具 - 精准程序监控版(笔记本优化版)
监视指定程序从启动到运行过程中的所有注册表修改
"""
import sys
import os
import threading
import time
import subprocess
from datetime import datetime
from typing import Dict, List, Tuple
import ctypes
from ctypes import wintypes
try:
import tkinter as tk
from tkinter import ttk, messagebox, filedialog, scrolledtext
import winreg
import psutil
except ImportError:
print("请先安装 psutil: pip install psutil")
sys.exit(1)
# 注册表根键映射
ROOT_KEYS = {
"HKEY_CLASSES_ROOT": winreg.HKEY_CLASSES_ROOT,
"HKEY_CURRENT_USER": winreg.HKEY_CURRENT_USER,
"HKEY_LOCAL_MACHINE": winreg.HKEY_LOCAL_MACHINE,
"HKEY_USERS": winreg.HKEY_USERS,
"HKEY_CURRENT_CONFIG": winreg.HKEY_CURRENT_CONFIG,
}
VALUE_TYPES = {
winreg.REG_SZ: "REG_SZ",
winreg.REG_EXPAND_SZ: "REG_EXPAND_SZ",
winreg.REG_BINARY: "REG_BINARY",
winreg.REG_MULTI_SZ: "REG_MULTI_SZ",
winreg.REG_DWORD: "REG_DWORD",
winreg.REG_QWORD: "REG_QWORD",
}
# 系统进程列表(需要过滤的)
SYSTEM_PROCESSES = [
"System", "System Idle Process", "svchost.exe", "explorer.exe", "csrss.exe",
"winlogon.exe", "services.exe", "lsass.exe", "wininit.exe", "spoolsv.exe",
"taskhost.exe", "dwm.exe", "SearchIndexer.exe", "WmiPrvSE.exe", "conhost.exe",
"ctfmon.exe", "sihost.exe", "RuntimeBroker.exe", "ShellExperienceHost.exe",
"SearchUI.exe", "StartMenuExperienceHost.exe", "TextInputHost.exe", "cmd.exe"
]
class RegistrySnapshot:
"""注册表快照类"""
def __init__(self):
self.data = {}
def add_key(self, key_path: str, value_name: str, value, value_type: int):
if key_path not in self.data:
self.data[key_path] = {}
self.data[key_path][value_name] = (value, value_type)
def compare(self, other: 'RegistrySnapshot') -> List[Dict]:
"""比较两个快照"""
changes = []
# 检查删除和修改
for key_path, values in self.data.items():
if key_path not in other.data:
for value_name, (val, val_type) in values.items():
changes.append({
'type': 'delete',
'key': key_path,
'value': value_name if value_name else '(默认)',
'old_value': self._format_value(val),
'new_value': None,
'value_type': VALUE_TYPES.get(val_type, f'Type_{val_type}')
})
else:
other_values = other.data[key_path]
for value_name, (old_val, old_type) in values.items():
if value_name not in other_values:
changes.append({
'type': 'delete',
'key': key_path,
'value': value_name if value_name else '(默认)',
'old_value': self._format_value(old_val),
'new_value': None,
'value_type': VALUE_TYPES.get(old_type, f'Type_{old_type}')
})
else:
new_val, new_type = other_values[value_name]
if str(old_val) != str(new_val) or old_type != new_type:
changes.append({
'type': 'modify',
'key': key_path,
'value': value_name if value_name else '(默认)',
'old_value': self._format_value(old_val),
'new_value': self._format_value(new_val),
'value_type': VALUE_TYPES.get(old_type, f'Type_{old_type}')
})
# 检查新增
for key_path, values in other.data.items():
if key_path not in self.data:
for value_name, (new_val, new_type) in values.items():
changes.append({
'type': 'create',
'key': key_path,
'value': value_name if value_name else '(默认)',
'old_value': None,
'new_value': self._format_value(new_val),
'value_type': VALUE_TYPES.get(new_type, f'Type_{new_type}')
})
else:
self_values = self.data[key_path]
for value_name, (new_val, new_type) in values.items():
if value_name not in self_values:
changes.append({
'type': 'create',
'key': key_path,
'value': value_name if value_name else '(默认)',
'old_value': None,
'new_value': self._format_value(new_val),
'value_type': VALUE_TYPES.get(new_type, f'Type_{new_type}')
})
return changes
def _format_value(self, value):
"""格式化值用于显示"""
if isinstance(value, bytes):
if len(value) > 64:
return value.hex()[:64] + "..."
return value.hex()
elif isinstance(value, list):
if len(value) > 5:
return "|".join(str(v) for v in value[:5]) + "..."
return "|".join(str(v) for v in value)
else:
return str(value)[:200]
class RegistryScanner:
"""注册表扫描器"""
@staticmethod
def scan_registry(selected_keys: List[str], callback=None) -> RegistrySnapshot:
"""扫描注册表"""
snapshot = RegistrySnapshot()
for root_name in selected_keys:
if root_name not in ROOT_KEYS:
continue
if callback:
callback(f"正在扫描 {root_name}...")
try:
RegistryScanner._scan_key(ROOT_KEYS[root_name], "", root_name, snapshot)
except Exception as e:
print(f"扫描 {root_name} 出错: {e}")
return snapshot
@staticmethod
def _scan_key(root_handle, sub_key: str, root_name: str, snapshot: RegistrySnapshot):
"""递归扫描注册表键"""
key_path = f"{root_name}\\{sub_key}" if sub_key else root_name
try:
key = winreg.OpenKey(root_handle, sub_key, 0, winreg.KEY_READ)
# 读取值
index = 0
while True:
try:
value_name, value_data, value_type = winreg.EnumValue(key, index)
if value_type == winreg.REG_BINARY:
if isinstance(value_data, bytes):
value_data = value_data
elif value_type == winreg.REG_MULTI_SZ:
if value_data:
value_data = value_data
snapshot.add_key(key_path, value_name, value_data, value_type)
index += 1
except OSError:
break
# 递归扫描子键
index = 0
while True:
try:
sub_key_name = winreg.EnumKey(key, index)
new_sub_key = f"{sub_key}\\{sub_key_name}" if sub_key else sub_key_name
RegistryScanner._scan_key(root_handle, new_sub_key, root_name, snapshot)
index += 1
except OSError:
break
winreg.CloseKey(key)
except PermissionError:
pass
except Exception:
pass
class RegistryMonitorApp:
"""主应用程序"""
def __init__(self, root):
self.root = root
self.root.title("注册表监控工具 - 精准追踪器")
self.root.geometry("1100x600") # 缩小尺寸,适合笔记本
# 颜色配置
self.bg_color = "#1e1e1e"
self.fg_color = "#ffffff"
# 监控状态
self.before_snapshot = None
self.after_snapshot = None
self.selected_program = None
self.target_process_name = None
self.target_process_pid = None
self.setup_ui()
def setup_ui(self):
"""设置界面"""
self.root.configure(bg=self.bg_color)
# 主框架
main_frame = tk.Frame(self.root, bg=self.bg_color)
main_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# 左侧控制面板(宽度减小)
left_frame = tk.Frame(main_frame, bg=self.bg_color, width=320)
left_frame.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 5))
left_frame.pack_propagate(False)
# 程序选择区域
program_group = tk.LabelFrame(left_frame, text="1. 选择要监控的程序",
bg=self.bg_color, fg=self.fg_color,
font=("Arial", 10, "bold"))
program_group.pack(fill=tk.X, pady=(0, 5))
tk.Label(program_group, text="程序路径:", bg=self.bg_color, fg=self.fg_color, font=("Arial", 9)).grid(row=0, column=0, padx=3, pady=3, sticky=tk.W)
self.program_path = tk.Entry(program_group, width=28, bg="#2d2d2d", fg=self.fg_color,
insertbackground="white", font=("Arial", 8))
self.program_path.grid(row=0, column=1, padx=3, pady=3)
self.btn_browse = tk.Button(program_group, text="浏览", command=self.browse_program,
bg="#3c3c3c", fg=self.fg_color, relief=tk.FLAT, font=("Arial", 8))
self.btn_browse.grid(row=0, column=2, padx=3, pady=3)
tk.Label(program_group, text="程序参数:", bg=self.bg_color, fg=self.fg_color, font=("Arial", 9)).grid(row=1, column=0, padx=3, pady=3, sticky=tk.W)
self.program_args = tk.Entry(program_group, width=28, bg="#2d2d2d", fg=self.fg_color,
insertbackground="white", font=("Arial", 8))
self.program_args.grid(row=1, column=1, columnspan=2, padx=3, pady=3, sticky=tk.W+tk.E)
# 过滤选项
filter_group = tk.LabelFrame(left_frame, text="过滤选项",
bg=self.bg_color, fg=self.fg_color,
font=("Arial", 10, "bold"))
filter_group.pack(fill=tk.X, pady=(0, 5))
self.filter_system = tk.BooleanVar(value=True)
tk.Checkbutton(filter_group, text="过滤系统进程", variable=self.filter_system,
bg=self.bg_color, fg=self.fg_color, selectcolor=self.bg_color,
font=("Arial", 9)).pack(anchor=tk.W, padx=5, pady=2)
self.filter_common = tk.BooleanVar(value=True)
tk.Checkbutton(filter_group, text="过滤常见系统操作", variable=self.filter_common,
bg=self.bg_color, fg=self.fg_color, selectcolor=self.bg_color,
font=("Arial", 9)).pack(anchor=tk.W, padx=5, pady=2)
# 注册表区域选择
registry_group = tk.LabelFrame(left_frame, text="2. 监控的注册表区域",
bg=self.bg_color, fg=self.fg_color,
font=("Arial", 10, "bold"))
registry_group.pack(fill=tk.X, pady=(0, 5))
self.registry_vars = {}
registry_keys = [
"HKEY_CLASSES_ROOT",
"HKEY_CURRENT_USER",
"HKEY_LOCAL_MACHINE",
"HKEY_USERS",
"HKEY_CURRENT_CONFIG"
]
for i, key in enumerate(registry_keys):
var = tk.BooleanVar(value=(key == "HKEY_CURRENT_USER" or key == "HKEY_LOCAL_MACHINE"))
self.registry_vars[key] = var
cb = tk.Checkbutton(registry_group, text=key, variable=var,
bg=self.bg_color, fg=self.fg_color, selectcolor=self.bg_color,
font=("Arial", 8))
cb.grid(row=i, column=0, padx=5, pady=1, sticky=tk.W)
# 控制按钮
control_group = tk.LabelFrame(left_frame, text="3. 开始监控",
bg=self.bg_color, fg=self.fg_color,
font=("Arial", 10, "bold"))
control_group.pack(fill=tk.X, pady=(0, 5))
self.btn_step1 = tk.Button(control_group, text="步骤1: 创建监控前快照",
command=self.create_before_snapshot,
bg="#0d7377", fg=self.fg_color, relief=tk.FLAT,
height=1, font=("Arial", 9))
self.btn_step1.pack(fill=tk.X, padx=5, pady=3)
self.btn_step2 = tk.Button(control_group, text="步骤2: 启动程序",
command=self.start_program,
bg="#4caf50", fg=self.fg_color, relief=tk.FLAT,
height=1, font=("Arial", 9), state=tk.DISABLED)
self.btn_step2.pack(fill=tk.X, padx=5, pady=3)
self.btn_step3 = tk.Button(control_group, text="步骤3: 对比注册表变化",
command=self.create_after_snapshot,
bg="#ff9800", fg=self.fg_color, relief=tk.FLAT,
height=1, font=("Arial", 9), state=tk.DISABLED)
self.btn_step3.pack(fill=tk.X, padx=5, pady=3)
self.btn_export = tk.Button(control_group, text="导出报告",
command=self.export_report,
bg="#2196f3", fg=self.fg_color, relief=tk.FLAT,
height=1, font=("Arial", 9), state=tk.DISABLED)
self.btn_export.pack(fill=tk.X, padx=5, pady=3)
# 状态显示
status_group = tk.LabelFrame(left_frame, text="状态",
bg=self.bg_color, fg=self.fg_color,
font=("Arial", 10, "bold"))
status_group.pack(fill=tk.X)
self.status_label = tk.Label(status_group, text="就绪",
bg=self.bg_color, fg="#00ff00",
font=("Arial", 9), anchor=tk.W)
self.status_label.pack(fill=tk.X, padx=5, pady=5)
# 右侧结果显示区域
right_frame = tk.Frame(main_frame, bg=self.bg_color)
right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
# 标签页
notebook = ttk.Notebook(right_frame)
notebook.pack(fill=tk.BOTH, expand=True)
# 变化日志页
log_frame = ttk.Frame(notebook)
notebook.add(log_frame, text="目标程序变化")
self.log_text = scrolledtext.ScrolledText(log_frame, bg="#1a1a1a", fg="#d4d4d4",
font=("Consolas", 9), insertbackground="white")
self.log_text.pack(fill=tk.BOTH, expand=True, padx=3, pady=3)
# 配置日志颜色
self.log_text.tag_config("create", foreground="#6a9955")
self.log_text.tag_config("modify", foreground="#ce9178")
self.log_text.tag_config("delete", foreground="#f48771")
self.log_text.tag_config("info", foreground="#569cd6")
self.log_text.tag_config("success", foreground="#6a9955")
self.log_text.tag_config("error", foreground="#f48771")
self.log_text.tag_config("filtered", foreground="#808080")
# 所有变化页
all_log_frame = ttk.Frame(notebook)
notebook.add(all_log_frame, text="所有变化")
self.all_log_text = scrolledtext.ScrolledText(all_log_frame, bg="#1a1a1a", fg="#d4d4d4",
font=("Consolas", 9), insertbackground="white")
self.all_log_text.pack(fill=tk.BOTH, expand=True, padx=3, pady=3)
for tag in ["create", "modify", "delete", "info", "success", "error"]:
self.all_log_text.tag_config(tag, foreground=self.log_text.tag_cget(tag, "foreground"))
# 统计信息页
stats_frame = ttk.Frame(notebook)
notebook.add(stats_frame, text="统计信息")
self.stats_text = scrolledtext.ScrolledText(stats_frame, bg="#1a1a1a", fg="#d4d4d4",
font=("Consolas", 9), insertbackground="white")
self.stats_text.pack(fill=tk.BOTH, expand=True, padx=3, pady=3)
def browse_program(self):
"""浏览选择程序"""
file_path = filedialog.askopenfilename(
title="选择要监控的程序",
filetypes=[("可执行文件", "*.exe"), ("所有文件", "*.*")]
)
if file_path:
self.program_path.delete(0, tk.END)
self.program_path.insert(0, file_path)
self.selected_program = file_path
self.target_process_name = os.path.basename(file_path).lower()
self.log(f"已选择程序: {self.target_process_name}", "info")
def log(self, message: str, tag: str = "info", to_all=True):
"""添加日志"""
timestamp = datetime.now().strftime("%H:%M:%S")
# 主日志
self.log_text.insert(tk.END, f"[{timestamp}] ", "info")
self.log_text.insert(tk.END, f"{message}\n", tag)
self.log_text.see(tk.END)
# 所有变化日志
if to_all:
self.all_log_text.insert(tk.END, f"[{timestamp}] ", "info")
self.all_log_text.insert(tk.END, f"{message}\n", tag)
self.all_log_text.see(tk.END)
self.root.update_idletasks()
def log_change(self, change: Dict, is_target: bool = False):
"""记录变化"""
timestamp = datetime.now().strftime("%H:%M:%S")
change_type = change['type']
if change_type == 'create':
tag = "create"
icon = "➕"
msg = f"{icon} 新增: {change['key']}\\{change['value']}"
elif change_type == 'modify':
tag = "modify"
icon = "✏️"
msg = f"{icon} 修改: {change['key']}\\{change['value']}"
else:
tag = "delete"
icon = "❌"
msg = f"{icon} 删除: {change['key']}\\{change['value']}"
# 始终记录到所有变化日志
self.all_log_text.insert(tk.END, f"[{timestamp}] ", "info")
self.all_log_text.insert(tk.END, f"{msg}\n", tag)
self.all_log_text.see(tk.END)
# 只记录目标程序相关的变化到主日志
if is_target:
self.log_text.insert(tk.END, f"[{timestamp}] ", "info")
self.log_text.insert(tk.END, f"{msg}\n", tag)
self.log_text.see(tk.END)
elif not self.filter_system.get():
self.log_text.insert(tk.END, f"[{timestamp}] ", "filtered")
self.log_text.insert(tk.END, f"[过滤] {msg}\n", "filtered")
self.log_text.see(tk.END)
self.root.update_idletasks()
def update_status(self, message: str, color: str = "#00ff00"):
"""更新状态栏"""
self.status_label.config(text=message, fg=color)
self.root.update_idletasks()
def is_change_from_target(self, change: Dict) -> bool:
"""判断变化是否来自目标程序"""
if not self.target_process_name:
return False
# 检查变化路径是否包含目标程序名
key_lower = change['key'].lower()
value_lower = str(change['value']).lower()
old_val_lower = str(change['old_value']).lower() if change['old_value'] else ""
new_val_lower = str(change['new_value']).lower() if change['new_value'] else ""
# 检查是否包含目标程序名
target_name = self.target_process_name.replace('.exe', '')
if target_name in key_lower:
return True
if self.target_process_name in value_lower:
return True
if self.target_process_name in old_val_lower:
return True
if self.target_process_name in new_val_lower:
return True
# 检查是否包含目标程序的完整路径
if self.selected_program and self.selected_program.lower() in key_lower:
return True
return False
def filter_common_operations(self, changes: List[Dict]) -> List[Dict]:
"""过滤常见系统操作"""
if not self.filter_common.get():
return changes
filtered = []
common_patterns = [
"\\SessionInfo\\",
"\\FeatureUsage\\",
"\\UserAssist\\",
"\\ActivityDataModel\\",
"\\bam\\State\\",
"\\Notifications\\Data",
"\\DolbySettings\\",
"\\SystemAppData\\",
"\\hivelist",
]
for change in changes:
key_lower = change['key'].lower()
is_common = False
for pattern in common_patterns:
if pattern.lower() in key_lower:
is_common = True
break
if not is_common:
filtered.append(change)
return filtered
def create_before_snapshot(self):
"""创建监控前的快照"""
selected_keys = [key for key, var in self.registry_vars.items() if var.get()]
if not selected_keys:
messagebox.showwarning("警告", "请至少选择一个注册表区域")
return
self.log("=" * 50, "info")
self.log("开始创建监控前的注册表快照...", "info")
self.update_status("正在创建快照...", "#ffff00")
def scan_thread():
try:
snapshot = RegistryScanner.scan_registry(selected_keys, self.log_status)
self.before_snapshot = snapshot
total_keys = len(snapshot.data)
total_values = sum(len(values) for values in snapshot.data.values())
self.root.after(0, lambda: self.log(f"✅ 监控前快照创建完成!", "success"))
self.root.after(0, lambda: self.log(f" 扫描到 {total_keys} 个键, {total_values} 个值", "info"))
self.root.after(0, lambda: self.update_status("快照创建完成", "#00ff00"))
self.root.after(0, lambda: self.btn_step2.config(state=tk.NORMAL))
except Exception as e:
self.root.after(0, lambda: self.log(f"❌ 创建快照失败: {e}", "error"))
self.root.after(0, lambda: self.update_status("快照创建失败", "#ff0000"))
threading.Thread(target=scan_thread, daemon=True).start()
def log_status(self, message: str):
"""记录扫描状态"""
self.root.after(0, lambda: self.log(message, "info"))
def start_program(self):
"""启动程序"""
program = self.program_path.get().strip()
if not program:
messagebox.showwarning("警告", "请选择要监控的程序")
return
if not os.path.exists(program):
messagebox.showerror("错误", f"程序文件不存在:\n{program}")
return
args = self.program_args.get().strip()
try:
self.log("=" * 50, "info")
self.log(f"正在启动程序: {os.path.basename(program)}", "info")
if args:
cmd = f'"{program}" {args}'
else:
cmd = f'"{program}"'
self.process = subprocess.Popen(cmd, shell=True)
self.target_process_pid = self.process.pid
self.log(f"程序已启动 (PID: {self.target_process_pid})", "success")
self.update_status(f"程序运行中 (PID: {self.target_process_pid})", "#00ff00")
self.log("", "info")
self.log("提示: 操作程序后点击'步骤3'查看变化", "info")
self.btn_step2.config(state=tk.DISABLED)
self.btn_step3.config(state=tk.NORMAL)
except Exception as e:
self.log(f"❌ 启动程序失败: {e}", "error")
self.update_status("程序启动失败", "#ff0000")
def create_after_snapshot(self):
"""创建监控后的快照并对比"""
selected_keys = [key for key, var in self.registry_vars.items() if var.get()]
if not selected_keys:
messagebox.showwarning("警告", "请至少选择一个注册表区域")
return
self.log("=" * 50, "info")
self.log("开始创建监控后的注册表快照...", "info")
self.update_status("正在创建快照...", "#ffff00")
def scan_thread():
try:
after_snapshot = RegistryScanner.scan_registry(selected_keys, self.log_status)
self.log("正在对比注册表变化...", "info")
all_changes = self.before_snapshot.compare(after_snapshot)
# 过滤常见系统操作
all_changes = self.filter_common_operations(all_changes)
# 分离目标程序的变化
target_changes = []
other_changes = []
for change in all_changes:
if self.is_change_from_target(change):
target_changes.append(change)
else:
other_changes.append(change)
# 显示结果
self.root.after(0, lambda: self.display_results(target_changes, other_changes, all_changes))
except Exception as e:
self.root.after(0, lambda: self.log(f"❌ 对比失败: {e}", "error"))
self.root.after(0, lambda: self.update_status("对比失败", "#ff0000"))
threading.Thread(target=scan_thread, daemon=True).start()
def display_results(self, target_changes: List[Dict], other_changes: List[Dict], all_changes: List[Dict]):
"""显示结果"""
# 显示目标程序的变化
if target_changes:
create_count = sum(1 for c in target_changes if c['type'] == 'create')
modify_count = sum(1 for c in target_changes if c['type'] == 'modify')
delete_count = sum(1 for c in target_changes if c['type'] == 'delete')
self.log("=" * 50, "info")
self.log(f"🎯 目标程序 ({self.target_process_name}) 变化:", "success")
self.log(f" ➕ 新增: {create_count} 项", "create")
self.log(f" ✏️ 修改: {modify_count} 项", "modify")
self.log(f" ❌ 删除: {delete_count} 项", "delete")
self.log("=" * 50, "info")
for change in target_changes:
self.log_change(change, is_target=True)
else:
self.log("🎉 未检测到目标程序的注册表变化!", "success")
self.log("提示: 程序可能没有修改注册表", "info")
# 更新统计
self.update_stats(target_changes, other_changes, all_changes)
self.update_status("监控完成", "#00ff00")
self.btn_export.config(state=tk.NORMAL)
def update_stats(self, target_changes: List[Dict], other_changes: List[Dict], all_changes: List[Dict]):
"""更新统计信息"""
self.stats_text.delete(1.0, tk.END)
target_create = [c for c in target_changes if c['type'] == 'create']
target_modify = [c for c in target_changes if c['type'] == 'modify']
target_delete = [c for c in target_changes if c['type'] == 'delete']
stats = f"""
╔════════════════════════════════════════════════╗
║ 注册表监控统计报告 ║
╚════════════════════════════════════════════════╝
监控时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
监控程序: {os.path.basename(self.program_path.get())}
程序PID: {self.target_process_pid}
┌────────────────────────────────────────────────┐
│ 目标程序变化统计 │
├────────────────────────────────────────────────┤
│ 总计变化数: {len(target_changes)} 项 │
│ │
│ ➕ 新增: {len(target_create)} 项 │
│ ✏️ 修改: {len(target_modify)} 项 │
│ ❌ 删除: {len(target_delete)} 项 │
└────────────────────────────────────────────────┘
┌────────────────────────────────────────────────┐
│ 所有程序变化统计 │
├────────────────────────────────────────────────┤
│ 总计变化数: {len(all_changes)} 项 │
│ ├─ 目标程序: {len(target_changes)} 项 │
│ └─ 其他程序: {len(other_changes)} 项 │
└────────────────────────────────────────────────┘
"""
# 详细变化列表
if target_changes:
stats += "\n\n详细变化列表:\n"
stats += "-" * 50 + "\n"
for i, change in enumerate(target_changes, 1):
stats += f"\n[{i}] {change['type'].upper()}\n"
stats += f" 路径: {change['key']}\n"
stats += f" 值名: {change['value']}\n"
if change['type'] == 'create':
stats += f" 新值: {change['new_value']}\n"
elif change['type'] == 'modify':
stats += f" 原值: {change['old_value']}\n"
stats += f" 新值: {change['new_value']}\n"
else:
stats += f" 原值: {change['old_value']}\n"
stats += f" 类型: {change['value_type']}\n"
self.stats_text.insert(1.0, stats)
def export_report(self):
"""导出报告"""
file_path = filedialog.asksaveasfilename(
defaultextension=".txt",
filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
)
if file_path:
try:
content = f"""注册表监控报告
生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
监控程序: {self.program_path.get()}
程序参数: {self.program_args.get()}
程序PID: {self.target_process_pid}
{'=' * 70}
【目标程序注册表变化】
{self.log_text.get("1.0", tk.END)}
{'=' * 70}
【所有程序注册表变化(含系统)】
{self.all_log_text.get("1.0", tk.END)}
{'=' * 70}
{self.stats_text.get("1.0", tk.END)}
"""
with open(file_path, 'w', encoding='utf-8') as f:
f.write(content)
self.log(f"✅ 报告已导出: {file_path}", "success")
messagebox.showinfo("成功", f"报告已保存到:\n{file_path}")
except Exception as e:
messagebox.showerror("错误", f"导出失败: {e}")
def main():
# 检查管理员权限
try:
is_admin = ctypes.windll.shell32.IsUserAnAdmin()
if not is_admin:
root = tk.Tk()
root.withdraw()
result = messagebox.askyesno(
"权限提示",
"建议以管理员身份运行以获得完整的注册表访问权限。\n"
"是否继续运行?"
)
root.destroy()
if not result:
return
except:
pass
root = tk.Tk()
app = RegistryMonitorApp(root)
root.mainloop()
if __name__ == "__main__":
main()