外观
00 · 架构与原理
在写任何代码之前,先搞清楚两件事:微信 4.x 的数据存在哪、怎么加密的, 以及我们要用什么架构把它变成一个 AI 能用的能力。
一、微信 4.x 的数据长什么样
微信 4.x(Weixin.exe)把聊天记录放在本地的 SQLCipher 加密 SQLite 库里。 典型目录结构(Windows):
<数据根>\<wxid>_<后缀>\db_storage\
message\message_0.db # 消息(每个会话一张 Msg_<md5> 表)
contact\contact.db # 联系人- 数据根本机实测在
E:\xwechat_files,也可能在「文档」下,或注册表HKCU\SOFTWARE\Tencent\Weixin的FileSavePath(第 1 章的paths_win.py会自动找)。 - macOS 在
~/Library/Containers/com.tencent.xinWeChat/.../xwechat_files/<account>/db_storage/。
这些 .db 文件不是普通 SQLite,直接用 DB Browser 打开会报错——它们被 SQLCipher-4 加密了。所以第一步永远是「拿到密钥 → 解密 → 得到明文 SQLite」。
二、SQLCipher-4 是怎么加密的
理解这几个参数,第 1 章的 sqlcipher4.py 就不再是黑魔法(这些参数已被 pywxdump / chatlog / wechat-dump-rs 等公开项目反复验证):
- 算法:AES-256-CBC,页大小
page_size = 4096字节。 - salt:数据库文件的前 16 字节(明文,不加密)。
- 密钥派生:
enc_key = PBKDF2-HMAC-SHA512(raw_key, salt, 256000 次, 32 字节)mac_key = PBKDF2-HMAC-SHA512(enc_key, salt XOR 0x3a, 2 次, 32 字节)
- 每页布局(
reserve = IV(16) + HMAC(64) = 80):
┌──────────────────────────── 4096 ────────────────────────────┐
│ 密文区 (4096 - 80 = 4016) │ IV 16 │ HMAC-SHA512 64 │
└───────────────────────────────┴─────────┴────────────────────┘
第 1 页:密文区最前 16 字节位置存的是明文 salt,真正密文从偏移 16 开始- 完整性:每页用
mac_key对密文区 + IV + 页号(小端4字节)算 HMAC-SHA512, 存在页末 64 字节。这也是我们验证密钥对不对的手段:拿候选密钥派生mac_key, 重算第 1 页 HMAC,和存储值一致 → 密钥正确。不用真去解密整库。
解密后第 1 页开头的 16 字节 salt 会被替换回标准 SQLite 文件头
"SQLite format 3\x00",这样明文库才能被普通 sqlite3 打开。
三、密钥从哪来
密钥不在数据库文件里,而在运行中的微信进程内存里。微信 4.x 的密钥算法分三步 (第 1 章实现,方法参考公开项目 LifeArchiveProject/WeChatDataAnalysis,按算法事实 clean-room 独立实现):
- 扫
Weixin.dll取internal_db_key:PE 解析代码段,匹配连续 4 条mov rdx, <imm64>(机器码48 BA)后跟test rax, rax(48 85 C0)的特征, 4×8 = 32 字节拼成一个内部密钥候选。 - 扫进程内存取原始密钥:按签名结构
[key_ptr(8)][0][0x20(=长度32)][0x2f(=容量47)],读指针指向的 32 字节。 - XOR 合并 + 验证:
真正密钥 = 原始密钥 XOR internal_db_key(部分库不 XOR), 再用第二节的 HMAC 校验第 1 页。
macOS 走的是另一条路:给系统函数 CCKeyDerivationPBKDF 下 lldb 断点,在派生密钥时 截获口令(见 code/wechat_mac/)。解密与读库部分两平台完全一致。
四、整体架构:四层各司其职
┌─────────────┐ 自然语言 ┌──────────┐ 工具调用 ┌──────────────┐
│ NoCannoBB │◀───────────▶│ Skill │◀───────────▶│ MCP Server │
│ (模型推理) │ 推理/摘要 │ (路由/解释)│ 固定只读工具│ (Python 只读) │
└─────────────┘ └──────────┘ └──────┬───────┘
│ sqlite3 只读
┌──────▼───────┐
│ 明文临时库 │
└──────▲───────┘
(第1章) 取密钥+解密一次
┌──────┴───────┐
│ 加密微信库 │
└──────────────┘- Python 层(第 1~2 章):真正干活——取密钥、解密、只读查询、zstd 解压、脱敏。
- MCP 层(第 3 章):把 Python 的固定函数暴露成工具。只暴露
search_messages / read_chat_history / list_contacts / list_conversations, 绝不暴露execute_sql/dump_key/export_all。 - Skill 层(第 4 章):把用户的话映射到工具调用,并解释/摘要结果。
- NoCannoBB(第 5 章):提供 OpenAI/Anthropic 兼容的模型接口,是 Skill 的大脑。
这套分层的意义:模型永远拿不到密钥,也不能执行任意 SQL。它只能通过几个受控的 只读入口访问数据,越界的能力从架构上就不存在。
下一章:01 · 取密钥与解密