微信协议简单调研笔记 -凯发k8网页登录

记录工作/学习的点点滴滴。

微信协议简单调研笔记

前言

微信可调研点很多,这里仅仅从协议角度进行调研,会涉及到微信协议交换、消息收发等。所谓“弱水三千,只取一瓢”吧。

杂七杂八的,有些长,可直接拉到最后看结论好了。

一。微信协议概览

微信传输协议,官方公布甚少,在微信技术总监所透漏ppt《微信之道—至简》文档中,有所体现。

纯个人理解:

因张小龙做邮箱foxmail起家,继而又做了qq mail等,qq mail是国内第一个支持exchange activesync协议的免费邮箱,基于其从业背景,微信从一开始就采取基于activesync的修改版状态同步协议sync,也就再自然不过了。

一句话:增量式、按序、可靠的状态同步传输的微信协议。

大致交换简图如下:

如何获取新数据呢:

  1. 服务器端通知,客户端获取
  2. 客户端携带最新的synckey,发起数据请求
  3. 服务器端生成最新的synckey连同最新数据发送给客户端
  4. 基于版本号机制同步协议,可确保数据增量、有序传输
  5. synckey,由服务器端序列号生成器生成,一旦有新消息产生,将会产生最新的synckey。类似于版本号

服务器端通知有状态更新,客户端主动获取自从上次更新之后有变动的状态数据,增量式,顺序式。

二。微信web端简单调试

在线版本微信:

通过firefox firebug组合调试,也能证实了微信大致通过交换synckey方式获取新数据的论述。

1. 发起get长连接检测是否存在新的需要同步的数据

会携带上最新synckey

https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/synccheck?callback=jquery18306073923335455973_1393208247730&r=1393209241862&sid=s7c/sxpgrsihgzaa&uin=937355&deviceid=e542565508353877&synckey=1_620943725|2_620943769|3_620943770|11_620942796|201_1393208420|202_1393209127|1000_1393203219&_=1393209241865

返回内容:

 window.synccheck={retcode:"0",selector:"2"}

selector值大于0,表示有新的消息需要同步。

据目测,心跳周期为27秒左右。

2. 一旦有新数据,客户端post请求主动获取同步的数据

https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=s7c/sxpgrsihgzaa&r=1393208447375

携带消息体:

{"baserequest":{"uin":937355,"sid":"s7c/sxpgrsihgzaa"},"synckey":{"count":6,"list":[{"key":1,"val":620943725},{"key":2,"val":620943767},{"key":3,"val":620943760},{"key":11,"val":620942796},{"key":201,"val":1393208365},{"key":1000,"val":1393203219}]},"rr":1393208447374}

会携带上最新的synckey,会返回复杂结构体json内容。

但浏览端收取到消息之后,如何通知服务器端已确认收到了?web版本微信,没有去做。

在以往使用过程中,曾发现web端有丢失消息的现象,但属于偶尔现象。但android微信客户端(只要登陆连接上来之后)貌似就没有丢失过。

3. 发送消息流程

  1. 发起一个post提交,用于提交用户需要发送的消息

    https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?sid=lq95vhr52dialvqo&r=1393988414386

发送内容:

{"baserequest":{"uin":937355,"sid":"lq95vhr52dialvqo","skey":"a6a1ecc6a7de59deff6a05f226aa334decba457887b25bc6","deviceid":"e937227863752975"},"msg":{"fromusername":"yongboy","tousername":"hehe057854","type":1,"content":"hello","clientmsgid":1393988414380,"localid":1393988414380}}

相应内容:

{
"baseresponse": {
"ret": 0,
"errmsg": ""
}
,
"msgid": 1020944348,
"localid": "1393988414380"
}
  1. 再次发起一个post请求,用于申请最新synckey

    https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=lq95vhr52dialvqo&r=1393988414756

发送内容:

{"baserequest":{"uin":937355,"sid":"lq95vhr52dialvqo"},"synckey":{"count":6,"list":[{"key":1,"val":620944310},{"key":2,"val":620944346},{"key":3,"val":620944344},{"key":11,"val":620942796},{"key":201,"val":1393988357},{"key":1000,"val":1393930108}]},"rr":1393988414756}

响应的(部分)内容:

