[微信协议分析] 文本消息

参考:

微信协议简单调研笔记

微信破解研究总结

Sync协议

  道听途说,加上上面参考中都是提到微信使用Sync协议。去年项目中做过参考Microsoft Exchange ActiveSync 协议来优化消息协议的方案,虽经过长时间讨论定稿,但由于一些原因最终没有实现;也从中深知Sync并不是表面上那么简单、那么好用。

  Sync 有啥问题呢?

  1. SyncKey 生成维护成本

    SyncKey 在ActiveSync中为字符串,客户端不需要解析,但服务端实现要用数字自增,需要强一致性,且不能回退。

  2. 消息的订阅模式 采用类似Zookeeper的One time triggler 还是每条消息都推送一条通知能

    One time trigger能够避免并发通知时,获取消息时重复问题,但增加了交互成本,和客户端实现复杂性。

  3. 自己发的消息,SyncKey怎么获取

    尤其要支持多端同步发消息,保证消息同步;也只好消息发完在给自己同步一遍(自己设备发的可以不带消息体)

  4. 消息推送延时加重

    Sync 消息体获取方式:Notify - Ack - get - Mssage, 也就是至少第四个应用包才能返回消息,在移动网络下成本很高。文中提到消息通过单独https请求,那么延时更为严重了(嗯,实测新版本并非如此)。

手机客户端不再Sync协议

抓包分析版本:Android 微信6.0, 抓包分析可参考:android 移动网络实时抓包

在wifi、gprs网络状况下都相同,客户端会依次尝试使用80、8080、443 端口连接服务器;消息发送、接收都使用长连接进行.

协议格式:

4byte Packet Len(包含4字节本身)

2byte Head Len(包含2字节本身) + 2byte Version(1) + 4byte Operation + 4byte SeqId + ….

(Packet Len - Head Len)  Body

协议交互方式:

- 客户端请求(一应一答,通过seqid匹配):

seqid = 1 开始,依次递增,服务器回复相同的seqid 作为应答

- 服务器推送通知(单向):

seqid = 0,Operation = 7a,  客户端不需要应答

主要业务:

-心跳包:

发起客户端请求,Operation = 0c,长度为16字节,算是最小的包

-发消息:

发起客户端请求,Operation = ed

  单点在线时发完消息后,应答携带SyncKey,不再同步,多点在线时,通过通知同步SyncKey,将随后文章分析。

-收消息:

1. 服务器推送消息, Operation = 7a,  Body 中携带消息内容

    抓包分析时,通过改变消息体大小,可能到接收方第一个包length 也会随之变化,可确认消息是push的。

2. 发起客户端单向请求,即消息的应答Ack

-加密:

未分析,一般来说像whatsapp那样,使用 hash(密码/OTP + 长连接第一个请求获取RandomCode) 做RC4 的密钥

总结:

现在版本的微信消息推送,并非Sync方式,而是推送+ack方式;

从他们协议设计来看,应该最开始用的是Notify + Sync Req + Sync Rsp 方式,因为协议上是不支持服务器发起请求的;

现在改成 Sync 消息+ 单向 Ack Req 的push方式,虽然协议上怪异, 相比Sync 消息接收会更加及时。从以前看到的文章都是说用的Sync协议,应该是是后期版本做了修改,push方式更为高效、而且通过顺序的SyncKey也能够修复丢失的消息。

下面一个通知包示例:

4 byte: 265 PacketLen

2 byte: 16   Head Length

2 byte: 1     Protocol Version

4 byte: 7a   Operation

4 byte: 0   SeqId 这是一个通知性消息

4 byte: unknow header

……. Body

Web客户端

  web微信客户端使用比较标准的Sync协议,Sync协议也比较适合web长轮询模型。

  移动客户端模式下,协议是二进制的而且有加密,很难分析;微信侧重手机端,web端主体协议应该保持与移动端一致,可通过web端推测整体协议实现,json也比较好分析。

  接收一条消息后SyncKey变化: 

  synckey:1_624161340|2_624162225|3_624162051|11_624161867|201_1420112604|1000_1420104656
  synckey:1_624161340|2_624162226|3_624162051|11_624161867|201_1420112631|1000_1420104656

  可以看出:

  - Synckey 有多个,应该是应对不同业务,其中2为为所有个人消息、讨论组消息,其他可能是联系人、朋友圈、订阅号等,201 为当前时间戳。

  - SyncKey 的值为数字自增,不是从0开始,应该有个固定的初始值。  

  - 发消息时,发完需要自己给再自己同步回一下SyncKey。

