Commit e880623d4f6f4ee96947d0ce54188814eedf6a91
1 parent
2b2b01e0
docs(wechat_plain): Mac 微信 4.x 数据库解密静态调研记录
纯调研,未做任何实际操作(未关 SIP/未装解密工具),记录目录结构、 密文确认、key_info.db 误判等试错过程,供后续评估是否接入 Mac 端 微信聊天记录作为数据源时参考。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Showing
1 changed file
with
121 additions
and
0 deletions
wechat_plain/scripts/db-decrypt/mac-wechat-4x-db-decrypt-research.md
0 → 100644
| 1 | +# Mac 微信 4.x 聊天记录数据库解密 — 研究记录(未执行,纯调研) | |
| 2 | + | |
| 3 | +> 状态:**只做了静态调研,没有对系统或微信做任何实际操作**(没关 SIP,没装任何解密工具,没碰任何 Keychain/进程)。本机仍是默认安全配置。 | |
| 4 | +> 时间:2026-06-24。触发原因:Personal CRM 项目(`lifelog-recorder`)想评估能不能把 Mac 端微信客户端的聊天记录也接进来作为数据源。 | |
| 5 | + | |
| 6 | +## 1. 本机环境 | |
| 7 | + | |
| 8 | +- 微信 Mac 版本:**4.1.5** (build 31960),`/Applications/WeChat.app` | |
| 9 | +- 容器路径:`~/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files/` | |
| 10 | +- 本机有两个账号目录: | |
| 11 | + - `wxid_51ap3m6p9xs722_8ead` — **当前活跃账号**(`message_0.db` 21MB,今天还在写) | |
| 12 | + - `yibooo_ac07` — 旧/备用账号(`message_0.db` 1GB,最后写入 4-08,应该是迁移后弃用了) | |
| 13 | + | |
| 14 | +这是微信 2024 年后重做的统一客户端(俗称"微信 4.0"),目录结构跟老版(单文件 `EnMicroMsg.db`,本项目 Android 侧 `wechat_plain/scripts/platform-tools/notes/EnMicroMsg.db` 记录的那套)完全不是一回事,**不能直接套用 Android 侧已有的 SQLCipher key 推导经验**(见 `wechat_plain/scripts/db-decrypt/` 下已有的 `wechat_android_*` 系列脚本——那些是 Android 端、走 Frida attach 设备进程,跟这次研究的 macOS 桌面客户端是两套完全独立的密钥体系)。 | |
| 15 | + | |
| 16 | +## 2. 目录结构 / 文件清单 | |
| 17 | + | |
| 18 | +每个账号目录下 `db_storage/` 关键文件: | |
| 19 | + | |
| 20 | +| 文件 | 内容 | | |
| 21 | +|---|---| | |
| 22 | +| `message/message_0.db` (+`-wal`/`-shm`) | 聊天正文,本机目前只有 `_0`,没有分片到 `_1` | | |
| 23 | +| `message/message_fts.db` | 全文索引 | | |
| 24 | +| `message/media_0.db` | 消息内媒体引用 | | |
| 25 | +| `message/biz_message_0.db` | 公众号/服务号消息 | | |
| 26 | +| `message/message_resource.db` | 消息资源 | | |
| 27 | +| `message/*.db-first.material` / `*-last.material` / `*-incremental.material` | WCDB 内部 checkpoint/合并用的中间文件,**不是明文备份**,本身也是加密格式的一部分 | | |
| 28 | +| `contact/contact.db` + `contact_fts.db` | 联系人 | | |
| 29 | +| `session/session.db` | 会话列表 | | |
| 30 | +| `sns/sns.db` | 朋友圈 | | |
| 31 | +| `head_image/head_image.db` | 头像 | | |
| 32 | +| `all_users/login/<account>/key_info.db` | 见下文「试错 1」 | | |
| 33 | + | |
| 34 | +文件头确认:`message_0.db` 开头不是 `SQLite format 3` magic,是随机字节——**确认整库是密文**,不是裸 SQLite。 | |
| 35 | + | |
| 36 | +## 3. 试错记录 | |
| 37 | + | |
| 38 | +### 试错 1:`key_info.db` 误以为是数据库密钥存放处(证伪) | |
| 39 | + | |
| 40 | +`all_users/login/<wxid>/key_info.db` 是**未加密**的标准 SQLite(文件头是正常的 `SQLite format 3`),表结构: | |
| 41 | + | |
| 42 | +```sql | |
| 43 | +CREATE TABLE LoginKeyInfoTable(user_name_md5 TEXT, key_md5 TEXT, key_info_md5 TEXT, key_info_data BLOB); | |
| 44 | +``` | |
| 45 | + | |
| 46 | +`key_info_data` 是个 ~179 字节的二进制 blob,一开始怀疑这就是 SQLCipher 密钥的某种包装形式。 | |
| 47 | + | |
| 48 | +**证伪方法**:对 `WeChat` 主二进制 (`/Applications/WeChat.app/Contents/MacOS/WeChat`,Mach-O universal x86_64+arm64) 跑 `strings`,过滤 cipher/key 相关符号,看到这组字符串聚在一起: | |
| 49 | + | |
| 50 | +``` | |
| 51 | +auth_key auth_id:key_info authkey GenEcdhKeyPair dhKeyAgreement | |
| 52 | +micromsg.ECDHKey mmcrypto.SecECDHKey Key_Info key_info_data key_info_md5 key_info.db | |
| 53 | +``` | |
| 54 | + | |
| 55 | +`GenEcdhKeyPair` / `dhKeyAgreement` / `ECDHKey` 这几个符号说明 `key_info.db` 这套东西是**登录鉴权用的 ECDH 密钥协商**(网络协议层的 authkey,用来跟微信服务器做登录握手),跟本地 SQLCipher 数据库加密**没有关系**。 | |
| 56 | + | |
| 57 | +**结论**:这条路是死的,不要浪费时间在 `key_info.db` 上。 | |
| 58 | + | |
| 59 | +### 试错 2:找本机有没有现成「聊天记录备份」文件可以绕开内存提取(证伪) | |
| 60 | + | |
| 61 | +设想:如果用户之前用过微信的「聊天记录迁移与备份」功能,本地可能留下一份独立的、时间点固定的备份数据库,理论上可以脱离"必须从正在跑的进程内存里挖密钥"这条路。 | |
| 62 | + | |
| 63 | +**搜索范围**: | |
| 64 | +- `xwechat_files/` 整个目录树(`find -maxdepth 6 -iname "*.db"`) | |
| 65 | +- 专门找 `*backup*` / `*migrat*` 命名的目录 | |
| 66 | +- 老版微信遗留路径 `Data/Library/Application Support/com.tencent.xinWeChat`(3.x 时代单文件库可能残留的地方) | |
| 67 | +- 全盘 `mdfind`(Spotlight 索引)搜 `EnMicroMsg` / `WCDB_Contact` / `wechat` 相关文件名,范围含 `~/Downloads`、`~/Desktop` | |
| 68 | + | |
| 69 | +**发现**: | |
| 70 | +- `xwechat_files/Backup/<account>/` 目录确实存在,但内容只有一个 `roam_device_info.dat`(设备漫游信息),**没有任何聊天记录数据库**。 | |
| 71 | +- `<account>/msg/migrate/` 和 `<account>/business/migrate/` 目录存在但本次没有展开看内容(标记为后续如果要继续深挖可以查的点,但目录名暗示是迁移过程的临时态,不太可能是稳定可用的全量备份)。 | |
| 72 | +- 全盘 `mdfind` 命中的全是项目代码里的字符串(本项目 Android 侧的 `EnMicroMsg.db` 笔记、各种带 "wechat" 文件名的截图/PPT),跟 Mac 微信客户端的数据库备份无关。 | |
| 73 | + | |
| 74 | +**结论**:本机**没有可以绕开内存提取的现成备份文件**。唯一的数据源就是运行中、被 SQLCipher4 加密的 `db_storage/message/message_0.db`(含 `-wal`)。如果要拿到明文,没有捷径,必须走"从运行中的微信进程内存里挖出实时密钥"这条路。 | |
| 75 | + | |
| 76 | +## 4. 加密方案技术结论(已通过公开资料 + 二进制字符串交叉确认) | |
| 77 | + | |
| 78 | +- 算法:**SQLCipher 4** | |
| 79 | +- 密钥格式:`x'<64位hex key><32位hex salt>'`,即 32 字节 AES key + 16 字节 salt,拼成 99 字符 hex 字符串传给 `PRAGMA key` | |
| 80 | +- 配套 PRAGMA:`PRAGMA cipher_compatibility = 4; PRAGMA cipher_page_size = 4096;` | |
| 81 | +- 密钥生命周期:**只在 WeChat 进程运行、且该账号数据库已被 WCDB 打开期间,短暂驻留在堆内存里**,新版本已经不会长期驻留(社区工具的 issue 里提到从某个版本开始"key 不再长期保留在内存数据中",需要在数据库刚打开的那个时间点抓)。 | |
| 82 | +- 提取手法(公开资料描述的方法,本次**没有实际操作**):用 `lldb` attach 到正在跑的 WeChat 进程,在它调用 `malloc(0x43)`(0x43=67 字节,密钥初始化分配的大小)前的 `mov x0/w0, #0x43` 指令处打断点,断点触发后用 `memory read` 把寄存器指向的内存读出来,就是上面那个 80 字节格式的密钥。 | |
| 83 | +- macOS 前置条件:**必须先 `csrutil disable`(关闭 SIP)**。正版 WeChat.app 是苹果公证签名、开了 Hardened Runtime 且没有 `get-task-allow` entitlement 的二进制,默认情况下任何第三方调试器都无法对它做 `task_for_pid`/attach,关 SIP 是公开资料里所有方法的共同前提。 | |
| 84 | + | |
| 85 | +## 5. 开源工具调研现状 | |
| 86 | + | |
| 87 | +| 项目 | 状态 | 备注 | | |
| 88 | +|---|---|---| | |
| 89 | +| [sjzar/chatlog](https://github.com/sjzar/chatlog) | **已完全删库** | 维护最好、用户最多的同类工具,作者收到微信官方函后以"合规风险"为由删除全部代码与提交历史,仓库只剩一份移除说明。**重要信号:这不是小项目,说明这类工具被腾讯主动追究过。** | | |
| 90 | +| [Thearas/wechat-db-decrypt-macos](https://github.com/Thearas/wechat-db-decrypt-macos) | 已 **archive**(上月,2026-05) | 文档明确写"只在微信 4.1.2.241 测试过",本机版本是 **4.1.5**,不保证特征码/偏移还对得上;archive 状态本身也说明作者放弃跟进新版本。 | | |
| 91 | +| [ylytdeng/wechat-decrypt](https://github.com/ylytdeng/wechat-decrypt) | 仓库仍在线 | 未实际验证,标称支持从内存提取密钥 + 解密 SQLCipher4 + 实时消息监控 | | |
| 92 | +| [cocohahaha/wechat-decrypt-macos](https://github.com/cocohahaha/wechat-decrypt-macos) | 仓库仍在线 | 标称用 Mach VM API 做内存提取 | | |
| 93 | +| [L1en2407/wechat-decrypt](https://github.com/L1en2407/wechat-decrypt) | 仓库仍在线 | 标称跨 Windows/macOS/Linux | | |
| 94 | +| [ydotdog/wechat-export-macos](https://github.com/ydotdog/wechat-export-macos) | 仓库仍在线 | 一键解密导出工具 | | |
| 95 | +| [nalzok/wechat-decipher-macos](https://github.com/nalzok/wechat-decipher-macos) | 仓库仍在线但很老 | DTrace 脚本方案,针对的是更老的单文件 `message.db` 时代客户端,跟本次目标(4.x `xwechat_files` 结构)不是同一套,方法论可能已经过时 | | |
| 96 | + | |
| 97 | +## 6. 风险评估 | |
| 98 | + | |
| 99 | +1. **法律/合规信号是真实且新鲜的**:chatlog 案例证明腾讯会主动对这类工具发函施压,即便用途是解密用户自己账号的本机数据,仍然落在微信 ToS"禁止反向工程"条款射程内,有现成的执法先例(不是假设性风险)。 | |
| 100 | +2. **系统级安全开关**:关闭 SIP 会削弱整机代码完整性保护,不只是对 WeChat 一个 App 生效,是机器级别的安全降级,且需要重启进恢复模式操作。 | |
| 101 | +3. **方案不稳定**:特征码/内存偏移跟具体版本号绑定,微信几乎每次更新都可能改变,本机当前版本(4.1.5/31960)没有任何一个已知工具明确验证过适配,等于每次都要重新逆向,不是一次性能跑通的方案。 | |
| 102 | + | |
| 103 | +## 7. 结论 / 暂定路线 | |
| 104 | + | |
| 105 | +**本次研究到此为止,没有进入实际解密阶段**。原因是上面三条风险叠加(法律先例 + 系统级改动 + 工程不稳定)已经足够大,在没有更强烈需求之前不值得动手。 | |
| 106 | + | |
| 107 | +低风险备选方案(如果只是要把 Mac 端聊天记录接进 Personal CRM,不追求结构化全量):微信客户端自带「聊天记录迁移与备份」「导出聊天记录」功能(设置内),走官方支持路径导出,不涉及逆向,但只能按对话手动导出 txt/html,不是可批量查询的结构化数据库。 | |
| 108 | + | |
| 109 | +如果以后要重新评估这件事,建议先确认: | |
| 110 | +- 微信 Mac 版本是否升到了某个已知被验证过的版本(关注上表里那些仍在维护的仓库的 issue 区,看有没有人报过跟当前版本匹配的成功案例); | |
| 111 | +- 用户对关闭 SIP + 潜在 ToS 风险的接受程度有没有变化。 | |
| 112 | + | |
| 113 | +## 参考链接 | |
| 114 | + | |
| 115 | +- [ylytdeng/wechat-decrypt](https://github.com/ylytdeng/wechat-decrypt) | |
| 116 | +- [L1en2407/wechat-decrypt](https://github.com/L1en2407/wechat-decrypt) | |
| 117 | +- [cocohahaha/wechat-decrypt-macos](https://github.com/cocohahaha/wechat-decrypt-macos) | |
| 118 | +- [Thearas/wechat-db-decrypt-macos](https://github.com/Thearas/wechat-db-decrypt-macos)(含《微信数据库解密.md》,内存特征码扫描法的具体描述来源) | |
| 119 | +- [nalzok/wechat-decipher-macos](https://github.com/nalzok/wechat-decipher-macos) | |
| 120 | +- [ydotdog/wechat-export-macos](https://github.com/ydotdog/wechat-export-macos) | |
| 121 | +- [sjzar/chatlog](https://github.com/sjzar/chatlog)(**已删库**,仅剩移除声明,记录其曾经存在过且被官方函下架这件事本身) | ... | ... |