特别声明:
本人非常欣赏暴雪及他们的游戏,之所以写这个文章,是想让大家了解一些网络封包分析方面的常见方法以及学习暴雪游戏在网络处理方面的经验,偶认为作为一个网络编程者,熟练掌握封包分析的工具和方法应该是其基本功之一。本文所列的所有封包分析内容,全部是采用普通黑箱方式即可得来的,并未涉及对魔兽世界可执行程序的逆向工程。同时,除此文涉及的内容外,本人拒绝向任何人透露更详细的关于魔兽世界封包方面的更多内容,有兴趣者请自己进行相关的试验,本人在此文中也将尽量避免公开敏感的封包内容及相关加解密算法。谨以此文献给忠爱的暴雪!
一、登录模块流程及封包分析
我们先看登录流程。从封包流程来看,魔兽的登录流程是这样的:
1.由Client向登录/账号服务器(Login Server)发送用户名及密码等信息。此数据包的最后部分是用户名(明文表示,未加密),在用户名的前一个字节表示的是用户名的长度。登录/账号服务器向Client返回登录成功及后续连接到游戏服务器服务器所必备的信息等。这中间的两个来往数据包,我还没有看出具体有什么作用。在这个交互过程中,由登录/账号服务器向Client发送所有的游戏服务器列表,服务器列表数据包的内容包括:ip, port, 服务器上所拥有的角色个数等信息,因服务器列表内容过多,被客户端分为两次接收完毕。
2.Client收到Login Server的服务器列表后,根据最近访问的服务器标识(这个信息应该是包含在那个服务器列表数据包中),连接到最近游戏的那个游戏服务器(Game Server)。连接成功后,Game Server首先向Client发送一个8字节的数据包,据以往的常识判断,这个数据包的内容很可能是以后客户端与服务器通信的加密密钥。
3.Client向Game Server再次发送自己的账号信息。Game Server与Client经过两个数据包的交互后,向Client发送角色数据包,此包中包括了玩家在该Game Server所创建的所有角色信息,当然这个信息只是部分的,并不是该角色的所有信息。
4.在此后的通信过程中,Client每隔30秒向Game Server发送一个保持连接的包,该包长度为10字节,包的最后四字节是一个递增数字,前面6字节暂时未看出规律。
5.只要Client没有点击某个角色进入最终的Game Server,则Client要始终与Login Server保持连接。当Client点击角色进入Game Server时,Client才与Login Server断开连接。在以后的游戏过程中,Client始终与且仅与该Game Server进行数据通信。
通过对登录流程中的数据包初步分析,可以得出以下几个结论:
1.Client向Login Server发的第一个数据包,用户名部分是采用明文的,且该数据包的内容,每次登录都一样,并没有因时间的不同而发生改变。由此可以推算:针对于此数据包中的密码加密算法是固定不变的,换句话说,密码的加密算法是比较容易通过逆向工程被找到的。偶认为,针对于此处,服务器也应该先向客户端发送一个加密密钥,以后的通信可以用该密钥作为安全验证的依据。但暴雪没有这样作,最大的可能是为了提高服务器的效率,在登录服务器上,如果每个客户端一旦连接成功,登录服务器都得向客户端广播一个数据包的话,可能这个量还是比较大的,这可能延长了玩家的登录等待时间,所以他们没有在这块作。
2.Client在登录Login Server的地址,每次Login Server的登录地址都可能是不一样的。偶没有在客户端目录里找到这些地址,只在客户端目录里找到了四个大区的四个域名,我猜想,魔兽世界是用的DNS解析的简单方法来实现Login Server的简单动态均衡的。不知道这个猜想是否正确。
3.“根据玩家最近在玩的哪个游戏,由客户端和服务器自动为玩家选择进入这个游戏服务器”,这一项设定充分体现了暴雪一贯的风格:为玩家着想,最大限度地提高游戏的舒适度。再次对暴雪的态度予以肯定!
4.一旦玩家进入了游戏世界,客户端与服务器的通信端口会一直保持不变。即:魔兽世界的游戏世界服务器群设计结构采用的是带网关的服务器集群。
5.偶觉得在整个的登录流程中,让我产生最大疑问的就是Login Server与Client的连接保持逻辑。当Client与Game Server连接了之后,Client并未与Login Server断开,是一直保持连接的。后来,经进一步的抓包分析,Client之所以要与Login Server保持这样的连接,是为了当Client重新选择服务器时,不至于重新连接Login Server。当Client点击了"选择服务器"按纽后,Login Server会每隔5秒向Client发一个当前所有的服务器列表数据包。要知道,这个服务器列表数据包的内容可是非常大的,如果有玩家就打开了这个窗口不关闭,Login Server向这种情况的所有玩家每5秒钟就发一个服务器列表数据包,这个广播量可是很大的哦(2k左右,这可是一个用户是2k哦)。偶认为这里的逻辑设计是相当不合理的。Login Server如果为了给客户端提供一个最新的全局服务器列表,可以保持连接,但也没必要每隔5秒就向客户端发一个服务器列表,最多只在客户端在某个服务器上创建了不同的角色后再更新这个列表也是可以的,但只用更新这个列表中的变化内容即可,不用发全部的完整包,这样,在通信量上就小了很多。据说,魔兽刚开始的时候,产生DOWN机的原因就是登录模块没有处理好,偶不知道现在的这个情况是不是已经经过改良的了。但偶还是认为每隔5秒就向客户端发送一个2K的包,这一点是不可以被接受的。
以上只是针对于魔兽世界登录流程的简单分析,没有多少技术含量,拿出来跟大家相互讨论讨论,看看有没有可以借鉴的地方,后面还会有其它部分的封包分析.
偶在文章前面部分说过,作为一个网络编程人员,熟练使用截包软件和掌握基本的封包分析方法是其基本能力之一,发此文的目的一个原因也是希望向正在作网络编程的兄弟介绍一下相关工具的使用和常见的分析方法。下面补充一下关于封包分析的基本方法和相关工具:
1.你需要一个截包工具,偶推荐:commview,小巧但功能强大,支持自定义的封包分析插件以DLL形式装载,也就是说只要你愿意,你可以写个DLL对某类特殊形式的包进行显示、记录、解密等特别处理。
2.如何查看真正的封包数据。在commview里,会详细列出自网卡级别以上的各层封包数据,包括Ethernet层,IP层和TCP层。而我们作封包分析时,只需要关注TCP层。但TCP层里也有很多内容,对于我们的分析需求来说,我们需要关注的是其Data字段(在协议目录里可以看到"data length标识,点击即可查看data段")的内容。
3.TCP的几个状态对于我们分析所起的作用。在TCP层,有个FLAGS字段,这个字段有以下几个标识:SYN, FIN, ACK, PSH, RST, URG.其中,对于我们日常的分析有用的就是前面的五个字段。它们的含义是:SYN表示建立连接,FIN表示关闭连接,ACK表示响应,PSH表示有DATA数据传输,RST表示连接重置。其中,ACK是可能与SYN,FIN等同时使用的,比如SYN和ACK可能同时为1,它表示的就是建立连接之后的响应,如果只是单个的一个SYN,它表示的只是建立连接。TCP的几次握手就是通过这样的ACK表现出来的。但SYN与FIN是不会同时为1的,因为前者表示的是建立连接,而后者表示的是断开连接。RST一般是在FIN之后才会出现为1的情况,表示的是连接重置。一般地,当出现FIN包或RST包时,我们便认为客户端与服务器端断开了连接;而当出现SYN和SYN+ACK包时,我们认为客户端与服务器建立了一个连接。PSH为1的情况,一般只出现在DATA内容不为0的包中,也就是说PSH为1表示的是有真正的TCP数据包内容被传递。TCP的连接建立和连接关闭,都是通过请求-响应的模式完成的。