Skip to content

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\WeixinFileSavePath(第 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 独立实现):

  1. Weixin.dllinternal_db_key:PE 解析代码段,匹配连续 4 条 mov rdx, <imm64>(机器码 48 BA)后跟 test rax, rax48 85 C0)的特征, 4×8 = 32 字节拼成一个内部密钥候选。
  2. 扫进程内存取原始密钥:按签名结构 [key_ptr(8)][0][0x20(=长度32)][0x2f(=容量47)],读指针指向的 32 字节。
  3. 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 · 取密钥与解密