引用 1
游客 [ IP:222.83.228.* ]
2007-09-07 09:56:56 
魔兽世界服务器端编写参考资料(3)原文地址:http://www.asstudio.de/wow/wow3.htm前两部分我们主要看了登陆服务器的验证方法和服务器列表的处理方式,现在我们来看看游戏服务器的验证部分和封包加解密方法。游 ...
魔兽世界服务器端编写参考资料(3)
原文地址:http://www.asstudio.de/wow/wow3.htm
前两部分我们主要看了登陆服务器的验证方法和服务器列表的处理方式,现在我们来看看游戏服务器的验证部分和封包加解密方法。
游戏服务器在收发封包时,有固定的结构:
接受封包时,封包加密前是由一个6字节长的封包头和主数据区组成,封包头为2字节UInt16型的封包除这两字节外的总长度加上4字节UInt32型的Opcode组成。发送封包时同样是封包头和主数据区组成,但是发送是封包头是4字节,因为Opcode用的是2字节的UInt16型,还有需要注意的是发送接收封包时的封包长度这个UInt16型高低位不对调。例子:一般来说讲整数型写入流中,这个整数的高低位会对调,比如511换算成16进制是01 FF,但是写入流中后则是FF 01。不对调的话也就是说还是01 FF,处理封包时一定要注意这一点。
游戏服务器使用的OpCode,点击这里查看。
游戏客户端在连上服务器以后,服务器端会随机生成一个4字节长的验证密码,我们称之为ServerSeed。紧接着客户端会发送一条CMSG_AUTH_SESSION命令,这个封包很长,不过不是所有数据都需要处理。封包头我们就不讨论了,从主数据区开始看。从第9字节开始处理,是用户名,以一个0字符结尾。接下来4个字节是一个客户端的验证密码,我们称之为ClientSeed。再下来20个字节就是客户端发送过来的验证信息,我们将他保存在digest变量中。服务器端根据这个信息经过一番运算来看客户端是否经过合法的验证。算法具体如下:
首先需要一个临时变量,dim t(3) as byte。不用赋值。下面公式中的所有变量均为byte()型。SessionKey为登陆服务器验证计算中的结果。
服务器端验证数据M1=sha1(accountname &t &ClientSeed &ServerSeed &Sessionkey)
如果M1=digest的话,那么验证通过。将SessionKey设置成封包加密密码(加解密方法后面会讲)。
服务器应答的封包结构:
4字节封包头,其中OpCode=SMSG_AUTH_RESPONSE。主数据区由一个1字节的ResponseCode(值是AUTH_OK,点击这里查看),一个2字节UInt16(值为0),再一个1字节Byte(值为0),再一个4字节UInt32(0值),最后再一个2字节UInt16(0值)组成。
例子代码:
view plaincopy to clipboardprint?
Private Function ProcessAuth(ByVal sock As Client ByVal data() As Byte) As Boolean Dim account As String digest() As Byte Dim i As Int16 = 8 For i = 8 To data.Length - 9 If data(i) = 0 Then Exit For account = account & Chr(data(i)) Next i sock.ClientSeed = br.ReadBytes(data i + 1 4) i = i + 5 digest = br.ReadBytes(data i 20) 'm_database.CurrentTableName = "Account" m_AccDB.UpdateTable() sock.SessionKey = help.hextobytes(m_AccDB.GetItem("id='" & account & "'" "session_key")) Dim sha As SHA1 Dim temp() As Byte t(3) As Byte sha = SHA1.Create temp = help.strtobytes(account) temp = help.CombinBytes(temp t) temp = help.CombinBytes(temp sock.ClientSeed) temp = help.CombinBytes(temp sock.ServerSeed) temp = help.CombinBytes(temp sock.SessionKey) sha.TransformFinalBlock(temp 0 temp.Length) temp = sha.Hash If help.CompareBytes(digest temp) Then sock.Crypt.Key = sock.SessionKey Dim pck() As Byte head() As Byte pck = bw.WriteData(pck Helper.BinWriter.Types.UInt16 Convert.ToUInt16(Packet.Opcode.OpCodes.SMSG_AUTH_RESPONSE)) pck = bw.WriteData(pck Helper.BinWriter.Types.Byte Packet.Opcode.AuthResponseCodes.AUTH_OK) pck = bw.WriteData(pck Helper.BinWriter.Types.UInt16 Convert.ToUInt16(0)) pck = bw.WriteData(pck Helper.BinWriter.Types.Byte Convert.ToByte(0)) pck = bw.WriteData(pck Helper.BinWriter.Types.UInt32 Convert.ToUInt32(0)) pck = bw.WriteData(pck Helper.BinWriter.Types.UInt16 Convert.ToUInt16(0)) m_SendMgr.AddPacket(sock pck) End If End Function
Private Function ProcessAuth(ByVal sock As Client ByVal data() As Byte) As Boolean Dim account As String digest() As Byte Dim i As Int16 = 8 For i = 8 To data.Length - 9 If data(i) = 0 Then Exit For account = account &Chr(data(i)) Next i sock.ClientSeed = br.ReadBytes(data i + 1 4) i = i + 5 digest = br.ReadBytes(data i 20) 'm_database.CurrentTableName = "Account" m_AccDB.UpdateTable() sock.SessionKey = help.hextobytes(m_AccDB.GetItem("id='" &account &"'" "session_key")) Dim sha As SHA1 Dim temp() As Byte t(3) As Byte sha = SHA1.Create temp = help.strtobytes(account) temp = help.CombinBytes(temp t) temp = help.CombinBytes(temp sock.ClientSeed) temp = help.CombinBytes(temp sock.ServerSeed) temp = help.CombinBytes(temp sock.SessionKey) sha.TransformFinalBlock(temp 0 temp.Length) temp = sha.Hash If help.CompareBytes(digest temp) Then sock.Crypt.Key = sock.SessionKey Dim pck() As Byte head() As Byte pck = bw.WriteData(pck Helper.BinWriter.Types.UInt16 Convert.ToUInt16(Packet.Opcode.OpCodes.SMSG_AUTH_RESPONSE)) pck = bw.WriteData(pck Helper.BinWriter.Types.Byte Packet.Opcode.AuthResponseCodes.AUTH_OK) pck = bw.WriteData(pck Helper.BinWriter.Types.UInt16 Convert.ToUInt16(0)) pck = bw.WriteData(pck Helper.BinWriter.Types.Byte Convert.ToByte(0)) pck = bw.WriteData(pck Helper.BinWriter.Types.UInt32 Convert.ToUInt32(0)) pck = bw.WriteData(pck Helper.BinWriter.Types.UInt16 Convert.ToUInt16(0)) m_SendMgr.AddPacket(sock pck) End If End Function
下面我们再来看看游戏服务器的封包加解密方法。首先,如果没有设置加密密码Key,那么则不进行加密,一旦设置密码则就加密。加密封包只加密封包头,接受6字节,发送4字节。加解密方法看下面的代码(我将整个加解密做成了一个类,方便调用):
view plaincopy to clipboardprint?
Namespace MyWoW.GameServer.Crypt Public Class WoWCrypt Private m_key() As Byte decKeyIndex As Byte decPrevCT As Byte encKeyIndex As Byte encPrevCT As Byte '// Block size for encryption Const CRYPTED_SEND_LEN = 4 '// Block size for decription Const CRYPTED_RECV_LEN = 6 '// Size of a key Const KEY_LEN = &H28 Public Sub New() End Sub Public Property Key() As Byte() Get Return m_key End Get Set(ByVal Value As Byte()) m_key = Value End Set End Property Public Function Decrypt(ByVal data() As Byte) As Byte() Dim ckey() As Byte ckey = Me.Key If ckey Is Nothing Then Return data Dim I As Integer For I = 0 To CRYPTED_RECV_LEN - 1 Dim tmp As Byte = data(I) tmp2 As Int16 tmp2 = Convert.ToInt16(data(I)) - Convert.ToInt16(decPrevCT) If tmp2 < 0 Then tmp2 = Convert.ToInt16(data(I)) + 256 - Convert.ToInt16(decPrevCT) data(I) = ckey(decKeyIndex) Xor tmp2 decPrevCT = tmp decKeyIndex += 1 decKeyIndex = decKeyIndex Mod KEY_LEN Next I Return data End Function Public Function Encrypt(ByVal data() As Byte) As Byte() Dim ckey() As Byte tmp As Int16 ckey = Me.Key If ckey Is Nothing Then Return data Dim I As Integer For I = 0 To CRYPTED_SEND_LEN - 1 tmp = Convert.ToInt16(encPrevCT) + Convert.ToInt16((ckey(encKeyIndex) Xor data(I))) If tmp > 255 Then tmp = tmp - 256 data(I) = tmp encPrevCT = data(I) encKeyIndex += 1 encKeyIndex = encKeyIndex Mod KEY_LEN Next I Return data End Function End Class End Namespace
Namespace MyWoW.GameServer.Crypt Public Class WoWCrypt Private m_key() As Byte decKeyIndex As Byte decPrevCT As Byte encKeyIndex As Byte encPrevCT As Byte '// Block size for encryption Const CRYPTED_SEND_LEN = 4 '// Block size for decription Const CRYPTED_RECV_LEN = 6 '// Size of a key Const KEY_LEN = &H28 Public Sub New() End Sub Public Property Key() As Byte() Get Return m_key End Get Set(ByVal Value As Byte()) m_key = Value End Set End Property Public Function Decrypt(ByVal data() As Byte) As Byte() Dim ckey() As Byte ckey = Me.Key If ckey Is Nothing Then Return data Dim I As Integer For I = 0 To CRYPTED_RECV_LEN - 1 Dim tmp As Byte = data(I) tmp2 As Int16 tmp2 = Convert.ToInt16(data(I)) - Convert.ToInt16(decPrevCT) If tmp2 255 Then tmp = tmp - 256 data(I) = tmp encPrevCT = data(I) encKeyIndex += 1 encKeyIndex = encKeyIndex Mod K
关键词:参考资料  端编写  服务器  
验证码: