feat: add Linux support with cross-platform memory scanning
- Add Linux memory scanner (`find_all_keys_linux.py`) using `/proc/<pid>/mem`, same approach as Windows/macOS — no GDB, no function offsets, no restart needed - Extract Windows-specific code to `find_all_keys_windows.py` - Make `find_all_keys.py` a platform dispatcher (Windows / Linux) - Add `key_utils.py` for cross-platform path matching (`/` vs `\` in all_keys.json) - Update `config.py` with Linux auto-detection of db_storage paths - Update all consumers (decrypt_db, monitor, monitor_web, mcp_server) to use `get_key_info()` for platform-agnostic key lookup Tested on remote Linux container: 15/15 DBs scanned, decrypted, and verified.
This commit is contained in:
@@ -7,7 +7,7 @@ WeChat 4.0 数据库解密器
|
||||
"""
|
||||
import hashlib, struct, os, sys, json
|
||||
import hmac as hmac_mod
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Cipher import AES
|
||||
|
||||
import functools
|
||||
print = functools.partial(print, flush=True)
|
||||
@@ -20,11 +20,12 @@ HMAC_SZ = 64
|
||||
RESERVE_SZ = 80 # IV(16) + HMAC(64)
|
||||
SQLITE_HDR = b'SQLite format 3\x00'
|
||||
|
||||
from config import load_config
|
||||
_cfg = load_config()
|
||||
DB_DIR = _cfg["db_dir"]
|
||||
OUT_DIR = _cfg["decrypted_dir"]
|
||||
KEYS_FILE = _cfg["keys_file"]
|
||||
from config import load_config
|
||||
from key_utils import get_key_info, strip_key_metadata
|
||||
_cfg = load_config()
|
||||
DB_DIR = _cfg["db_dir"]
|
||||
OUT_DIR = _cfg["decrypted_dir"]
|
||||
KEYS_FILE = _cfg["keys_file"]
|
||||
|
||||
|
||||
def derive_mac_key(enc_key, salt):
|
||||
@@ -115,13 +116,13 @@ def main():
|
||||
print("请先运行 find_all_keys.py")
|
||||
sys.exit(1)
|
||||
|
||||
with open(KEYS_FILE) as f:
|
||||
keys = json.load(f)
|
||||
|
||||
keys.pop("_db_dir", None)
|
||||
print(f"\n加载 {len(keys)} 个数据库密钥")
|
||||
print(f"输出目录: {OUT_DIR}")
|
||||
os.makedirs(OUT_DIR, exist_ok=True)
|
||||
with open(KEYS_FILE) as f:
|
||||
keys = json.load(f)
|
||||
|
||||
keys = strip_key_metadata(keys)
|
||||
print(f"\n加载 {len(keys)} 个数据库密钥")
|
||||
print(f"输出目录: {OUT_DIR}")
|
||||
os.makedirs(OUT_DIR, exist_ok=True)
|
||||
|
||||
# 收集所有DB文件
|
||||
db_files = []
|
||||
@@ -129,7 +130,7 @@ def main():
|
||||
for f in files:
|
||||
if f.endswith('.db') and not f.endswith('-wal') and not f.endswith('-shm'):
|
||||
path = os.path.join(root, f)
|
||||
rel = os.path.relpath(path, DB_DIR).replace('\\', '/')
|
||||
rel = os.path.relpath(path, DB_DIR)
|
||||
sz = os.path.getsize(path)
|
||||
db_files.append((rel, path, sz))
|
||||
|
||||
@@ -141,16 +142,15 @@ def main():
|
||||
failed = 0
|
||||
total_bytes = 0
|
||||
|
||||
for rel, path, sz in db_files:
|
||||
# 统一用正斜杠查找key
|
||||
rel_key = rel.replace('\\', '/')
|
||||
if rel_key not in keys:
|
||||
print(f"SKIP: {rel} (无密钥)")
|
||||
failed += 1
|
||||
continue
|
||||
|
||||
enc_key = bytes.fromhex(keys[rel_key]["enc_key"])
|
||||
out_path = os.path.join(OUT_DIR, rel)
|
||||
for rel, path, sz in db_files:
|
||||
key_info = get_key_info(keys, rel)
|
||||
if not key_info:
|
||||
print(f"SKIP: {rel} (无密钥)")
|
||||
failed += 1
|
||||
continue
|
||||
|
||||
enc_key = bytes.fromhex(key_info["enc_key"])
|
||||
out_path = os.path.join(OUT_DIR, rel)
|
||||
|
||||
print(f"解密: {rel} ({sz/1024/1024:.1f}MB) ...", end=" ")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user