我们做了个工具,把 macOS 上你自己的微信变成给 AI agent / 脚本用的本地接口:发消息、查会话、读历史,全在你这台 Mac 上,不上云、不走 iPad 协议。
第一次跑通那天挺有成就感。然后微信更新了。

版本永远在前面跑
工具的原理,是直接读微信的本地数据库、并在内存里定位到几个关键函数和字段。问题是这些"东西在哪"全都依赖具体版本:微信每次小版本号往上跳(4.1.8 → 4.1.9 → 4.1.10),编译出来的二进制就可能把函数挪个位置、把结构体字段换个偏移。对普通用户毫无感知,对我们就是当场失灵。
所以这个项目的日常不是"做新功能",是追。跑步机上那个小人就是本人,绿气泡永远在够不着的前面。
一更新就崩,而且常常是悄悄崩

更刺激的是静默热更:微信会在后台把核心组件(那个承载全部逻辑的动态库)换成新版,不弹任何对话框。你早上还好好的,下午脚本就开始报错,而你根本不知道二进制已经被换了。每次排查都得先确认一句:"是不是又热更了?"
这逼着我们做的第一件事,反而是关掉它的自动热更——锁住更新路径,让当前这套适配别被半夜偷偷打掉,争取一个能稳定干活的窗口。
取 key:三代办法,被微信逼着升级

微信的本地库是 SQLCipher 加密的,要读数据就得先拿到那把 32 字节的原始密钥。这一块我们换了三代办法,每一代都是被新版本逼出来的:
第一代——扫堆里的密钥文本。 SQLCipher 解库时会执行类似 PRAGMA key = "x'……'" 的语句,早期版本里这串十六进制密钥文本会残留在进程堆里。直接扫进程内存、匹配这个形状,就能把 key 捞出来。4.1.9 还能用。
第二代——扫二进制密钥 + 用页头 HMAC 验证。 等微信不再把密钥以明文文本留在堆里之后,第一代就废了。退而求其次:把堆里每一段 32 字节都当候选密钥,拿数据库第一页的 HMAC 去验(SQLCipher 每页带 HMAC 校验,密钥不对就过不了)。能验过的就是真 key。问题是到 4.1.10,扫遍几百 MB 堆、几百万个候选,HMAC 命中数是零——明文密钥根本不在堆里了。而且扫一遍要几十分钟,慢到不像个能用的办法。
第三代——断点打在系统加密函数上。 关键转念:密钥不在堆里,但它一定会"流过"某个地方。SQLCipher 底层用的是 macOS 系统的 CommonCrypto,每解一个库都要调 CCCryptorCreate 建 AES 上下文,而这个系统函数的符号没被剥掉。把断点下在它身上,当密钥长度是 32 时,参数里那个指针指向的就是 key。一抓一个准。
4.1.10 还顺手把密钥模型也改了:从"一把主密钥"变成每个库一把(per-DB key)。所以得让微信把各个库都解密一遍,断点才能把钥匙抓全。
一句话总结这张图:每翻一个大版本,钥匙就换一种藏法,旧办法凑到锁孔前总是差那么一点。
后台发消息:得改"这条发给谁"
发消息比读数据难得多。我们要的是完全后台、不抢你鼠标焦点地把一条消息发出去。这就绕不开一个问题:微信怎么知道这条消息该进哪个会话?
内存里有一个字段,记着"当前这条要发给谁"。后台发送的思路,是在发送链路的某个断点处,把这个路由字段改写成我们的目标,让下游照着新值把消息投出去。在好几个版本上,这招是通的。
到 4.1.10 卡住了,而且卡得很有教育意义:我们顺着特征找到一个"看起来就是路由 wxid"的字段,改它——结果消息照样进了原来那个会话。后来才搞明白,那个字段是个被写入的副本(某个 setter 往里填的),根本不是下游真正读来决定路由的那个点。改副本,源头照旧。真正的路由读取点还没找到。
真正能复用的,是方法不是位置
追了一串版本之后,最值钱的一条经验是:
你记下来的所有"具体地址、偏移、版本指纹",下个版本基本全废。能跨版本活下来的,只有"怎么把东西找出来"的方法。
具体哪些能复用、哪些必废,大概是这样:
- 必废:硬编码的函数地址、字段偏移、二进制指纹——腾讯重排一次全过期。
- 能复用:用特征指令序列去定位函数(比如某个函数体里有一条很独特的指令,全二进制只此一处,靠它能在新版本里重新找到这个函数);用函数大小 + 调用链拓扑做指纹(腾讯热更往往只搬位置、不改函数体,所以大小和形状能跨版本对上);以及结构性的教训——像上面那个"setter 副本不是真路由点",是会一直管用的认知。
所以真正的护城河不是某一次破解的结果,是攒下来的一套找东西的手艺。结果会过期,手艺不会。
现在爬到哪了

诚实交代到最新的 4.1.10:
- 读通了——靠第三代取 key 办法(断点 CommonCrypto),会话、历史、联系人都能正常取。
- 发还没翻过去——卡在上面那个"真正的路由读取点还没找到"的环节。
图里插旗打勾的半山腰就是现状,山顶那个红叉是还在爬的部分。不装"全部搞定"——做这种贴着别人应用内部结构的适配,永远有下一个版本、下一个山头。
写在最后
定位一直没变:本地优先、不上云、数据完全在你自己手里。它是 *-use 系列的一员(还有 profile-use、iphone-use),都是让 agent 直接操作你本地的真实工具,而不是把数据搬到别人的服务器上。
代码、装法、能力边界都在仓库里:github.com/leeguooooo/wechat-use。仅供个人 / 研究用途——商业、群发、自动化别人的账号一律不在支持范围内。
追版本这事还在继续。下一个山头见。
评论
评论发布后会立即公开,如触发规则可能被审核下架。