mirror of https://github.com/jackwener/wx-cli.git
refactor(linux): improve wechat detection and sudo db path fallback
parent
bc80a1578d
commit
bf77cc97d8
|
|
@ -209,7 +209,6 @@ V2 文件结构: `[6B signature] [4B aes_size LE] [4B xor_size LE] [1B padding]`
|
||||||
|
|
||||||
## macOS 数据库密钥扫描 (WeChat 4.x)
|
## macOS 数据库密钥扫描 (WeChat 4.x)
|
||||||
|
|
||||||
|
|
||||||
macOS 版微信 4.x 使用 SQLCipher 4 加密本地数据库,密钥格式为 `x'<64hex_key><32hex_salt>'`。C 版扫描器通过 Mach VM API 扫描微信进程内存提取密钥。
|
macOS 版微信 4.x 使用 SQLCipher 4 加密本地数据库,密钥格式为 `x'<64hex_key><32hex_salt>'`。C 版扫描器通过 Mach VM API 扫描微信进程内存提取密钥。
|
||||||
|
|
||||||
### 前置条件
|
### 前置条件
|
||||||
|
|
|
||||||
11
config.py
11
config.py
|
|
@ -105,14 +105,21 @@ def _auto_detect_db_dir_windows():
|
||||||
def _auto_detect_db_dir_linux():
|
def _auto_detect_db_dir_linux():
|
||||||
"""自动检测 Linux 微信 db_storage 路径。
|
"""自动检测 Linux 微信 db_storage 路径。
|
||||||
|
|
||||||
优先搜索当前用户的 home 目录,避免以 root 运行时误检测其他用户的数据。
|
优先搜索当前用户的 home 目录。以 sudo 运行时通过 SUDO_USER 回退到
|
||||||
|
实际用户的 home,避免只搜索 /root 而遗漏真实数据目录。
|
||||||
"""
|
"""
|
||||||
seen = set()
|
seen = set()
|
||||||
candidates = []
|
candidates = []
|
||||||
# 只搜索当前用户的 home 目录
|
|
||||||
search_roots = [
|
search_roots = [
|
||||||
os.path.expanduser("~/Documents/xwechat_files"),
|
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:
|
for root in search_roots:
|
||||||
if not os.path.isdir(root):
|
if not os.path.isdir(root):
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,26 @@ def _safe_readlink(path):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
_INTERPRETERS = {"python", "python3", "bash", "sh", "zsh", "node", "perl", "ruby"}
|
||||||
|
|
||||||
|
|
||||||
def _is_wechat_process(pid):
|
def _is_wechat_process(pid):
|
||||||
"""检查 pid 是否为微信进程。"""
|
"""检查 pid 是否为微信进程。
|
||||||
|
|
||||||
|
使用子串匹配以覆盖 wechat 主进程和 WeChatAppEx 子进程,
|
||||||
|
同时排除自身和解释器进程(如 python3 find_all_keys.py)。
|
||||||
|
"""
|
||||||
|
if pid == os.getpid():
|
||||||
|
return False
|
||||||
try:
|
try:
|
||||||
with open(f"/proc/{pid}/comm") as f:
|
with open(f"/proc/{pid}/comm") as f:
|
||||||
comm = f.read().strip()
|
comm = f.read().strip()
|
||||||
exe_name = os.path.basename(_safe_readlink(f"/proc/{pid}/exe")) or comm
|
exe_path = _safe_readlink(f"/proc/{pid}/exe")
|
||||||
haystack = " ".join((comm, exe_name)).lower()
|
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
|
return "wechat" in haystack or "weixin" in haystack
|
||||||
except (PermissionError, FileNotFoundError, ProcessLookupError):
|
except (PermissionError, FileNotFoundError, ProcessLookupError):
|
||||||
return False
|
return False
|
||||||
|
|
@ -85,12 +98,16 @@ def _get_readable_regions(pid):
|
||||||
continue
|
continue
|
||||||
if "r" not in parts[1]:
|
if "r" not in parts[1]:
|
||||||
continue
|
continue
|
||||||
# 跳过特殊映射
|
# 跳过特殊映射和无关系统库,但保留 wcdb/wechat 相关库
|
||||||
if len(parts) >= 6:
|
if len(parts) >= 6:
|
||||||
mapping_name = parts[5]
|
mapping_name = parts[5]
|
||||||
if mapping_name in _SKIP_MAPPINGS:
|
if mapping_name in _SKIP_MAPPINGS:
|
||||||
continue
|
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
|
continue
|
||||||
start_s, end_s = parts[0].split("-")
|
start_s, end_s = parts[0].split("-")
|
||||||
start = int(start_s, 16)
|
start = int(start_s, 16)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue