feat: 添加微信数据库解密工具的基本功能

This commit is contained in:
2977094657
2025-07-07 19:01:14 +08:00
commit 4896e8a2ec
11 changed files with 1895 additions and 0 deletions
+447
View File
@@ -0,0 +1,447 @@
"""微信数据库检测模块
提供微信安装检测和数据库发现功能。
基于PyWxDump的检测逻辑。
"""
import os
import re
import psutil
import ctypes
from pathlib import Path
from typing import List, Dict, Any, Union
from ctypes import wintypes
def get_wx_db(msg_dir: str = None,
db_types: Union[List[str], str] = None,
wxids: Union[List[str], str] = None) -> List[dict]:
r"""
获取微信数据库路径(基于PyWxDump逻辑)
:param msg_dir: 微信数据库目录 eg: C:\Users\user\Documents\WeChat Files (非wxid目录)
:param db_types: 需要获取的数据库类型,如果为空,则获取所有数据库
:param wxids: 微信id列表,如果为空,则获取所有wxid下的数据库
:return: [{"wxid": wxid, "db_type": db_type, "db_path": db_path, "wxid_dir": wxid_dir}, ...]
"""
result = []
if not msg_dir or not os.path.exists(msg_dir):
print(f"[-] 微信文件目录不存在: {msg_dir}, 将使用默认路径")
msg_dir = get_wx_dir_by_reg()
if not os.path.exists(msg_dir):
print(f"[-] 目录不存在: {msg_dir}")
return result
wxids = wxids.split(";") if isinstance(wxids, str) else wxids
if not isinstance(wxids, list) or len(wxids) <= 0:
wxids = None
db_types = db_types.split(";") if isinstance(db_types, str) and db_types else db_types
if not isinstance(db_types, list) or len(db_types) <= 0:
db_types = None
wxid_dirs = {} # wx用户目录
if wxids or "All Users" in os.listdir(msg_dir) or "Applet" in os.listdir(msg_dir) or "WMPF" in os.listdir(msg_dir):
for sub_dir in os.listdir(msg_dir):
if os.path.isdir(os.path.join(msg_dir, sub_dir)) and sub_dir not in ["All Users", "Applet", "WMPF"]:
wxid_dirs[os.path.basename(sub_dir)] = os.path.join(msg_dir, sub_dir)
else:
wxid_dirs[os.path.basename(msg_dir)] = msg_dir
for wxid, wxid_dir in wxid_dirs.items():
if wxids and wxid not in wxids: # 如果指定wxid,则过滤掉其他wxid
continue
for root, dirs, files in os.walk(wxid_dir):
# 只处理db_storage目录下的数据库文件
if "db_storage" not in root:
continue
for file_name in files:
if not file_name.endswith(".db"):
continue
# 排除不需要解密的数据库
if file_name in ["key_info.db"]:
continue
db_type = re.sub(r"\d*\.db$", "", file_name)
if db_types and db_type not in db_types: # 如果指定db_type,则过滤掉其他db_type
continue
db_path = os.path.join(root, file_name)
result.append({"wxid": wxid, "db_type": db_type, "db_path": db_path, "wxid_dir": wxid_dir})
return result
# Windows API 常量和结构
PROCESS_QUERY_INFORMATION = 0x0400
PROCESS_VM_READ = 0x0010
MAX_PATH = 260
TH32CS_SNAPPROCESS = 0x00000002
# Windows API 函数
kernel32 = ctypes.windll.kernel32
psapi = ctypes.windll.psapi
OpenProcess = kernel32.OpenProcess
CloseHandle = kernel32.CloseHandle
GetModuleFileNameExW = psapi.GetModuleFileNameExW
CreateToolhelp32Snapshot = kernel32.CreateToolhelp32Snapshot
Process32FirstW = kernel32.Process32FirstW
Process32NextW = kernel32.Process32NextW
class PROCESSENTRY32W(ctypes.Structure):
_fields_ = [
('dwSize', wintypes.DWORD),
('cntUsage', wintypes.DWORD),
('th32ProcessID', wintypes.DWORD),
('th32DefaultHeapID', ctypes.POINTER(wintypes.ULONG)),
('th32ModuleID', wintypes.DWORD),
('cntThreads', wintypes.DWORD),
('th32ParentProcessID', wintypes.DWORD),
('pcPriClassBase', wintypes.LONG),
('dwFlags', wintypes.DWORD),
('szExeFile', wintypes.WCHAR * MAX_PATH)
]
# 删除了WeChatDecryptor类,解密功能已移至独立的wechat_decrypt.py脚本
def find_wechat_databases() -> List[str]:
"""在新的xwechat_files目录中查找微信数据库文件
返回值:
数据库文件路径列表
"""
db_files = []
# 获取用户的Documents目录
documents_dir = Path.home() / "Documents"
# 检查新的微信4.0+目录结构
wechat_dirs = [
documents_dir / "xwechat_files", # 新版微信4.0+
documents_dir / "WeChat Files" # 旧版微信
]
for wechat_dir in wechat_dirs:
if not wechat_dir.exists():
continue
# 查找用户目录(wxid_*模式)
for user_dir in wechat_dir.iterdir():
if not user_dir.is_dir():
continue
# 跳过系统目录
if user_dir.name in ['All Users', 'Applet', 'WMPF']:
continue
# 查找Msg目录
msg_dir = user_dir / "Msg"
if msg_dir.exists():
# 查找数据库文件
for db_file in msg_dir.glob("*.db"):
if db_file.is_file():
db_files.append(str(db_file))
# 同时检查Multi目录
multi_dir = msg_dir / "Multi"
if multi_dir.exists():
for db_file in multi_dir.glob("*.db"):
if db_file.is_file():
db_files.append(str(db_file))
return db_files
def get_process_exe_path(process_id):
"""获取进程可执行文件路径"""
h_process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, process_id)
if not h_process:
return None
exe_path = ctypes.create_unicode_buffer(MAX_PATH)
if GetModuleFileNameExW(h_process, None, exe_path, MAX_PATH) > 0:
CloseHandle(h_process)
return exe_path.value
else:
CloseHandle(h_process)
return None
def get_process_list():
"""获取系统进程列表"""
h_process_snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
if h_process_snap == ctypes.wintypes.HANDLE(-1).value:
return []
pe32 = PROCESSENTRY32W()
pe32.dwSize = ctypes.sizeof(PROCESSENTRY32W)
process_list = []
if not Process32FirstW(h_process_snap, ctypes.byref(pe32)):
CloseHandle(h_process_snap)
return []
while True:
process_list.append((pe32.th32ProcessID, pe32.szExeFile))
if not Process32NextW(h_process_snap, ctypes.byref(pe32)):
break
CloseHandle(h_process_snap)
return process_list
def auto_detect_wechat_data_dirs():
"""
自动检测微信数据目录 - 多策略组合检测
:return: 检测到的微信数据目录列表
"""
detected_dirs = []
# 策略1:注册表检测已移除
# 策略2和策略3:注册表相关检测已移除
# 策略1:常见驱动器扫描微信相关目录
common_wechat_patterns = [
"WeChat Files", "wechat_files", "xwechat_files", "wechatMSG",
"WeChat", "微信", "Weixin", "wechat"
]
# 扫描常见驱动器
drives = ['C:', 'D:', 'E:', 'F:']
for drive in drives:
if not os.path.exists(drive):
continue
try:
# 扫描驱动器根目录和常见目录
scan_paths = [
drive + os.sep,
os.path.join(drive + os.sep, "Users"),
]
for scan_path in scan_paths:
if not os.path.exists(scan_path):
continue
try:
for item in os.listdir(scan_path):
item_path = os.path.join(scan_path, item)
if not os.path.isdir(item_path):
continue
# 检查是否匹配微信目录模式
for pattern in common_wechat_patterns:
if pattern.lower() in item.lower():
# 检查是否包含wxid目录
if has_wxid_directories(item_path):
if item_path not in detected_dirs:
detected_dirs.append(item_path)
print(f"[DEBUG] 目录扫描检测成功: {item_path}")
break
except (PermissionError, OSError):
continue
except (PermissionError, OSError):
continue
# 策略2:进程内存分析(简化版)
try:
process_list = get_process_list()
for pid, process_name in process_list:
if process_name.lower() in ['weixin.exe', 'wechat.exe']:
# 尝试获取进程的工作目录
try:
import psutil
proc = psutil.Process(pid)
cwd = proc.cwd()
# 从进程工作目录向上查找可能的数据目录
parent_dirs = [cwd]
current = cwd
for _ in range(3): # 向上查找3级目录
parent = os.path.dirname(current)
if parent != current:
parent_dirs.append(parent)
current = parent
else:
break
for parent_dir in parent_dirs:
for pattern in common_wechat_patterns:
potential_dir = os.path.join(parent_dir, pattern)
if os.path.exists(potential_dir) and has_wxid_directories(potential_dir):
if potential_dir not in detected_dirs:
detected_dirs.append(potential_dir)
print(f"[DEBUG] 进程分析检测成功: {potential_dir}")
except:
pass
except:
pass
return detected_dirs
# 删除了所有解密相关函数,解密功能已移至独立的wechat_decrypt.py脚本
def has_wxid_directories(directory):
"""
检查目录是否包含wxid格式的子目录
:param directory: 要检查的目录
:return: 是否包含wxid目录
"""
try:
for item in os.listdir(directory):
item_path = os.path.join(directory, item)
if os.path.isdir(item_path) and (item.startswith('wxid_') or len(item) > 10):
# 进一步检查是否包含数据库文件
for root, _, files in os.walk(item_path):
for file in files:
if file.endswith('.db'):
return True
return False
except:
return False
def get_wx_dir_by_reg(wxid="all"):
"""
通过多种方法获取微信目录 - 改进的自动检测
:param wxid: 微信id,如果为"all"则返回WeChat Files目录,否则返回具体wxid目录
:return: 微信目录路径
"""
if not wxid:
return None
# 使用新的自动检测方法
detected_dirs = auto_detect_wechat_data_dirs()
if not detected_dirs:
print(f"[DEBUG] 未检测到任何微信数据目录")
return None
# 返回第一个检测到的目录
wx_dir = detected_dirs[0]
print(f"[DEBUG] 使用检测到的微信目录: {wx_dir}")
# 如果指定了具体的wxid,返回wxid目录
if wxid and wxid != "all":
wxid_dir = os.path.join(wx_dir, wxid)
return wxid_dir if os.path.exists(wxid_dir) else None
return wx_dir if os.path.exists(wx_dir) else None
def detect_wechat_installation() -> Dict[str, Any]:
"""
检测微信安装情况 - 完全按照PyWxDump的逻辑实现
"""
result = {
"wechat_version": None,
"wechat_install_path": None,
"wechat_exe_path": None,
"wechat_data_dirs": [],
"message_dirs": [],
"databases": [],
"version_detected": None,
"is_running": False,
"user_accounts": [],
"detection_errors": [],
"detection_methods": []
}
# 进程检测 - 只检测Weixin.exe(按照用户要求)
result["detection_methods"].append("进程检测")
process_list = get_process_list()
for pid, process_name in process_list:
# 只检查Weixin.exe进程
if process_name.lower() == 'weixin.exe':
try:
exe_path = get_process_exe_path(pid)
if exe_path:
result["wechat_exe_path"] = exe_path
result["wechat_install_path"] = os.path.dirname(exe_path)
result["is_running"] = True
result["detection_methods"].append(f"检测到微信进程: {process_name} (PID: {pid})")
# 尝试获取版本信息
try:
import win32api
version_info = win32api.GetFileVersionInfo(exe_path, "\\")
version = f"{version_info['FileVersionMS'] >> 16}.{version_info['FileVersionMS'] & 0xFFFF}.{version_info['FileVersionLS'] >> 16}.{version_info['FileVersionLS'] & 0xFFFF}"
result["wechat_version"] = version
result["detection_methods"].append(f"获取到微信版本: {version}")
except ImportError:
result["detection_errors"].append("win32api库未安装,无法获取版本信息")
except Exception as e:
result["detection_errors"].append(f"版本获取失败: {e}")
break
except Exception as e:
result["detection_errors"].append(f"进程信息获取失败: {e}")
if not result["is_running"]:
result["detection_methods"].append("未检测到微信进程")
# 2. 使用自动检测逻辑获取微信目录和数据库
result["detection_methods"].append("目录自动检测")
try:
wx_dir = get_wx_dir_by_reg()
if wx_dir and os.path.exists(wx_dir):
result["wechat_data_dirs"].append(wx_dir)
result["detection_methods"].append(f"通过自动检测找到微信目录: {wx_dir}")
# 使用PyWxDump的get_wx_db函数获取数据库信息
db_list = get_wx_db(msg_dir=wx_dir) # 移除db_types限制,获取所有.db文件
# 统计用户账户和消息目录
user_accounts_set = set()
message_dirs_set = set()
for db_info in db_list:
wxid = db_info["wxid"]
wxid_dir = db_info["wxid_dir"]
db_path = db_info["db_path"]
db_type = db_info["db_type"]
# 添加用户账户
user_accounts_set.add(wxid)
message_dirs_set.add(wxid_dir)
# 添加数据库信息
if os.path.exists(db_path):
result["databases"].append({
"path": db_path,
"name": os.path.basename(db_path),
"type": db_type,
"size": os.path.getsize(db_path),
"user": wxid,
"user_dir": wxid_dir
})
# 转换为列表
result["user_accounts"] = list(user_accounts_set)
result["message_dirs"] = list(message_dirs_set)
result["detection_methods"].append(f"检测到 {len(result['user_accounts'])} 个用户账户")
result["detection_methods"].append(f"检测到 {len(result['databases'])} 个数据库文件")
# 按数据库类型统计
db_type_count = {}
for db in result["databases"]:
db_type = db["type"]
db_type_count[db_type] = db_type_count.get(db_type, 0) + 1
if db_type_count:
type_summary = ", ".join([f"{k}({v})" for k, v in db_type_count.items()])
result["detection_methods"].append(f"数据库类型分布: {type_summary}")
else:
result["detection_methods"].append("自动检测未找到微信目录")
except Exception as e:
result["detection_errors"].append(f"目录检测失败: {str(e)}")
return result
def get_wechat_info() -> Dict[str, Any]:
"""获取微信安装和数据库信息
返回值:
包含微信信息的字典
"""
return detect_wechat_installation()