教 AI 助手"读懂"你的微信:Hermes Agent 对接微信全记录(含 4.x 本地数据库解密)
让 AI 助手帮我总结"今天微信有什么重要消息",听起来是个很自然的需求。但微信没有开放个人消息 API,怎么办?这篇文章记录了我如何一步步让开源 Agent 框架 Hermes 真正"读"到我电脑端微信的聊天记录——从官方机器人对接,到硬啃微信 4.x 加密数据库,再到把它沉淀成一个随叫随到的技能。
我日常用电脑端微信,消息很多。我希望有一个 AI 助手能:
- 每天帮我扫一遍微信,挑出真正重要的消息(工作跟进、通知、家人的事);
- 过滤掉购物群刷屏、广告;
- 我随时问"昨天 XX 群聊了什么""导出和某人的记录",它能答上来。
难点很直接:微信不给第三方读个人消息的接口。所以路只有两条——
①能让 AI"在微信里跟你对话",但读不到你和别人的记录;②才能真正读历史。我两条都做了,①是基础,②是重头戏。
⚠️ 先说合规:本文所有操作都只针对你自己账号、你自己电脑上的数据,用于个人备份与整理。请勿用于读取他人数据,尊重隐私。
Hermes Agent 是 Nous Research 开源的 Agent 框架,可以理解成"可以接各种聊天平台、带工具调用、能装技能(Skill)的 AI 助手运行时"。
我的操作环境:
- macOS 12(Intel x86_64)——老系统,后面会有坑
- Python venv 由 Hermes 自带(~/.hermes/hermes-agent/venv)
- 大模型接的是阿里云百炼(qwen 系列,走 Anthropic 兼容接口)
Hermes 的几个关键概念,后面会反复用到:
- Gateway(网关):常驻服务,负责接收各平台消息(微信、Telegram 等),由 launchd 托管。
- api_server:网关内置的 OpenAI 兼容接口,本机 127.0.0.1:8642。
- Skill(技能):~/.hermes/skills/<分类>/<技能名>/SKILL.md,告诉 AI"遇到 XX 类任务该怎么做"。
- SOUL.md:~/.hermes/SOUL.md,身份层提示词,会注入到每个会话,优先级很高。
Hermes 内置了 weixin 平台,走腾讯 iLink Bot API(长轮询,不是公开 webhook)。
hermes gateway setup# 选 Weixin → 手机微信扫码 → 按提示完成
成功后会在 ~/.hermes/.env 里写入一组 WEIXIN_* 配置:
WEIXIN_ACCOUNT_ID=<你的bot账号>@im.botWEIXIN_TOKEN=<token>WEIXIN_BASE_URL=https://ilinkai.weixin.qq.comWEIXIN_DM_POLICY=allowlist # 只允许白名单用户私聊WEIXIN_ALLOWED_USERS=<你自己的wxid>WEIXIN_GROUP_POLICY=disabled # 群聊关掉
重启网关后,你在微信里给这个 bot 发消息,它就是 Hermes 了:
hermes gateway restart这条路的能力边界要清楚:bot 身份只能收发"发给它"的消息,读不到你和别人的聊天记录,普通群也基本进不去(iLink 侧限制)。所以我把它当成"对话入口",读历史交给第二步。
电脑端微信的本地数据在这里:
~/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files/<账号>/db_storage/下面按功能分目录:message(聊天)、contact(通讯录)、session、sns(朋友圈)、favorite(收藏)……每个 .db 都是 SQLCipher 4 加密库,参数是:
- AES-256-CBC,HMAC-SHA512
- PBKDF2 派生,仅 2 轮
- 页大小 4096,每页保留 80 字节,盐 16 字节
解铃还须系铃人:只要能拿到那把 32 字节的主密钥,就能整库解密。
以前的工具(以及我一开始的尝试)是扫描微信进程内存,找形如 x'<64位hex密钥><32位hex盐>' 的明文。但 WeChat 4.1.10+ 把这层明文缓存删了,还裁掉了 SQLCipher 符号。我实测内存扫描:
Scan complete: 1241MB scanned, 609 regions, 0 unique keys一个密钥都没有。路被堵死了。
微信解密每一页数据,最终都要调用系统加密库 CommonCrypto 的 AES 原语(CCCrypt / CCCryptorCreate / CCCryptorCreateWithMode),而那把 32 字节主密钥会作为参数传进去。思路就是:用 lldb 在这几个函数上打断点,把参数里的密钥读出来。
我参考了社区的思路,但原版只支持 ARM64(M 系列芯片)。我的是 Intel x86_64,得按 System V AMD64 调用约定重写寄存器映射:
lldb 钩子脚本核心逻辑(Intel 适配版):
import lldbOUT = "/tmp/hunted_keys.txt"_seen = set()def _log_key(frame, kptr, klen):if klen != 32 or not kptr:returnerr = lldb.SBError()data = frame.GetThread().GetProcess().ReadMemory(kptr, 32, err)if not err.Success() or not data:returnh = data.hex()if h in _seen:return_seen.add(h)open(OUT, "a").write(h + "\n")print("KEY32[%d]: %s" % (len(_seen), h))def on_cccrypt(frame, bp_loc, extra, internal_dict):# key=rcx, len=r8_log_key(frame, frame.FindRegister("rcx").GetValueAsUnsigned(),frame.FindRegister("r8").GetValueAsUnsigned())return Falsedef on_ccmode(frame, bp_loc, extra, internal_dict):# key=r9, len=栈[rsp+8]kptr = frame.FindRegister("r9").GetValueAsUnsigned()rsp = frame.FindRegister("rsp").GetValueAsUnsigned()err = lldb.SBError()raw = frame.GetThread().GetProcess().ReadMemory(rsp + 8, 8, err)klen = int.from_bytes(raw, "little") if err.Success() and raw else 0_log_key(frame, kptr, klen)return False
注意一个前置坑:微信是带官方签名的,直接 attach 会被拒,需要先重签(ad-hoc):
osascript -e 'quit app "WeChat"'; killall WeChat 2>/dev/nullsudo xattr -cr /Applications/WeChat.appsudo codesign --force --deep --sign - /Applications/WeChat.app
然后 attach 并触发(看到 keyhunt armed 后,切回微信,多打开几个聊天、翻翻朋友圈/收藏/通讯录,每出现一行 KEY32[n] 就是抓到一把):
PID=$(pgrep -x WeChat | head -1)sudo lldb -p "$PID" \-o "command script import /path/to/keyhunt.py" \-o "keyhunt_start" -o "continue"
最终抓到了 14 把密钥。
抓到一堆密钥,怎么知道哪把对应哪个库?用 SQLCipher 的第 1 页 HMAC 校验(参数无关,不依赖能否打开库):
import hashlib, hmac, structPAGE, RESERVE, HMAC = 4096, 80, 64def mac_key_for(enc_key, salt):mac_salt = bytes(b ^ 0x3A for b in salt)return hashlib.pbkdf2_hmac("sha512", enc_key, mac_salt, 2, dklen=32)def page1_ok(enc_key, p1):salt = p1[:16]mk = mac_key_for(enc_key, salt)data = p1[16: PAGE - RESERVE + 16] + struct.pack("<I", 1)return hmac.new(mk, data, hashlib.sha512).digest() == p1[PAGE - HMAC:]
能对上,就说明这把密钥能解这个库。结果:主账号 18 个库匹配上 14 个(聊天、通讯录、朋友圈、收藏等核心库全中;表情、媒体等 4 个库用了别的密钥,暂缺)。
有了密钥,用开源工具(我基于 ydotdog/wechat-export-macos 的解密/导出逻辑)整库解密,产物就是普通 SQLite:
python decrypt_db.py # 14 成功, 4 失败python export_chat.py --list # 按消息数列出所有会话
到这一步,数据已经能读了。
光能解密不够,我要的是"我交代一句,Hermes 自己去读"。这里做了三件事,也踩了三个坑。
我把工具包固定放在 ~/wxdecrypt/,并让 Hermes 每次现取现解密(不做后台同步,只在任务时跑):
# 1. 同步最新加密库rsync -a --prune-empty-dirs --include='*/' --include='*.db' --exclude='*' \"$HOME/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files/<账号>/db_storage/" \~/wxdecrypt/live/# 2. 解密cd ~/wxdecrypt && rm -rf decrypted && python decrypt_db.py# 3. 每日摘要(跨所有聊天按日期统计)python ~/wxdecrypt/today_digest.py
在 ~/.hermes/skills/messaging/wechat-local/SKILL.md 里写清楚"何时用、怎么用、密钥在哪、失效怎么重抓",让 Hermes 任何会话里看到"查微信"类任务都能对上。
1、加了 Skill 不生效,必须重启网关。Hermes 把"可用技能列表"缓存在进程里,缓存键不含文件修改时间,所以新建的 Skill 不会自动被发现。改完 Skill 或 SOUL.md 后:
hermes gateway restart2、模型"自认为"读不了微信,直接拒绝。我接的模型有个很强的先验——"微信不开放 API 给第三方"。即使 Skill 已经在可用列表里,它也懒得看,直接回"我无法访问你的聊天记录"。解法:在 SOUL.md(身份层,优先级最高)里明确授权——"你可以通过 wechat-local 读本机微信数据,别声称读不了"。加完后,它不再拒绝了。
3、不拒绝了,但它开始"自由发挥"。授权之后,模型会去读了,却经常不用我给的脚本,而是自己写 python -c / 屏幕抓取之类的野路子,还反复触发危险命令审批。解法有两层:
- 把正确命令写死进 SOUL.md,并明确禁止 execute_code/osascript/自写分析代码;
- 提供一个确定性的每日摘要脚本 today_digest.py(跨所有聊天、按日期统计、自动过滤压缩消息),模型照抄一条命令就行。
另外有个隐藏关键:如果之前的会话里已经积累了一堆错误尝试,模型会照着旧错误继续错。这时在微信里发 /new 开新会话(记得对确认框回 /approve,否则不会真的重置),再重新问。
现在我在微信里直接问 Hermes:
我:看看昨天的消息,有没有重要的事情
它会自己跑"同步→解密→摘要",然后给出类似这样的回答(示意):

