包結構類型:
TCPF包我們把它分為5類:
登入請求包(LIP,LogIn Packet),它是由用戶端向伺服器發出登入請求的資料包。
登入應答包(LRP,Login Reply Packet),它是由伺服器響應用戶端登入請求的資料包。
登出請求包(LOP,LogOut Packet),它是由用戶端向伺服器發出登出登入請求的資料包,伺服器對這個包不作應答。
用戶端其它包(CSP,Client Sent Packet),它是由用戶端向伺服器發送的其它包。
伺服器其它包(SSP,Server 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這個序列号,伺服器收到以後,傳回一個序列号為0x1110的0x0016指令響應。下一次,用戶端又發送一個0x0026指令,這一次它使用加一了的序列号0x1111,伺服器也響應0x1111序列号的一個0x0026指令響應。如果這是伺服器要向用戶端發送0x0017指令,它使用它自己的目前序列号,比如說0x2220,用戶端收到以後,也響應一個序列号為0x2220的0x0017指令應答。我們可以通過序列号來判斷發出的指令是否已經得到了應答,如果沒有,可以重發。伺服器對收到的指令的序列号順序沒有要求。伺服器也不會一定按照發出的順序給予應答。
包尾:
所有的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算法來加密資料。它使用的是128bit(16 bytes)的密鑰。在0A1D版本中,這個密鑰已經固定為16個01。
第27-106位元組(80 bytes):加密後的登入包資料。
LRP包:
從第7位元組開始到包尾前:加密的登入應答包資料。解密的密鑰随用戶端版本的不同,有不同的可能。在舊有版本中,使用登入包的随機密鑰,在後期的版本,使用使用者QQ密碼的MD5 Digest。在0A1D中,使用QQ密碼的MD5 Digest的MD5 Digest(這展現了騰訊有多麼的愚昧和無恥,為了改變而改變)。LRP包内資料很重要的是16個位元組的Session Key,它用來作為以後通訊的加密密鑰。
LOP包:
它的序列号總是0xFFFF。不過,在新的版本中,好象已經沒有了這個要求。
第7-10位元組(4 bytes):發送登出登入請求的QQ号碼。
第11位元組到包尾前:加密的登出登入包資料。使用Session Key作為密鑰。
CSP包:
第7-10位元組(4 bytes):發送請求的QQ号碼。
第11位元組到包尾前:加密的包資料。使用Session Key作為密鑰。
SSP包:
從第7位元組開始到包尾前:加密的伺服器發送包資料,使用Session Key作為密鑰。
QQ加密算法概述:
QQ使用的加密算法來源于一種稱為TEA(Tiny Encryption Algorithm)加密算法。它是在1994年由英國劍橋大學的David Wheeler和Roger 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使用16輪的加密(這是最低限,推薦應該是32輪)。
QQ在使用這個算法的時候,由于需要加密不定長的資料,是以使用了一些正常的填充辦法和交織算法(也就是說,把前一組的加密結果和後一組的進行運算,産生新的結果)。
具體的填充算法是:原始字元串加上8個位元組再加上填充字元數應該是8的倍數(至少填充2個位元組)。填充後的字元串是這樣組織的。第一個位元組,為填充字元數減2 OR 上0xA8。後面是填充位元組。然後是待加密的資料,最後是7個0。填充的位元組一般是0xAD,但再0A1dD版本中,會使用随機的填充字元串。一般,我們會用解密後最後是否7個零來判斷是否正确的解密。
交織算法:第一個64bits塊,按照一般的TEA加密。下一個64bit塊與上一組的加密結果XOR生成待加密資料,加密後與上一組的待加密資料XOR生成加密結果。
轉載:http://www.csna.cn/network-analyst-1382-1-1.html?sid=2881C8