From bf77cc97d8e6377eea1758c91579c205112eb3f2 Mon Sep 17 00:00:00 2001 From: PeanutSplash Date: Fri, 6 Mar 2026 17:02:42 +0800 Subject: [PATCH] refactor(linux): improve wechat detection and sudo db path fallback --- README.md | 1 - config.py | 11 +++++++++-- find_all_keys_linux.py | 27 ++++++++++++++++++++++----- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c7bb84e..969cd83 100644 --- a/README.md +++ b/README.md @@ -209,7 +209,6 @@ V2 文件结构: `[6B signature] [4B aes_size LE] [4B xor_size LE] [1B padding]` ## macOS 数据库密钥扫描 (WeChat 4.x) - macOS 版微信 4.x 使用 SQLCipher 4 加密本地数据库,密钥格式为 `x'<64hex_key><32hex_salt>'`。C 版扫描器通过 Mach VM API 扫描微信进程内存提取密钥。 ### 前置条件 diff --git a/config.py b/config.py index 86435a5..c4e5d09 100644 --- a/config.py +++ b/config.py @@ -105,14 +105,21 @@ def _auto_detect_db_dir_windows(): def _auto_detect_db_dir_linux(): """自动检测 Linux 微信 db_storage 路径。 - 优先搜索当前用户的 home 目录,避免以 root 运行时误检测其他用户的数据。 + 优先搜索当前用户的 home 目录。以 sudo 运行时通过 SUDO_USER 回退到 + 实际用户的 home,避免只搜索 /root 而遗漏真实数据目录。 """ seen = set() candidates = [] - # 只搜索当前用户的 home 目录 search_roots = [ os.path.expanduser("~/Documents/xwechat_files"), ] + # sudo 运行时,~ 展开为 /root;回退到实际用户的 home + sudo_user = os.environ.get("SUDO_USER") + if sudo_user: + sudo_home = os.path.expanduser(f"~{sudo_user}") + fallback = os.path.join(sudo_home, "Documents", "xwechat_files") + if fallback not in search_roots: + search_roots.append(fallback) for root in search_roots: if not os.path.isdir(root): diff --git a/find_all_keys_linux.py b/find_all_keys_linux.py index a98a970..92b0e65 100644 --- a/find_all_keys_linux.py +++ b/find_all_keys_linux.py @@ -28,13 +28,26 @@ def _safe_readlink(path): return "" +_INTERPRETERS = {"python", "python3", "bash", "sh", "zsh", "node", "perl", "ruby"} + + def _is_wechat_process(pid): - """检查 pid 是否为微信进程。""" + """检查 pid 是否为微信进程。 + + 使用子串匹配以覆盖 wechat 主进程和 WeChatAppEx 子进程, + 同时排除自身和解释器进程(如 python3 find_all_keys.py)。 + """ + if pid == os.getpid(): + return False try: with open(f"/proc/{pid}/comm") as f: comm = f.read().strip() - exe_name = os.path.basename(_safe_readlink(f"/proc/{pid}/exe")) or comm - haystack = " ".join((comm, exe_name)).lower() + exe_path = _safe_readlink(f"/proc/{pid}/exe") + exe_name = os.path.basename(exe_path) + # 排除脚本解释器进程(避免匹配 python3 wechat-decrypt 等) + if exe_name.lower() in _INTERPRETERS: + return False + haystack = f"{comm} {exe_name}".lower() return "wechat" in haystack or "weixin" in haystack except (PermissionError, FileNotFoundError, ProcessLookupError): return False @@ -85,12 +98,16 @@ def _get_readable_regions(pid): continue if "r" not in parts[1]: continue - # 跳过特殊映射 + # 跳过特殊映射和无关系统库,但保留 wcdb/wechat 相关库 if len(parts) >= 6: mapping_name = parts[5] if mapping_name in _SKIP_MAPPINGS: continue - if any(mapping_name.startswith(p) for p in _SKIP_PATH_PREFIXES): + mapping_lower = mapping_name.lower() + if (any(mapping_name.startswith(p) for p in _SKIP_PATH_PREFIXES) + and "wcdb" not in mapping_lower + and "wechat" not in mapping_lower + and "weixin" not in mapping_lower): continue start_s, end_s = parts[0].split("-") start = int(start_s, 16)