微信本地数据提取完全指南(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 anthropic

2.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 bytes 28 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

启动后需要:

  1. 在签名版微信中登录
  2. 打开「收藏」页面(触发 favorite.db 密钥加载)
  3. 等待 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 pycryptodome

4.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.html

4.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/临时储存/我的朋友圈/我的朋友圈.md

5.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.jsonfrida 提取的数据库密钥
wechat-cli 配置~/.wechat-cli/config.jsonwechat-cli 数据目录配置
wechat-cli 密钥~/.wechat-cli/all_keys.jsonwechat-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 提取。日常生成日报不需要打开签名版微信,只需要密钥文件。