干净会话里它发挥得很稳:数字准确、会抓重点、会主动过滤噪音。
- 版本敏感:微信 4.1.x 的密钥策略、Hermes 的缓存行为都可能随版本变。本文基于 WeChat 4.1.11 + Hermes 0.19,思路通用,细节需按你的版本核对。
- 老系统有坑:我在 macOS 12(Intel)上,很多新工具/新二进制不兼容,CCCrypt 钩子也要按 x86_64 重写寄存器映射。M 系列芯片请用 ARM64 版。
- 审批要分清:正确流程的命令(rsync/decrypt_db.py/today_digest.py)可以放心 /approve always;但 osascript/execute_code/python -c 这种野路子要 /deny。
- 合规底线:只解密你自己账号、你自己设备上的数据,用于个人备份与整理。技术本身中性,边界在使用者。
整个过程最有意思的不是某个具体技巧,而是一个规律:把不稳定的"模型自由发挥",逐步收敛成确定性的"一条命令 + 明确授权"。模型会有先验、会偷懒、会即兴,而我们要做的是用提示词(SOUL.md)、技能(Skill)和脚本,把正确的路铺成阻力最小的那条。
后续还可以把hermes的微信能力设置为一个专职微信助手Profile。
涉及工具:Hermes Agent、lldb、SQLCipher、wechat-export-macos 等,排名不分先后,感谢开源社区。
感谢阅读 · 欢迎分享
夜雨聆风