微信本地数据提取完全指南(macOS)
适用于微信 Mac 4.x 版本。实操验证于 2026-04-17。
核心原理:微信 Mac 的所有数据(聊天记录、收藏、朋友圈、联系人)都以加密 SQLite 数据库存储在本地。加密方式为 SQLCipher 4(AES-256-CBC + PBKDF2 256000轮)。密钥在微信进程内存中,通过 frida 动态 hook 提取,之后可离线解密数据库文件副本。
一、涉及的 GitHub 仓库
| 仓库 | 用途 | 地址 |
|---|---|---|
| wx-favorites-report | 微信收藏解密、解析、HTML可视化报告 | https://github.com/zhuyansen/wx-favorites-report |
| wechat-cli | 命令行工具:聊天记录查询、搜索、导出、联系人、收藏等 | https://github.com/freestylefly/wechat-cli |
二、环境准备
2.1 安装依赖
pip3 install pycryptodome zstandard frida frida-tools anthropic2.2 微信数据目录
~/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files/wxid_xxx_xxxx/db_storage/
├── contact/contact.db # 联系人
├── message/message_0.db # 聊天记录(每个会话一个 Msg_{md5(username)} 表)
├── session/session.db # 会话列表
├── favorite/favorite.db # 收藏
├── sns/sns.db # 朋友圈
├── emoticon/emoticon.db # 表情
└── ...
wxid_xxx_xxxx路径因账号不同而不同,在xwechat_files下能找到。
2.3 数据库加密参数
| 参数 | 值 |
|---|---|
| 加密算法 | AES-256-CBC |
| 密钥派生 | PBKDF2-HMAC-SHA512,256000轮 |
| 页大小 | 4096 字节 |
| 每页保留区 | 80 字节(最后80字节) |
| IV | 保留区前16字节 |
| 首页特殊 | 前16字节为 SQLite 文件头,不加密 |
2.4 消息内容编码
local_type=1:纯文本或 ZSTD 压缩文本(magic bytes28 b5 2f fd)local_type=3:图片(内容为加密二进制)local_type=34:语音local_type=43:视频local_type=47:表情/贴纸local_type=10000:系统消息(撤回通知等,XML 格式)- 其他大数字类型:微信 4.x 扩展消息类型,内容均为加密二进制
三、密钥提取(只需做一次)
3.1 准备签名版微信
macOS 的 Hardened Runtime 会阻止外部程序读取微信进程内存。需要复制微信并去掉这个保护:
# 复制微信到桌面
cp -R /Applications/WeChat.app ~/Desktop/WeChat.app
# 用 ad-hoc 签名替换原签名(去掉 Hardened Runtime)
codesign --force --deep --sign - ~/Desktop/WeChat.app这不会影响
/Applications/WeChat.app原版微信。签名版只在提取密钥时使用。
3.2 用 frida 提取密钥
# 1. 关闭原版微信
killall WeChat 2>/dev/null; sleep 2
# 2. 用 frida spawn 模式启动签名版微信,hook PBKDF2 函数frida 脚本(保存为 extract_keys.js):
function buf2hex(buffer) {
var a = new Uint8Array(buffer); var h = '';
for (var i = 0; i < a.length; i++) h += ('0' + a[i].toString(16)).slice(-2);
return h;
}
var found = false;
Process.enumerateModules().forEach(function(m) {
if (found) return;
m.enumerateExports().forEach(function(exp) {
if (found) return;
if (exp.name === "CCKeyDerivationPBKDF") {
found = true;
send("[*] Hook installed on " + m.name);
Interceptor.attach(exp.address, {
onEnter: function(args) {
this.pwLen = args[2].toInt32();
this.saltLen = args[4].toInt32();
this.rounds = args[6].toInt32();
this.pw = args[1]; this.salt = args[3];
this.dk = args[7]; this.dkLen = args[8].toInt32();
},
onLeave: function(retval) {
if (this.pwLen < 4 || this.pwLen > 256) return;
if (this.saltLen < 4 || this.saltLen > 64) return;
var saltHex = buf2hex(this.salt.readByteArray(this.saltLen));
var dkHex = buf2hex(this.dk.readByteArray(this.dkLen));
var pwHex = buf2hex(this.pw.readByteArray(this.pwLen));
send("[PBKDF2] r=" + this.rounds + " salt=" + saltHex);
var f = new File("/tmp/wechat_frida_keys.log", "a");
f.write("rounds=" + this.rounds + "\\npw=" + pwHex + "\\nsalt=" + saltHex + "\\ndk=" + dkHex + "\\n\\n");
f.flush(); f.close();
}
});
}
});
});
if (!found) send("[!] CCKeyDerivationPBKDF not found");Python 启动脚本:
import frida, time, os
device = frida.get_local_device()
pid = device.spawn([os.path.expanduser("~/Desktop/WeChat.app/Contents/MacOS/WeChat")])
session = device.attach(pid)
with open("extract_keys.js") as f:
js_code = f.read()
script = session.create_script(js_code)
script.on("message", lambda msg, data: print(msg.get("payload", msg)))
script.load()
device.resume(pid)
print("=== WeChat started. Login → open Favorites → wait 120s ===")
time.sleep(120)
session.detach()
print("=== Done. Check /tmp/wechat_frida_keys.log ===")3.3 运行提取
python3 extract_keys.py启动后需要:
- 在签名版微信中登录
- 打开「收藏」页面(触发 favorite.db 密钥加载)
- 等待 120 秒
密钥日志在 /tmp/wechat_frida_keys.log。256000 轮的 PBKDF2 输出(dk 字段)就是数据库密钥。
3.4 匹配密钥到数据库
每个密钥对应一个数据库,通过 salt 匹配(salt = 数据库文件第17-32字节):
import hashlib
# 将密钥保存到配置文件
keys = {
"message_0": "提取到的64位hex密钥",
"contact": "...",
"session": "...",
"favorite": "...",
"sns": "...",
}
# 保存
import json
with open(os.path.expanduser("~/.config/wechat-keys.json"), "w") as f:
json.dump(keys, f, indent=4)密钥在微信不更新大版本的情况下不会变。提取一次即可长期使用。
3.5 清理
# 密钥已保存,可以删除签名版微信
rm -rf ~/Desktop/WeChat.app四、微信收藏导出
4.1 使用 wx-favorites-report
仓库地址:https://github.com/zhuyansen/wx-favorites-report
# 克隆仓库
cd ~/Downloads
git clone https://github.com/zhuyansen/wx-favorites-report.git
# 安装依赖
pip3 install pycryptodome4.2 解密收藏数据库
收藏数据库使用不同的加密方式(逐页 AES-256-CBC + HMAC-SHA512 校验),仓库内含解密脚本。
4.3 解析与可视化
# 解析解密后的 favorite.db
python3 ~/Downloads/wx-favorites-report/parse_favorites.py \
--input ~/tmp/wechat_daily/favorite_decrypted.db \
--output ./data.json
# 生成交互式 HTML 报告
python3 ~/Downloads/wx-favorites-report/generate_report.py \
--input ./data.json \
--output ./report.html
# 预览
open ./report.html4.4 收藏类型说明
| Type | 含义 | 可提取字段 |
|---|---|---|
| 1 | 文本 | desc |
| 2 | 图片 | datafmt + fullsize |
| 4 | 视频 | datatitle + datadesc |
| 5 | 文章/链接 | pagetitle + pagedesc + link |
| 8 | 文件 | datatitle + datafmt |
| 14 | 聊天记录 | datalist → 逐条拼接 |
| 其他 | 位置/笔记/小程序等 | title + desc |
4.5 导出到 Obsidian
收藏数据可分类整理后保存为 Markdown:
~/obsidian/临时储存/微信收藏整理/
├── AI工具与教程.md
├── 投资理财.md
├── 创业与商业.md
├── ...
五、微信朋友圈导出
5.1 数据来源
朋友圈数据在 sns.db 中:
sns.db → 表结构:
- sns_post:朋友圈帖子
- sns_comment:评论
- sns_like:点赞
5.2 只导出自己发的
-- 筛选自己发的朋友圈(通过 userName 字段过滤自己的 wxid)
SELECT * FROM sns_post WHERE userName = 'wxid_yfio8tnzkk3o22'5.3 导出脚本
将解密后的 sns.db 查询结果导出为 Markdown:
# 输出位置
~/obsidian/临时储存/我的朋友圈/我的朋友圈.md5.4 已知限制
- 图片来自微信 CDN,需要 Token 认证,无法通过 URL 直接下载
- 目前只能导出文字内容,图片需手动从微信保存
六、微信聊天日报
6.1 方案一:wechat_daily.py(当前使用)
脚本位置:~/scripts/wechat_daily.py
功能:
- 自动解密 message_0.db、contact.db、session.db
- 按日期提取所有聊天记录
- 自动解压 ZSTD 压缩消息
- 按消息类型分类(文本/图片/语音/视频/表情/系统消息)
- 生成 Markdown 格式日报,按会话分组
运行:
# 生成今天的日报
python3 ~/scripts/wechat_daily.py
# 生成指定日期的日报
python3 ~/scripts/wechat_daily.py 2026-04-17输出位置:~/obsidian/临时储存/微信日报/YYYY-MM-DD.md
定时任务(crontab):
# 每天 23:55 自动生成日报
55 23 * * * /usr/bin/python3 /Users/yichen/scripts/wechat_daily.py >> /tmp/wechat_daily.log 2>&1密钥文件:~/.config/wechat-keys.json
依赖:pycryptodome, zstandard
6.2 方案二:wechat-cli
仓库地址:https://github.com/freestylefly/wechat-cli
# 安装
npm install -g @canghe_ai/wechat-cli
# 或从 https://github.com/freestylefly/wechat-cli/releases 下载
# 初始化(需要签名版微信 + sudo)
sudo wechat-cli init
# 如果已有密钥,手动创建配置:
# ~/.wechat-cli/config.json → { "db_dir": "..." }
# ~/.wechat-cli/all_keys.json → { "message/message_0.db": { "enc_key": "...", "salt": "..." } }常用命令:
wechat-cli sessions # 最近会话列表
wechat-cli history "群名" --limit 20 # 查看最近20条消息
wechat-cli search "关键词" # 全局搜索消息
wechat-cli contacts --query "张" # 搜索联系人
wechat-cli export "群名" --format md # 导出为 Markdown
wechat-cli new-messages # 获取增量新消息
wechat-cli stats "群名" # 聊天统计
wechat-cli favorites # 查看收藏
wechat-cli members "群名" # 群成员列表
wechat-cli unread # 未读会话优势(对比 wechat_daily.py):
- 单二进制,无 Python 依赖
- 自动解析联系人备注名(不需要手动 hash 映射)
- JSON 输出,天然适合接入 AI
- 支持增量消息、搜索、导出等更多功能
劣势:
- 闭源二进制,无法审计
- 需要 sudo 或签名版微信才能提取密钥
6.3 AI 生成精华摘要(手动流程)
原始日报生成后,可让 Claude 按以下提示词生成精华版:
你是一个群聊精华提取专家,擅长从碎片化的聊天记录中提炼有价值的信息。
任务:分析微信群聊天记录,生成精炼的群聊总结。
输出格式:
1. 开头:1-2段概括当天最核心的内容
2. 正文:按群分类,每个群提取有价值的讨论要点
3. 结尾:固定格式"本简报由AI自动生成"
分类参考:工具技巧、资源推荐、行业动态、观点碰撞、群友趣事
格式:不用 markdown 加粗和标题,用 emoji + 列表
重点突出,过滤闲聊,保留关键人名和链接
七、安全性说明
7.1 对微信账号的影响
| 操作 | 风险 |
|---|---|
| 复制并签名微信 | 仅本地操作,微信服务器无感知 |
| frida hook 提取密钥 | 进程注入,微信理论上可检测,但当前版本未做反调试 |
| 用密钥解密数据库副本 | 纯读文件副本,不影响微信正常运行 |
| 日常使用原版微信 | 完全不受影响 |
7.2 密钥安全
- 密钥文件存储在本地(
~/.config/wechat-keys.json和~/.wechat-cli/all_keys.json) - 拥有密钥 = 可以读取所有微信聊天记录,务必保护
- 建议收紧文件权限:
chmod 600 ~/.config/wechat-keys.json
7.3 解密数据库残留
~/tmp/wechat_daily/下有解密后的数据库文件(约95MB),包含所有聊天记录明文- 建议定期清理或加入
.gitignore
八、文件速查
| 文件 | 路径 | 说明 |
|---|---|---|
| 日报脚本 | ~/scripts/wechat_daily.py | 聊天日报生成器 |
| 密钥文件 | ~/.config/wechat-keys.json | frida 提取的数据库密钥 |
| wechat-cli 配置 | ~/.wechat-cli/config.json | wechat-cli 数据目录配置 |
| wechat-cli 密钥 | ~/.wechat-cli/all_keys.json | wechat-cli 用的密钥 |
| 收藏工具 | ~/Downloads/wx-favorites-report/ | 收藏导出工具 |
| wechat-cli | ~/Downloads/wechat-cli/ | 命令行工具 |
| 日报输出 | ~/obsidian/临时储存/微信日报/ | 每日聊天日报 |
| 收藏整理 | ~/obsidian/临时储存/微信收藏整理/ | 分类后的收藏内容 |
| 朋友圈 | ~/obsidian/临时储存/我的朋友圈/ | 自己发的朋友圈 |
| 解密临时文件 | ~/tmp/wechat_daily/ | 解密后的数据库副本 |
九、常见问题
Q: 密钥什么时候需要重新提取? A: 微信大版本更新时(如 4.x → 5.x)。日常小更新不影响。
Q: 双开微信怎么做?
A: open -n /Applications/WeChat.app,可以登录第二个微信账号。两个账号数据目录独立。
Q: 为什么日报里有些消息显示乱码? A: 非文本消息(图片、语音、视频、表情)的 message_content 是加密二进制。脚本已按 local_type 过滤,文本消息会自动解压 ZSTD 格式。
Q: 朋友圈图片能导出吗? A: 目前不能。图片存在微信 CDN,需要 Token 认证。只能导出文字内容,图片需手动从微信保存。
Q: wechat-cli 和 wechat_daily.py 用哪个? A: wechat-cli 功能更全(搜索、导出、增量消息),适合日常查询。wechat_daily.py 是我们自己的脚本,代码透明可审计,适合自动化日报。可以并用。
Q: 日报什么时候需要密钥? A: 只在微信大版本更新时需要重新用 frida 提取。日常生成日报不需要打开签名版微信,只需要密钥文件。