这几天运动会,抽空仔细看了下闪通用户登录后的心跳包结构。闪通的心跳包是分为两种的,一个是用户登录后就有的心跳,用于保持用户登录的状态,另一个就是高速通道的心跳,高速通道的心跳留给下次长假再研究~

闪通登录的包是http,但是明显是经过base64二次编码的,算法不是很困难,但是都快毕业的人了,留一些谜团给学弟学妹们去解吧~

闪通用户的心跳包是发往('mail.189joy.com', 8987)的UDP包,每个包的长度固定为80字节,拿一个包来做下例子(帐号信息略去):

0000  c8 e7 d8 53 7d de 00 0c  29 f1 51 37 08 00 45 00   ...S}... ).Q7..E.
0010  00 6c 8d b4 00 00 80 11  71 0d c0 a8 01 65 7a e3   .l...... q....ez.
0020  fe ce 07 55 23 1b 00 58  f0 5a 7a 8c 0c 00 00 00   ...U#..X .Zz.....
0030  00 00 7f e8 fc 5e 49 01  00 00 0* ** *7 00 00 00   .....^I. ........
0040  00 00 00 00 00 00 00 00  00 00 43 38 37 34 39 43   ........ ..C8749C
0050  2d 34 31 42 46 36 2d 43  37 32 34 35 45 33 35 2d   -41BF6-C 7245E35-
0060  32 41 45 35 41 34 51 fb  d2 e6 00 00 00 00 00 00   2AE5A4Q. ........
0070  00 00 00 00 00 00 00 00  00 00                     ........ ..      

以下高亮部分就是此心跳包的Data部分:

我们可以认为心跳包有两个header,header_1为4字节,是校验位,校验该包是否由闪通客户端发出,由TickCount作为种子而得,具体算法是【禁止事项】~不难的。header_2也是4字节,全是0……

接下来是一个时间位,我叫他timeNow,占8字节,按小端模式,是由GetLocalTime()得到时间戳后,转换成从1970年1月1日00:00:00到此刻的毫秒数。

再之后是一个用户信息,我叫他userID,占4字节,闪通用户有一个userID,区别于闪通ID,这个userID在客户端的界面上几乎不可见,这个userID是用来和服务端通讯的时候使用,比如我的userID是678888,经过小端模式打包后的数据就是\xE8\x5B\x0A\x00

在后面有一个4字节的空白位,我叫他blank部分。

之后有一个timeRecv位,占8字节。这个值的机制是这样的,闪通帐号登录后,闪通客户端会发一个login包(包的类型之后会讲到),此时这个位置是空白的;服务端校验成功后,返回一个包,那个包里会存在这个值,目测是服务端接收到这个包的时间,作为之后的几个keep包和logout包里的值。同样按小端模式打包。

之后是最显眼的UUID位,长度28字节。UUID的算法和系统用户名有关(我这里是Administrator),先取系统用户名,然后经过一个类似md5的运算得到16位的字符串,再经过某个大型算法(没学过密码学。。),得到一个32位的字符串,再按'%s-%s-%s-%s' % (UUID[0:6], UUID[6:11], UUID[11:19], UUID[19:25])的方式重新组合而得。

在UUID后面的是action位,长度4字节,这个数值决定了这个包的类型,比如0xE6D2FB51代表login,0xE6D2FB53代表logout,除此之外还有keepAlive包和recvSucceed包,尝试几次就能全部得到。同样按小端打包。

之后有一个errorInfo位,本地基本上不会对该位复制,基本上都是由服务端返回的,因为这个位子上的值不为零就代表心跳失败所以暂时没研究他的值各代表什么意义。

最后两个footer位,总共占12字节,其实当做最后的padding也无所谓,我这里当作footer_1是4字节,footer_2是8字节,全为0。

图像更形象点: