QQ协议分析(一)

QQ协议首选的传输层是UDP,如果UDP不可登陆,那么会再尝试使用TCP进行传输。UDP使用的端口是8000,TCP使用的端口是443,应用协议基本一样,只是在通过TCP进行传输时,前两个字节为协议内容的长度(包括2个字节)。

QQ协议中每个通信内容都带有一个协议头部,如下图:

20150508171015088

其中标识占一个字节,版本号、命令字和序号都是2个字节,QQ号码有4个字节,接下来是数据部分(已加密),最后是一个尾部标识1个字节。

在进行协议还原的时候,最关心的就是协议头部的命令字,需要根据不同的命令字,来进行相应的处理,最终获取密钥解密聊天内容。

在2012这一个版本出来之前,接触包的命令是0091,不过QQ2012之后现在的接触包是0825。

分析最新的qq2014,发现特征码是0828,客户端的特征串是  02 00 00 00 01 01 01 00 00 67 49

QQ协议的所有包体都有一个很明显又固定的特征,那就是它每一个包体的未加密部分基本相同,加密部分也能通过未加密部分找出密钥来解密包体。

包结构类型: 

 

TCPF包我们把它分为5类: 

 

登录请求包(LIPLogIn Packet),它是由客户端向服务器发出登录请求的数据包。 

 

登录应答包(LRPLogin Reply Packet),它是由服务器响应客户端登录请求的数据包。

 

注销请求包(LOPLogOut Packet),它是由客户端向服务器发出注销登录请求的数据包,服务器对这个包不作应答。 

 

客户端其它包(CSPClient Sent Packet),它是由客户端向服务器发送的其它包。

 

服务器其它包(SSPServer Sent Packet),它是由服务器向客户端发送的其它包。

 

包头: 

 

所有TCPF包的前7个字节是包头,包头可以识别TCPF包的内容。包头的格式为: 

 

第0字节:TCPF包标识:0x02 

 

第1-2字节:发送者标识。如果是0x01 0x00,表明是由服务器发送。客户端的标识与所使用的使用的QQ版本有关,目前最新版本QQ2003(0808)的标识为0x0A 0x1D。具体的协议的格式与这个字段所标识的客户端版本有关。目前我们以这个最新的0A1D版本来讨论。 

 

第3-4字节:命令编号。具体的命令编号含义在《QQ协议概述》(Protocol Overview.rtf)中有描述。如果这个字段是0x00 0x01,那么这是一个注销请求包。如果这个字段是0x00 0x22,而发送者标识是0x01 0x00,那么这是一个登录应答包。如果这个字段是0x00 0x22,而发送者标识是其它(例如0x0A 0x1D),那么这是一个登录请求包。其它的命令代码表明是其它包,我们通过发送者标识来区分它是CSP还是SSP 

 

第5-6字节:命令序列号。客户端和服务器都有各自的当前发送序列号。每初始发出一个指令的时候,使用当前的序列号,然后把当前序列号加一,如果超过0xFFFF,就绕回。如果是响应对方发出的命令,则使用这个命令的序列号。例如,客户端当前的序列号为0x1110,它向服务发送一个0x0016命令,它使用0x1110这个序列号,服务器收到以后,返回一个序列号为0x11100x0016命令响应。下一次,客户端又发送一个0x0026命令,这一次它使用加一了的序列号0x1111,服务器也响应0x1111序列号的一个0x0026命令响应。如果这是服务器要向客户端发送0x0017命令,它使用它自己的当前序列号,比如说0x2220,客户端收到以后,也响应一个序列号为0x22200x0017命令应答。我们可以通过序列号来判断发出的指令是否已经得到了应答,如果没有,可以重发。服务器对收到的命令的序列号顺序没有要求。服务器也不会一定按照发出的顺序给予应答。  

 

包尾: 

 

所有的TCPF包都以0x03作为包尾。在包头和包尾中间的包数据则不同类型的包有所不同。 

 

LIP包: 

 

登录请求包的包数据格式为: 

 

7-10字节(4 bytes):发出登录请求的QQ号码。这是一个Big Endian(高位在前)的unsigned long型数值。例如:0x01 0x82 0x5D 0x90就是0x01825D90,转换为十进制是25320848,表明发出请求的QQ号是25320848 

 

11-26字节(16 bytes):随机密钥。这个密钥由于加密后面的数据。QQ使用TEA算法来加密数据。它使用的是128bit16 bytes)的密钥。在0A1D版本中,这个密钥已经固定为1601 

 

27-106字节(80 bytes):加密后的登录包数据。  

 

LRP包: 

 

从第7字节开始到包尾前:加密的登录应答包数据。解密的密钥随客户端版本的不同,有不同的可能。在旧有版本中,使用登录包的随机密钥,在后期的版本,使用用户QQ密码的MD5 Digest。在0A1D中,使用QQ密码的MD5 DigestMD5 Digest(这体现了腾讯有多么的愚昧和无耻,为了改变而改变)。LRP包内数据很重要的是16个字节的Session Key,它用来作为以后通讯的加密密钥。  

 

LOP包: 

 

它的序列号总是0xFFFF。不过,在新的版本中,好象已经没有了这个要求。 710字节(4 bytes):发送注销登录请求的QQ号码。 

 

11字节到包尾前:加密的注销登录包数据。使用Session Key作为密钥。  

 

CSP包:

 

7-10字节(4 bytes):发送请求的QQ号码。

 

11字节到包尾前:加密的包数据。使用Session Key作为密钥。  

 

SSP包: 

 

从第7字节开始到包尾前:加密的服务器发送包数据,使用Session Key作为密钥。  

 

QQ加密算法概述: 

 

 

 

 

 

 

 

 

 

QQ使用的加密算法来源于一种称为TEATiny Encryption Algorithm)加密算法。它是在1994年由英国剑桥大学的David WheelerRoger Needham所发明的一种加密方法。大概来说,它是使用128bit密钥加密64bit数据产生64bit输出的一种算法。这种算法的可靠性是通过加密轮数而不是算法的复杂度来保证的。具体的算法可以参考:

http://www.ftp.cl.cam.ac.uk/ftp/papers/djw-rmn/djw-rmn-tea.html。

实现可以参考:

http://abcn.net/crypto.htm

 

 

QQ使用的加密算法来源于一种称为TEATiny Encryption Algorithm)加密算法。它是在1994年由英国剑桥大学的David WheelerRoger Needham所发明的一种加密方法。大概来说,它是使用128bit密钥加密64bit数据产生64bit输出的一种算法。这种算法的可靠性是通过加密轮数而不是算法的复杂度来保证的。具体的算法可以参考:。实现可以参考:。

QQ使用16轮的加密(这是最低限,推荐应该是32轮)。

QQ在使用这个算法的时候,由于需要加密不定长的数据,所以使用了一些常规的填充办法和交织算法(也就是说,把前一组的加密结果和后一组的进行运算,产生新的结果)。

具体的填充算法是:原始字符串加上8个字节再加上填充字符数应该是8的倍数(至少填充2个字节)。填充后的字符串是这样组织的。第一个字节,为填充字符数减2 OR 0xA8。后面是填充字节。然后是待加密的数据,最后是70。填充的字节一般是0xAD,但再0A1dD版本中,会使用随机的填充字符串。一般,我们会用解密后最后是否7个零来判断是否正确的解密。

交织算法:第一个64bits块,按照一般的TEA加密。下一个64bit块与上一组的加密结果XOR生成待加密数据,加密后与上一组的待加密数据XOR生成加密结果。

阅读剩余
THE END