- 下面是一条消息增量同步结构,一堆要同步字段+是否修改FlagMask,同步协议变得很简洁。

{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
}
,
"AddMsgCount": 1,
"AddMsgList": [{
"MsgId": 1625734358,
"FromUserName": "@sssss",
"ToUserName": "@ssssssss2",
"MsgType": 1,
"Content": "捶地笑……",
"Status": 3,
"ImgStatus": 1,
"CreateTime": 1420109883,
"VoiceLength": 0,
"PlayLength": 0,
"FileName": "",
"FileSize": "",
"MediaId": "",
"Url": "",
"AppMsgType": 0,
"StatusNotifyCode": 0,
"StatusNotifyUserName": "",
"RecommendInfo": {
"UserName": "",
"NickName": "",
"QQNum": 0,
"Province": "",
"City": "",
"Content": "",
"Signature": "",
"Alias": "",
"Scene": 0,
"VerifyFlag": 0,
"AttrStatus": 0,
"Sex": 0,
"Ticket": "",
"OpCode": 0
}
,
"ForwardFlag": 0,
"AppInfo": {
"AppID": "",
"Type": 0
}
,
"HasProductId": 0,
"Ticket": ""
}
],
"ModContactCount": 0,
"ModContactList": [],
"DelContactCount": 0,
"DelContactList": [],
"ModChatRoomMemberCount": 0,
"ModChatRoomMemberList": [],
"Profile": {
"BitFlag": 0,
"UserName": {
"Buff": ""
}
,
"NickName": {
"Buff": ""
}
,
"BindUin": 0,
"BindEmail": {
"Buff": ""
}
,
"BindMobile": {
"Buff": ""
}
,
"Status": 0,
"Sex": 0,
"PersonalCard": 0,
"Alias": "",
"HeadImgUpdateFlag": 0,
"HeadImgUrl": "",
"Signature": ""
}
,
"ContinueFlag": 0,
"SyncKey": {
"Count": 6,
"List": [{
"Key": 1,
"Val": 624161340
}
,{
"Key": 2,
"Val": 624162166
}
,{
"Key": 3,
"Val": 624162051
}
,{
"Key": 11,
"Val": 624161867
}
,{
"Key": 201,
"Val": 1420109883
}
,{
"Key": 1000,
"Val": 1420104656
}
]
}
,
"SKey": ""
}

  

时间: 2024-11-06 19:32:03

[微信协议分析] 文本消息的相关文章

Python实现通过微信企业号发送文本消息的Class

前文<Python实现获取微信企业号access_token的Class>提供了获取微信企业号的access_token,本文中的代码做实际发送文本消息. 编程要点和调用方法: 支持发送中文,核心语句"payload = json.dumps(self.data, encoding='utf-8', ensure_ascii=False)",关键字"python json 中文" 这个Class只有一个公共方法send(). 使用方法:import这个c

微信程序开发系列教程(三)使用微信API给微信用户发文本消息

这个系列的第二篇教程,介绍的实际是被动方式给微信用户发文本消息,即微信用户关注您的公众号时,微信平台将这个关注事件通过一个HTTP post发送到您的微信消息服务器上.您对这个post请求做了应答(格式为文本),则该应答会通过微信平台投递到您粉丝的微信应用上. 微信开发者中心的文档将这种行为称为"被动回复用户消息": 回复消息报文的格式在开发者文档里也有清晰的定义,是一个xml格式的字符串.我的第二篇教程里也有具体的发送该报文的代码示例. 本文作为这个开发系列的第三篇教程,介绍的是如何

C#-MVC开发微信应用(3)--文本消息和图文消息的应答

