fix: handle exited PIDs and narrow message DB keys

feat/daemon-cli
PeanutSplash 2026-03-06 16:15:17 +08:00 committed by ylytdeng
parent f9c338b48d
commit 872e3f58dc
2 changed files with 26 additions and 21 deletions

View File

@ -146,6 +146,9 @@ def main():
except PermissionError: except PermissionError:
print(f"[WARN] 无法读取 /proc/{pid}/maps权限不足跳过") print(f"[WARN] 无法读取 /proc/{pid}/maps权限不足跳过")
continue continue
except (FileNotFoundError, ProcessLookupError):
print(f"[WARN] PID {pid} 已退出,跳过")
continue
total_bytes = sum(s for _, s in regions) total_bytes = sum(s for _, s in regions)
total_mb = total_bytes / 1024 / 1024 total_mb = total_bytes / 1024 / 1024
@ -157,6 +160,9 @@ def main():
except PermissionError: except PermissionError:
print(f"[WARN] 无法打开 /proc/{pid}/mem权限不足跳过") print(f"[WARN] 无法打开 /proc/{pid}/mem权限不足跳过")
continue continue
except (FileNotFoundError, ProcessLookupError):
print(f"[WARN] PID {pid} 已退出,跳过")
continue
try: try:
for reg_idx, (base, size) in enumerate(regions): for reg_idx, (base, size) in enumerate(regions):

View File

@ -5,14 +5,14 @@ Based on FastMCP (stdio transport), reuses existing decryption.
Runs on Windows Python (needs access to D:\ WeChat databases). Runs on Windows Python (needs access to D:\ WeChat databases).
""" """
import os, sys, json, time, sqlite3, tempfile, struct, hashlib, atexit import os, sys, json, time, sqlite3, tempfile, struct, hashlib, atexit, re
import hmac as hmac_mod import hmac as hmac_mod
from datetime import datetime from datetime import datetime
from Crypto.Cipher import AES from Crypto.Cipher import AES
from mcp.server.fastmcp import FastMCP from mcp.server.fastmcp import FastMCP
import zstandard as zstd import zstandard as zstd
from decode_image import ImageResolver from decode_image import ImageResolver
from key_utils import get_key_info, key_path_variants, strip_key_metadata from key_utils import get_key_info, key_path_variants, strip_key_metadata
# ============ 加密常量 ============ # ============ 加密常量 ============
PAGE_SZ = 4096 PAGE_SZ = 4096
@ -50,8 +50,8 @@ if not DECODED_IMAGE_DIR:
elif not os.path.isabs(DECODED_IMAGE_DIR): elif not os.path.isabs(DECODED_IMAGE_DIR):
DECODED_IMAGE_DIR = os.path.join(SCRIPT_DIR, DECODED_IMAGE_DIR) DECODED_IMAGE_DIR = os.path.join(SCRIPT_DIR, DECODED_IMAGE_DIR)
with open(KEYS_FILE) as f: with open(KEYS_FILE) as f:
ALL_KEYS = strip_key_metadata(json.load(f)) ALL_KEYS = strip_key_metadata(json.load(f))
# ============ 解密函数 ============ # ============ 解密函数 ============
@ -175,13 +175,13 @@ class DBCache:
except OSError: except OSError:
pass pass
def get(self, rel_key): def get(self, rel_key):
key_info = get_key_info(ALL_KEYS, rel_key) key_info = get_key_info(ALL_KEYS, rel_key)
if not key_info: if not key_info:
return None return None
rel_path = rel_key.replace('\\', '/').replace('/', os.sep) rel_path = rel_key.replace('\\', '/').replace('/', os.sep)
db_path = os.path.join(DB_DIR, rel_path) db_path = os.path.join(DB_DIR, rel_path)
wal_path = db_path + "-wal" wal_path = db_path + "-wal"
if not os.path.exists(db_path): if not os.path.exists(db_path):
return None return None
@ -197,8 +197,8 @@ class DBCache:
return c_path return c_path
tmp_path = self._cache_path(rel_key) tmp_path = self._cache_path(rel_key)
enc_key = bytes.fromhex(key_info["enc_key"]) enc_key = bytes.fromhex(key_info["enc_key"])
full_decrypt(db_path, tmp_path, enc_key) full_decrypt(db_path, tmp_path, enc_key)
if os.path.exists(wal_path): if os.path.exists(wal_path):
decrypt_wal(wal_path, tmp_path, enc_key) decrypt_wal(wal_path, tmp_path, enc_key)
self._cache[rel_key] = (db_mtime, wal_mtime, tmp_path) self._cache[rel_key] = (db_mtime, wal_mtime, tmp_path)
@ -332,12 +332,11 @@ def _parse_message_content(content, local_type, is_group):
# 消息 DB 的 rel_keys排除 fts/resource/media/biz # 消息 DB 的 rel_keys排除 fts/resource/media/biz
MSG_DB_KEYS = sorted([ MSG_DB_KEYS = sorted([
k for k in ALL_KEYS k for k in ALL_KEYS
if any(v.startswith("message/") for v in key_path_variants(k)) if any(v.startswith("message/") for v in key_path_variants(k))
and any(v.endswith(".db") for v in key_path_variants(k)) and any(re.search(r"message_\d+\.db$", v) for v in key_path_variants(k))
and "fts" not in k and "resource" not in k ])
])
def _find_msg_table_for_user(username): def _find_msg_table_for_user(username):