"skey": "8f8c6a03489e85e9fdf727acb95c93c2cdce9fb9532fc15b"  
  1. 终止get长连接,使用最新synckey再次发起一个新的get长连接

    https://webpush.weixin.qq.com/cgi-bin/mmwebwx-bin/synccheck?callback=jquery1830245810089652082181393988305564&r=1393988415015&sid=lq95vhr52dialvqo&uin=937355&deviceid=e937227863752975&synckey=1620944310|2620944348|3620944344|11620942796|2011393988357|10001393930108&=1393988415016

三。微信android简单分析

windows桌面端android虚拟机中运行最新版微信(5.2),通过tcpdump/wireshark组合封包分析,以下为分析结果。

0. 初始连接记录

简单记录微信启动之后请求:

11:20:35 dns查询 
dns.weixin.qq.com
返回一组ip地址
11:20:35 dns查询
long.weixin.qq.com
返回一组ip地址,本次通信中,微信使用了最后一个ip作为tcp长连接的连接地址。
11:20:35
http://dns.weixin.qq.com/cgi-bin/micromsg-bin/newgetdns?uin=0&clientversion=620888113&scene=0&net=1
用于请求服务器获得最优ip路径。服务器通过结算返回一个xml定义了域名:ip对应列表。仔细阅读,可看到微信已经开始了国际化的步伐:香港、加拿大、韩国等。
具体文本,请参考:https://gist.github.com/yongboy/9341884
11:20:35
获取到long.weixin.qq.com最优ip,然后建立到101.227.131.105的tcp长连接
11:21:25
post http://short.weixin.qq.com/cgi-bin/micromsg-bin/getprofile http/1.1  (application/octet-stream)
返回一个名为“micromsgresp.dat”的附件,估计是未阅读的离线消息
11:21:31
post http://short.weixin.qq.com/cgi-bin/micromsg-bin/whatsnews http/1.1  (application/octet-stream)
大概是资讯、订阅更新等
中间进行一些资源请求等,类似于
get http://wx.qlogo.cn/mmhead/q3auhgzwzm7nr4tyfconjbxzpfo9aiae7ru5lxguw13smicl6iacwif2a/96
图片等一些静态资源都会被分配到wx.qlogo.cn域名下面
不明白做什么用途
post http://short.weixin.qq.com/cgi-bin/micromsg-bin/downloadpackage http/1.1  (application/octet-stream)
输出为micromsgresp.dat文件
11:21:47
get http://support.weixin.qq.com/cgi-bin/mmsupport-bin/reportdevice?channel=34&deviceid=a952001f7a840c2a&clientversion=620888113&platform=0&lang=zh_cn&installtype=0 http/1.1 
返回chunked分块数据
11:21:49
post http://short.weixin.qq.com/cgi-bin/micromsg-bin/reportstrategy http/1.1  (application/octet-stream)

1. 心跳频率约为5分钟

上次使用wireshark分析有误(得出18分钟结论),再次重新分析,心跳频率在5分钟左右。

2. 登陆之后,会建立一个长连接,端口号为8080

简单目测为http,初始以为是双通道http,难道是自定义的用于双通道通信的http协议吗,网络上可见资料都是模棱两可、语焉不详。

具体查看长连接初始数据通信,没有发现任何包含"http"字样的数据,以为是微信自定义的tcp/http通信格式。据分析,用于可能用于获取数据、心跳交换消息等用途吧。这个后面会详谈微信是如何做到的。

2.0 初始消息传输

个人资料、离线未阅读消息部分等通过 post http短连接单独获取。

2.1 二进制简单分析

抽取微信某次http协议方式通信数据,16进制表示,每两个靠近的数字为一个byte字节:

微信协议可能如下:

一个消息包 = 消息头   消息体

消息头固定16字节长度,消息包长度定义在消息头前4个字节中。

单纯摘取第0000行为例,共16个字节的头部:

00 00 00 10 00 10 00 01 00 00 00 06 00 00 00 0f

16进制表示,每两个紧挨着数字代表一个byte字节。

微信消息包格式: 1. 前4字节表示数据包长度,可变 值为16时,意味着一个仅仅包含头部的完整的数据包(可能表示着预先定义好的业务意义),后面可能还有会别的消息包 2. 2个字节表示头部长度,固定值,0x10 = 16 3. 2个字节表示谢意版本,固定值,0x01 = 1 4. 4个字节操作说明数字,可变 5. 序列号,可变 6. 头部后面紧跟着消息体,非明文,加密形式 7. 一个消息包,最小16 byte字节

