- Add Windows 4.1.x Config.Cipher pointer-chain key extraction with cross-chunk
MemoryPatternScanner and bounded blob XOR decoding; keys still require per-DB
page-1 HMAC verification before caching.
- Cache keys by account fingerprint + database relative path; db scan --save
skips memory scanning entirely once all discovered databases are cached.
- Add DbMessage model (localId, serverId, type, timestamp, sender, display name,
avatar, isSelf) read read-only from Msg_{md5(chat)} via SQLCipher with hex/zstd
content decoding and contact.db name resolution.
- CLI: db messages / db contacts / db schema with masked defaults; include the
earlier chat send --session wiring. 97 Core tests pass; real-machine validated.
51 lines
3.9 KiB
Markdown
51 lines
3.9 KiB
Markdown
# 完整消息模型:只读数据库消息读取与多账号密钥缓存(2026-09-06)
|
||
|
||
## 目标与边界
|
||
|
||
- 本阶段补齐「完整消息模型」:稳定消息 ID、发送者、时间戳、收发方向等 UIA 无法提供的字段,全部来自只读 SQLCipher 数据库。
|
||
- 不写数据库、不注入、不修改微信进程、不做登录绕过;密钥只通过页面 1 HMAC 校验后缓存。
|
||
- 一个机器多账号:密钥按「账号指纹 + 库相对路径」缓存,已缓存账号后续 `db scan` 直接跳过内存扫描。
|
||
|
||
## 密钥提取(Windows 微信 4.1.13.63)
|
||
|
||
- 旧式明文十六进制扫描(ASCII/UTF-16)在该版本找不到可验证密钥。
|
||
- 新增 Windows 4.1.x 的 `Config.Cipher` 只读指针链扫描:
|
||
- 全内存找 `com.Tencent.WCDB.Config.Cipher` 字符串地址;
|
||
- 用字符串地址+长度组成的 16 字节对再次全内存定位对象节点(`节点基址 = 配对地址 - 0x10`);
|
||
- 沿节点 `+0x28 → 配置指针 +0x88 → 数据指针 +0x8 / 长度 +0x10` 读回最多 1024 字节的加密配置块;
|
||
- 固定 33 字节 XOR 掩码解码,提取 `x'<64~192 hex>'` 字面量,候选密钥要求 ≥15 个不同字节且非全 0/全 FF;
|
||
- 最终仍以每个目标库页面 1 HMAC 校验为准。
|
||
- `MemoryPatternScanner` 处理跨分块/跨区边界匹配;所有读出的进程内存缓冲均清零。
|
||
- 扫描结果:5 个进程、19,309 个候选、149,800 次校验 → 20 个数据库全部 `PageHmacVerified`,来源进程 8912。
|
||
|
||
## 多账号缓存
|
||
|
||
- `db scan --save` 先加载密钥缓存,计算「发现库 − 已缓存库」;无待办则 `scanned=false` 直接跳过(processCount/candidateCount=0)。
|
||
- 第二次 `db scan --save` 验证:`scanned=false`,缓存仍 20 个库,无需重扫。
|
||
- 缓存键大小写不敏感(Windows 路径);新账号/新库出现时才触发增量扫描。
|
||
|
||
## 消息模型与读取
|
||
|
||
- 消息表名:`Msg_{md5(chat_wxid)}`;在 `message/message_*.db`、`message/biz_message_*.db` 中定位。
|
||
- 只读查询列:`local_id, server_id, local_type, create_time, hex(message_content), WCDB_CT_message_content, real_sender_id`,`LEFT JOIN name2id` 得发送者 wxid。
|
||
- 内容解码:hex → UTF-8;压缩标记且带 zstd 魔数 `28 b5 2f fd` 时用 zstd 解压(ZstdSharp.Port,Core 内跨平台)。
|
||
- 发送者显示名/头像:`contact/contact.db` 的 `contact` 表按 wxid 批量查 `remark → nick_name → username` 与 `small_head_url`。
|
||
- 收发方向:账号根目录名 `<wxid>_<random>` 前缀匹配发送者即 `IsSelf=true`(AccountRootPath 指向 `db_storage`,其父目录名才是账号目录)。
|
||
- CLI:`db messages --account <fp> --chat <wxid> [--limit] [--include-content]`、`db contacts`、`db schema`;默认脱敏,`--include-content` 才显示名称/内容/头像。
|
||
|
||
## 真机验收
|
||
|
||
- Windows 10.0.19044,微信 4.1.13.63,原交互会话 1(已解锁),唯一密钥缓存。
|
||
- 群聊名解析:`db contacts --contains 测试` 命中 `53271859539@chatroom`,昵称「消息测试专用群组」。
|
||
- 消息读取:`db messages --chat 53271859539@chatroom --limit 6 --include-content` 返回 6 条:
|
||
- 每条含 `local_id`(7–12)、`server_id`、`type=1`、RFC3339 时间戳、发送者、`IsSelf`、显示名、头像、内容。
|
||
- 内容正是此前本机发送的测试标记(`wx-agent-isolation-*`、`wx-agent-repeat-*`、`wx-agent-m6-listener-*`),证明 hex/zstd 解码正确。
|
||
- 本机发送消息 `IsSelf=true`、`senderName=Rogee`;发送者名/头像经 contact.db 解析。
|
||
- Core:97/97 测试通过;Release 全量构建与 self-contained 发布 0 警告 0 错误。
|
||
- 密钥文件位于 `%LOCALAPPDATA%\WxAgent\database-keys.json`,ACL 仅当前用户;CLI 输出不含密钥。
|
||
|
||
## 尚未完成(本阶段之外)
|
||
|
||
- 通用发送能力、导航能力、合并聊天记录展开仍按顺序推进。
|
||
- 消息模型与 UIA 事件流的合并(实时新消息方向归属)不在本阶段。
|