最近咨询微信的人很多,感觉这块也是一块商机,也为了演示SNF快速开发平台的优势,就用SNF快速开发平台开发出一套微信应用程序.使用<SNF.CodeGenerator>代码生成工具可以节省大量时间. 在前面两篇两篇随笔<C#-MVC开发微信应用(1)--开始使用微信接口>和<C#-MVC开发微信应用(2)--开始使用微信接口>里面,大致介绍了我微信应用的框架构建,本随笔继续介绍这一主题,介绍消息应答里面的文本应答和图文应答的过程. 我们知道,给手机用户发送响应消息,它可

[微信协议分析] 多媒体

语音片断 语音片断的发送.接收都是通过长连接分包进行. 发送:语音录制过程中,客户端每2秒发一次,每次2.5K左右 接收:服务器将语音分片文件整体当成一条消息,和文本消息一样的方式推送 总结,语音分片发送和文本相差不大,只是语音因为体积较大,录制过程中会同时上传操作,加快发送速度,取消时,删除已上传部分即可. 图片.视频片断.小视频 都类似,只是文件类型,大小不一样,客户端处理方式不同,对于服务器差别不大. 发送:https短连接,不走长连接,所有发送完后SyncKey 会通过长连接回推 接收:

[微信协议分析] 多点登陆

IM产品的多点登陆逻辑特别复杂,很难做到很好的用户体验,就像新版mac handoff 功能也不少人在喷. 微信最开始并不支持多点登陆,后来陆续增加的Web版.Mac版,但并不是完整意义的客户端,要说只是辅助工具. 微信允许: 一个移动端(下面称之为主客户端) + 一个web/mac 同时在线(下面称之为从客户端),web/mac 只能接收在线消息.发消息,不记录消息历史.这样多点逻辑就变得相对简单很多了. 存储 服务器不用保存完整消息历史,通过客户端对push消息的ack保证消息送达,协议保证

python实现微信企业号的文本消息推送

[企业号的创建.企业号应用的创建.组.tag.part就不赘述了,一搜一大堆,但是网上拿的那些个脚本好多都不好使,所以自己修了一个] 坦率的讲,这个脚本是用来作为zabbix的通知媒介脚本的,本人是个菜鸟,如果哪里不对,大神们不要笑话,python也处于学习阶段,如果有哪些地方不合理,很希望可以不吝赐教,废话不多说,脚本奉上: #!/usr/bin/python # _*_coding:utf-8 _*_ import urllib2 import json import sys reload(

(6)微信二次开发 之 微信文本消息接口实现

p.p1 { margin: 13.0px 0.0px 13.0px 0.0px; text-align: justify; font: 16.0px SimSun } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; text-align: justify; font: 10.5px SimSun } span.s1 { font: 16.0px Cambria } span.s2 { font: 16.0px "Times New Roman" } s

微信公号开发之文本消息技巧:长度限制、换行和表情

微信公众账号文本消息的内容长度限制揭秘 相信不少朋友都遇到过这样的问题:当发送的文本消息内容过长时,微信将不做任何响应.那么到底微信允许的文本消息的最大长度是多少呢?我们又该如何计算文本的长度呢?为什么还有些人反应微信好像支持的文本消息最大长度在1300多呢?这篇文章会彻底解除大家的疑问. 接口文档中对消息长度限制为2048: 可以看到,接口文档中写的很明确:回复的消息内容长度不超过2048字节.那为什么很多人测试反应消息内容长度在1300多字节时,微信就不响应了呢?我想这问题应该在这部分人没有

夺命雷公狗---微信开发23----客服消息接口基础和推送文本

我们这边课程里面一共用到了三个文件,分别是WeChat.class.php和common.php以及index.php 我们在写这个功能之前也要学会查手册,手册我们可以在微信开发这里找到,如下所示: 点击进去后我们将会看到客服接口,我们可以点击下进去看看里面有什么动动 这里有一个发送文本消息的,我们点击进去看下 这里很明显就看到文本消息是通过一个json数据来进行实现的,废话不多说,开工 这里我们先来写一个WeChat.php的文件,这里作用主要适用于封装一个CURL上传类的,代码如下所示: <