最近一直在折腾微信4.0的Hook,前面先在Mac微信4.1.6.12上做了验证,后来又开始研究Windows微信4.1.12.26。
最开始,我也是按照网上常见的思路,从微信上层的消息发送逻辑往下找。后来发现,这种方式虽然能做出来,但版本依赖比较严重。微信只要更新一次,之前分析的调用关系和数据结构就可能发生变化,很多工作又要重新做。
继续往下分析时,我注意到了腾讯开源的Mars通信框架。
Mars本身是一套跨平台的通信组件,Mac、Windows和Android都可以使用。微信三个平台的界面和上层代码虽然不一样,但消息最终还是要进入底层通信链路。
所以我产生了一个想法:如果不一直盯着某个平台的聊天窗口和上层业务函数,而是从更底层的任务链路入手,有没有可能整理出一套Mac、Windows和Android都能参考的方案?
先说明一下目前的进度。
Mac微信4.1.6.12已经做过实际验证,可以从底层链路触发一条文本消息。Windows端目前主要围绕4.1.12.26版本进行适配。Android端暂时还没有完成实机验证。
所以这里说的“三端可行”,指的是三个平台存在可以复用的分析思路,不是说同一份脚本复制过去就能直接运行。
为什么选择从Mars入手?
普通用户在微信里发送消息时,看到的过程很简单:输入文字,按下回车,对方收到消息。
但是在客户端内部,这条消息还要经历对象创建、任务提交、数据转换、网络发送和结果回调等过程。
我这次关注的就是这条底层任务链路。
相比界面层的按钮和窗口,底层通信框架受UI改版的影响更小。而且Mars本来就考虑了跨平台使用,这使得Mac、Windows和Android之间可能存在一些相近的处理逻辑。
当然,这并不代表三个平台完全一样。
Mac和Windows的程序格式、调用约定和模块结构不一样,Android端还涉及Java层和Native层之间的调用。即使最后使用了相同的底层框架,编译之后的函数形式、参数传递和对象布局也可能不同。
因此,Mars只能作为一个共同入口,不能把它理解成现成的微信消息接口。
Mac端是怎么验证的?
Mac端测试使用的是微信4.1.6.12。
开始的时候,我先正常发送消息,观察这次操作会经过哪些调用。顺着任务提交过程往下看,基本可以确认上层消息最后会进入底层的任务处理流程。
找到任务入口只是第一步,后面真正麻烦的是消息内容。
如果只是触发任务,却没有提供正确的消息数据,任务即使执行了也发不出有效内容。我最开始尝试在前面的数据转换阶段处理,但里面的数据引用关系比较复杂,部分对象又存在生命周期问题,调试起来很不直观。
后来换了个思路,没有继续在最上层硬套数据,而是在消息已经接近最终传输形式的位置进行验证。这样需要处理的中间对象少了一些,也更容易判断问题究竟出在任务触发阶段,还是出在数据构造阶段。
最终的测试结果是,对方可以收到一条“hello world”。
不过这里出现了一个挺有意思的问题:接收方能看到消息,发送方Mac微信的聊天窗口里却看不到这条消息。
这说明发送链路确实已经走通了,但本地消息记录和界面更新没有同步完成。
正常使用微信发送消息时,除了把内容交给网络层,客户端还会更新本地聊天记录、会话列表和消息状态。我目前验证的是偏底层的发送能力,没有完整走完上层的本地处理流程。
所以这次结果只能算“底层发送成功”,还不能说已经完全等同于用户手动发送。
最容易忽略的是内存回收
调试过程中还有一个比较容易踩的坑:消息发出去以后,程序不一定马上出问题,但任务结束时可能突然崩溃。
原因一般不是发送失败,而是内存归属没有处理好。
微信完成一次任务后,会按照自己的逻辑清理相关对象。如果中途放进去的数据不是按照原来的方式创建,或者数据仍然挂在某个待回收对象上,任务结束时就可能释放到一块不该由它处理的内存。
这种问题比“消息发不出去”更难排查,因为前面的流程看起来全是正常的,甚至对方已经收到消息了,最后客户端却在收尾阶段异常退出。
因此,做这类验证不能只看一次发送是否成功,还需要连续测试,观察任务结束、对象释放和线程退出时是否稳定。
很多网上的微信Hook演示,只展示“成功收到一条消息”的截图。但能成功一次,和能够长时间稳定运行,完全是两个概念。
Windows 4.1.12.26能不能使用同样的思路?
从整体方向看,我认为是可行的,但不能直接照搬Mac端的实现。
Windows微信4.1.12.26需要重新确认对应模块、任务入口和参数传递方式。即使业务逻辑相似,编译到不同平台以后,实际看到的代码结构也可能有明显区别。
另外,微信4.x仍然在持续更新。即使同属于4.1系列,不同小版本也不能默认直接兼容。
因此,我在Windows端首先做的是版本识别。只有当前客户端版本与已适配版本一致时,才允许加载对应能力。版本不一致就停止,而不是强行继续调用。
这一步看起来比较保守,但比客户端升级以后直接崩溃要可靠得多。
如果后面需要兼容多个版本,也应该为每个经过验证的版本单独维护适配信息,而不是对外宣称“微信4.0全部通用”。
Android端还需要单独验证
Android理论上也能从Mars相关的任务链路继续分析,但它与桌面端的环境区别更大。
Android客户端既有上层应用代码,也有Native模块,还要考虑不同系统版本、处理器架构和运行环境。能不能找到相似逻辑是一回事,能不能稳定地完成参数处理又是另一回事。
目前Android端我还没有完成实机验证,所以暂时不把它写成已经实现的功能。
不过从整体架构来看,如果三个平台最终都能完成适配,外部业务层可以使用同一种消息格式和调用方式。平台差异只留在最底层,上面的C#、Java或者Python程序不需要关心消息究竟来自Mac、Windows还是Android。
这也是研究三端共性的主要价值。
这类方案真正难的不是找到一个函数
不少人把微信Hook理解成“找到地址,然后调用一下”。
真正做起来以后会发现,找到一个疑似函数可能并不是最难的。后面还有一系列问题:
当前版本是否匹配,参数到底是什么类型,对象什么时候失效,任务运行在哪个线程,消息发出以后怎样得到结果,本地记录是否同步,微信退出再登录以后能不能恢复,以及客户端升级后怎样重新适配。
如果这些问题没有处理,最多只能做一个演示程序。
真正能接入业务系统的方案,最好把底层适配和上层功能分开。Hook部分只负责处理必要的客户端事件,耗时操作交给外部程序完成。
例如,收到消息以后,底层模块只整理出发送者、会话、消息类型和内容,再交给外部服务。至于关键词判断、工单创建、数据库存储或者AI回复,都不应该塞进微信进程里执行。
这样即使微信版本变化,也主要调整底层适配部分,不至于把整套业务程序推倒重来。
微信Hook适合做什么?
我研究这个方向,并不是为了做无限群发或者自动加好友。
从项目角度看,我认为它更适合解决一些具体的业务问题,例如:
客户发来设备故障后,自动生成售后记录;
工作群里出现重要关键词时,提醒相关负责人;
将经过授权的消息和文件按照项目归档;
把微信中的客户咨询接入现有客服系统;
结合企业知识库生成回复建议;
将ERP、CRM或者设备平台的信息推送给指定人员。
这类需求的共同点是:微信只是消息入口,真正的处理仍然在企业自己的业务系统中完成。
如果只是定时点击几个按钮,使用RPA可能更简单;如果企业微信官方接口可以满足需求,也没有必要为了Hook而Hook。
只有在官方接口和UI自动化确实无法满足要求时,底层适配才值得投入时间。
最后说一下
目前Mac微信4.1.6.12已经完成了基础发送链路验证,对方能够正常收到测试消息,但发送方本地聊天记录还没有形成完整闭环。
Windows端主要针对微信4.1.12.26进行适配。整体分析思路可以参考Mac端,但具体实现仍需根据Windows客户端重新处理。
Android端目前属于可行性研究阶段,还没有完成实机验证。
这篇文章只记录整体思路和实际遇到的问题,不公开具体偏移地址、关键函数、消息体数据以及可以直接运行的注入脚本。因为这些内容和客户端版本绑定得很紧,单独复制某个地址没有多少长期价值。
后面如果继续推进,我会重点验证Windows端不同消息类型、本地状态同步、异常恢复,以及外部业务接口的稳定性。
有类似项目需要评估的,可以带上操作系统、微信完整版本号、想实现的功能和实际使用场景交流。先把需求和版本确认清楚,再判断适合使用官方接口、RPA还是微信Hook。
相关研究仅限自有账号、授权测试及正常业务场景,不涉及数据窃取、绕过平台限制和未经允许的批量营销。
## 其他未开源接口一览,有需要的联系TG
| 方法 | 路径 | 摘要 |
|------|------|------|
| `POST` | `/api/send/text` | 文本发送 |
| `POST` | `/api/send/chatroom` | 群内发送 |
| `POST` | `/api/send_at_text` | 群内艾特人 |
| `GET` | `/api/msg/pop` | 获取实时消息,轮询 |
| `POST` | `/api/send/image` | 个人发送图片 |
| `POST` | `/api/send/chatroom/image` | 群内发送图片 |
| `POST` | `/api/send/video` | 个人发送视频 |
| `POST` | `/api/send/chatroom/video` | 群内发送视频 |
| `GET` | `/api/get_db_handles` | 获取数据库句柄,需要登陆前注入有效 |
| `POST` | `/api/exec_sql` | 数据库方式获取联系人 |
| `POST` | `/api/get_room_members` | 数据库方式获取群成员 |
| `POST` | `/api/get_room_members_hook` | 获取群成员列表 |
| `GET` | `/api/get_contacts` | 内存方式获取联系人列表 |
| `POST` | `/api/download_image` | cdn下载图片 |
| `POST` | `/api/get_room_info` | 群详情( 群主/群名/头像/公告/成员数) |
| `GET` | `/api/get_self` | 从 DB 路径解析本机 wxid |
| `POST` | `/api/send_pat` | 拍一拍,走的网络层,本地UI不显示 |
| `POST` | `/api/send_card_msg` | 发送名片信息,走的网络层,本地UI不显示 |
| `POST` | `/api/send_xml` | 发送链接信息,走的网络层,本地UI不显示 |
| `POST` | `/api/send_emotion_msg` | 发送本地GIF信息,走的网络层,本地UI不显示 |
| `POST` | `/api/send_app_msg` | 发送卡片信息都可以发 包括但不限于 小程序 位置 音乐卡片等等,走的网络层,本地UI不显示 |
| `POST` | `/api/send_fav_emotion` | 发送收藏表情,走的网络层,本地UI不显示 |
| `POST` | `/api/cdn_video_forward` | cdn转发视频,走的网络层,本地UI不显示 |
| `POST` | `/api/send_cdn_img_msg` | cdn发送图片(无源可用做转发消息) |
| `POST` | `/api/send_mp3_voice` | 发送mp3语音,走的网络层,本地UI不显示 |
| `POST` | `/api/send_applet_msg` | 发送小程序,走的网络层,本地UI不显示 |
| `GET` | `/api/get_favs` | 获取收藏列表 |
| `POST` | `/api/set_room_announcement_pb` | 设置群公告 |
| `POST` | `/api/send_location_msg` | 发送位置消息,走的网络层,本地UI不显示 |
| `POST` | `/api/sns_post` | 发送朋友圈 |
| `POST` | `/api/get_profile_new` | 语音转文本 |
| `GET` | `/api/get_profile_cache` | 获取自身信息 |
| `POST` | `/api/net_scene_search_contact` | 搜索微信号/手机号 |
| `POST` | `/api/add_friend` | 添加好友 |
| `POST` | `/api/js_login` | 获取小程序code |
| `POST` | `/api/verify_friend` | 同意好友申请(有变动) |
| `POST` | `/api/sync_msg/clear` | 清掉旧乱码,同意加好友申请,用的测试接口 |
| `GET` | `/api/sync_msg/pop` | 专门接收同意好友申请的消息接口 |
| `POST` | `/api/get_a8key` | 群聊获取A8key |
| `POST` | `/api/creat_chat_room` | 创建群聊 |
| `POST` | `/api/invite_member_to_chat_room` | 邀请进入群聊 |
| `POST` | `/api/del_member_from_chat_room` | 踢出群成员 |