通过上图(以及其它数据多次采样)分析:

  1. 0000 - 0040为单独的数据包
  2. 0050行为下一个数据包的头部,前四个字节值为0xca = 202,表示包含了从0050-0110共202个字节数据
  3. 一次数据发送,可能包含若干子数据包
  4. 换行符\n,16进制表示为0x0a,在00f0行,包含了两个换行符号
  5. 一个数据体换行符号用于更细粒度的业务数据分割 是否蒙对,需要问问做微信协议的同学
  6. 所有被标记为http协议通信所发送数据都包含换行符号
2.2 动手试试猜想,模拟微信tcp长连接

开始很不解为什么会出现如此怪异的http双通道长连接请求,难道基于tcp通信,然后做了一些手脚?很常规的tcp长连接,传输数据时(不是所有数据传输),被wireshark误认为http长连接。这个需要做一个实验证实一下自己想法,设想如下:

写一个ping-pong客户端、服务器端程序,然后使用wireshark看一下结果,是否符合判断。

java版本的请求端,默认请求8080端口:

c语言版本的服务器程序,收到什么发送什么,没有任何逻辑,默认绑定8080端口:

这里有一个现场图:

可以尝试稍微改变输出内容,去除换行符“\n”,把端口换成9000,试试看,就会发现wireshark输出不同的结果来。

2.3 结论是什么呢?

若使用原始tcp进行双向通信,则需要满足以下条件,可以被类似于wireshark协议拦截器误认为是http长连接:

  1. 使用80/8080端口(81/3128/8000经测试无效) 也许8080一般被作为web代理服务端口,微信才会享用这个红利吧。
  2. 输出的内容中,一定要包含换行字符"\n"

因此,可以定性为微信使用了基于8080端口tcp长连接,一旦数据包中含有换行"\n"符号,就会被wireshark误认为http协议。可能微信是无心为之吧。

3. 新消息获取方式

  1. tcp长连接接收到服务器通知有新消息需要获取
  2. app发起一个http post请求获取新状态消息,会带上当前synckey 地址为:http://short.weixin.qq.com/cgi-bin/micromsg-bin/reportstrategy http/1.1,看不到明文
  3. app获取到新的消息,会再次发起一次http post请求,告诉服务器已确认收到,同时获取最新synckey 地址为:http://short.weixin.qq.com/cgi-bin/micromsg-bin/kvreport,看不到明文
  4. 接受一个消息,tcp长连接至少交互两次,客户端发起两次http post请求
    具体每次交互内容是什么,有些模糊
  5. 服务器需要支持:状态消息获取标记,状态消息确认收取标记。只有被确认收到,此状态消息才算是被正确消费掉
  6. 多个不同设备同一账号同时使用微信,同一个状态消息会会被同时分发到多个设备上

此时消息请求截图如下:

4. 发送消息方式

发送消息走已经建立的tcp长连接通道,发送消息到服务器,然后接受确认信息等,产生一次交互。

小伙伴接收到信息阅读也都会收到服务器端通知,产生一次交互等。

可以确定,微信发送消息走tcp长连接方式,因为不对自身状态数据产生影响,应该不交换synckey。

  • 在低速网络下,大概会看到消息发送中的提示,属于消息重发机制
  • 网络不好有时客户端会出现发送失败的红色感叹号
  • 已发送到服务器但未收到确认的消息,客户端显示红色感叹号,再次重发,服务器作为重复消息处理,反馈确认
  • 上传图片,会根据图片大小,分割成若干部分(大概1.5k被划分为一部分),同一时间点,客户端会发起若干次post请求,各自上传成功之后,服务器大概会合并成一个完整图片,返回一个缩略图,显示在app聊天窗口内。app作为常规的文字消息发送到服务器端
  • 上传音频,则单独走tcp通道,一个两秒的录制音频,客户端录制完毕,分为两块传输,一块最大1.5k左右,服务端响应一条数据通知确认收到。共三次数据传输。
    音频和纯文字信息一致,都是走tcp长连接,客户端发送,服务器端确认。

四。微信协议小结

  1. 发布的消息对应一个id(只要单个方向唯一即可,服务器端可能会根id判断重复接收),消息重传机制确保有限次的重试,重试失败给予用户提示,发送成功会反馈确认,客户端只有收到确认信息才知道发送成功。发送消息可能不会产生新synckey。
  2. 基于版本号(synkey)的状态消息同步机制,增量、有序传输需求水到渠成。长连接通知/短连接获取、确认等,交互方式简单,确保了消息可靠谱、准确无误到达。
  3. 客户端/服务器端都会存储消息id处理记录,避免被重复消费客户端获取最新消息,但未确认,服务器端不会认为该消息被消费掉。下次客户端会重新获取,会查询当前消息是否被处理过。根据一些现象猜测。
  4. 总体上看,微信协议跨平台(tcp或htpp都可呈现,处理方式可统一),通过“握手”同步,很可靠,无论哪一个平台都可以支持的很好
  5. 微信协议最小成本为16字节,大部分时间若干个消息包和在一起,批量传输。微信协议说不上最简洁,也不是最节省流量,但是非常成功的。
  6. 若服务器检测到一些不确定因素,可能会导致微启用安全套接层ssl协议进行常规的tcp长连接传输。短连接都没有发生变化

以上,根据有限资料和数据拦截观察总结得出,啰啰嗦嗦,勉强凑成一篇,会存在一些不正确之处,欢迎给予纠正。在多次

五。附录

microsoft exchange active sync协议,简称eas,分为folderrsync(同步文件夹目录,即邮箱内有哪几个文件夹)和sync(每个文件夹内有哪些文档)两部分。

某网友总结的协议一次回话大致示范:

client:   synckey=0 //第一次key为0
server:  newsynckey=1235434    //第一次返回新key
client:   synckey=1235434   //使用新key查询
server:  newsynckey=1647645,data=*****//第一次查询,得到新key和数据
client:   synckey=1647645
server:  newsynckey=5637535,data=null //第二次查询,无新消息
client:   synckey=5637535
server: newsynckey=8654542, data=****//第三次查询,增量同步
  • 上页中的相邻请求都是隔固定时间的,如两分钟
  • 客户端每次使用旧key标记自己的状态,服务端每次将新key和增量数据一起返回。
  • key是递增的,但不要求连续
  • 请求的某个参数决定服务器是否立即返回

posted on 2014-03-05 14:15 nieyong 阅读(96111) 评论(22)     所属分类: 移动后端

# re: 微信协议简单调研笔记 2014-03-06 11:55

好长的代码啊!  回复     

# re: 微信协议简单调研笔记 2014-03-07 07:08 海边沫沫

学习了  回复     

# re: 微信协议简单调研笔记 2014-07-16 09:21

谢谢博主!  回复     

# re: 微信协议简单调研笔记[未登录] 2014-07-23 17:40

wireshark 是通过端口号来辨识协议类型,8080是http的常用端口,wireshark就把消息标识为http,这个功能可以禁止掉。
另外,微信使用8080端口,跟http没有关系,也不是冒充http,主要在于有些公司会封掉端口,但是8080 80 这些常用端口是打开的。  回复     

# re: 微信协议简单调研笔记 2014-08-28 13:27

好长的代码啊。不过还是很受用。谢谢啦  回复     

# re: 微信协议简单调研笔记 2014-08-28 13:29

不错不错  回复     

# re: 微信协议简单调研笔记 2014-09-26 01:26

博主。。有个软件请你开发可以吗啊,关于微信的。。重金酬谢!请联系我qq:412609534  回复     

# re: 微信协议简单调研笔记 2014-10-10 10:52

写的真不错,总结起来,web版本就是采用的长轮询方案,轮询timeout时间大概是27s。
客户端版,使用8080端口做长连接,主要是用于是否有新消息的检测,以及消息发送。新消息的获取和收到确认过程依旧是采用http的方式。有一个问题是,8080端口被公司封掉的话,是否就会有问题了?  回复     

# re: 微信协议简单调研笔记 2014-11-17 13:49

博主,tcpdump的命令是什么样的?  回复     

# re: 微信协议简单调研笔记 2015-01-09 10:32

hi 某个人的碎碎念,

*微信web协议synckey遭遇1100的bug*

我把详细讨论放在

以下是bug概述:

用“微信同步心跳”做为关键词google,可以发现

当其返回不是window.synccheck={retcode:"0",selector:"0"}就需要再次回到第二步, 重新获得synckey! 但是post的json内容中用到的synckey只有4个元素,即第一步的initsynckey, 我现在用的是5个synckey,弃掉key值为11的元素。

不幸运的是我会得到window.synccheck={retcode:"1100",selector:"0"}一旦出现1100 心跳同步就失败了!无法接收、发送微信!bug提交在

敬礼

涩兔子leslie  回复     

# re: 微信协议简单调研笔记 2015-01-09 16:08

@涩兔子leslie
fix咯   回复     

# re: 微信协议简单调研笔记 2015-03-10 17:26

害人不浅啊。。。。
1.tcp长连接接收到服务器通知有新消息需要获取
2.app发起一个http post请求获取新状态消息,会带上当前synckey 地址为: http/1.1,看不到明文

你确定微信发http请求了????你用charles只抓http。
别人给你发消息。。你看是否有http

这样的文章,最好还事调研清楚,,害人不浅  回复     

# re: 微信协议简单调研笔记[未登录] 2015-03-11 08:41

弄清楚什么是http协议和长连接再说吧。  回复     

# re: 微信协议简单调研笔记[未登录] 2015-03-11 08:43

>> 2.3 结论是什么呢?
>> 若使用原始tcp进行双向通信,则需要满足以下条件,可以被类似于wireshark协议拦截器误认为是http长连接:

>>使用80/8080端口(81/3128/8000经测试无效) 也许8080一般被作为web代理服务端口,微信才会享用这个红利吧。
>> 输出的内容中,一定要包含换行字符"\n"
>> 因此,可以定性为微信使用了基于8080端口tcp长连接,一旦数据包中含有换行"\n"符号,就会被wireshark误认为http协议。可能微信是无心为之吧。

你这误人子弟了吧。  回复     

# re: 微信协议简单调研笔记[未登录] 2015-04-16 22:47

谢谢博主的分享。
请教一个问题关于微信开发的,是否可以把mqtt协议的客户端程序加入微信中,使之能够接收mqtt的订阅信息?谢谢  回复     

# re: 微信协议简单调研笔记 2015-04-17 10:05 nieyong

@leo 理论上是可以的,不同线程/不同组件处理不同事宜,只要不混杂在一起就行。  回复     

# re: 微信协议简单调研笔记[未登录] 2015-04-17 18:03

@nieyong
谢谢,有机会再请教  回复     

# re: 微信协议简单调研笔记[未登录] 2015-04-20 23:00

可以联系我下嘛 qq758660  回复     

# re: 微信协议简单调研笔记 2015-04-29 17:53

楼主,很高兴你能分享自己所得,但是有些地方我不认同,就是收取新的消息,根据wireshark抓包分析出来的结果,服务器 通过tcp长连接 发送app 一个数据包,app是通过 tcp 长连接 请求服务器,然后服务器 还是通过tcp的长连接 返回消息数据吧。。。。。 还有那个语音消息,依然是这条tcp连接,没有新建连接吧  回复     

# re: 微信协议简单调研笔记 2015-05-04 10:22

weixin://协议  回复     

# re: 微信协议简单调研笔记 2015-11-05 11:56

很感谢腾迅帮助我走困惑、多年、多少网友没能找到终结、我从内心配服、你们的为客服解难之心、天天关注你们徵信、新闻没错、希望傻乌能飞出井底、谢谢大家  回复     

# re: 微信协议简单调研笔记[未登录] 2016-06-13 16:03

楼主
你知道群红包详情的接口是哪个吗。。如有。请告知。

我qq:147171718 qq邮箱也行。。
如成功了。红包答谢。  回复     


只有注册用户后才能发表评论。


网站导航:
              
 

公告

所有文章皆为原创,若转载请标明出处,谢谢~

新浪微博,欢迎关注:

导航

2014年3月
2324252627281
234678
9101112131415
16171819202122
23242526272829
303112345

统计

常用链接

留言簿(58)

随笔分类(129)

随笔档案(149)

个人收藏

最新随笔

搜索

最新评论

阅读排行榜

评论排行榜

网站地图