首先,你需要安裝有VPC,這樣你才能運行PC版的QQ。其次,你要有你機器root用戶的權限。
然后,你啟動VPC,注意先不要登錄QQ。
打開終端窗口。輸入su命令,在提示里面輸入root用戶密碼,進入root用戶。這時候提示符應該是個#號。
以root身份運行終端命令:
tcpdump -w dump.dat -s 0 udp
這個命令的作用是把網絡上傳輸的數據截獲下來。
-w dump.dat 意思是把輸出存到dump.dat文件下。
-s 0 是指定保存完整的包,如果指定一個非零的數值,那么將會保存這個數值的長度。
udp 是指只保存UDP協議的數據(騰訊文字通訊所采用的協議)。
(你有PC的話,也可以使用windump來截獲你PC上的QQ的數據包。windump是windows下的命令行程序,它的使用參數和tcpdump完全一樣。你可以在 http://windump.polito.it/ 中下載)。
然后我們啟動VPC里面的QQ,執行我們所想要研究的有關操作。完成以后,會到終端窗口,按ctrl-c中斷tcpdump的運行。這時,在當前目錄下就有dump.dat了。
然后,可以用hexedit打開這個文件,觀察一下我們dump的結果。
里面是連接著的數據,是按照“QQ包->UDP包->IP包->鏈路層封裝->tcpdump的文件格式”的層次結構進行封裝的。
下面是一個數據片段:
0008: A1 B2 C3 D4 00 02 00 04
0008: 00 00 00 00 00 00 00 00
0016: 00 00 FF FF 00 00 00 01
0024: 3F 44 32 28 00 0C 2D AF
0032: 00 00 00 96 00 00 00 96
0040: 00 06 25 60 F4 C0 00 03
0048: 93 A7 09 38 08 00 45 00
0056: 00 88 8E 53 00 00 80 11
0064: 9D 9D C0 A8 01 66 CA 68
0072: 81 FD C2 34 1F 40 00 74
0080: C3 AD 02 08 16 00 22 00
0088: 10 01 82 5D 90 6F 30 FD
0096: 96 3B B1 0F E5 FF 8E 3E
0104: 4B 38 E2 86 E1 8A F7 C8
0112: CA B2 01 76 B6 ED 9E 2B
0120: 97 FD B9 7F 23 B2 09 02
0128: 71 22 94 E3 4B E8 E2 8F
0136: FD FF 02 87 83 0B 32 57
0144: 73 91 7F EF 7B 7A 60 CB
0152: 44 A4 B5 CA 13 19 F6 CE
0160: D5 EC 2F D5 8A 88 22 48
0168: 14 4E 44 08 18 37 9D 8D
0176: AA 42 9C 88 A4 AB 44 0D
0184: 4B 23 74 AC ED 03 3F 44
0192: 32 29 00 06 D0 EA 00 00
0200: 00 68 00 00 00 68 00 06
0208: 25 60 F4 C0 00 03 93 A7
0216: 09 38 08 00 45 00 00 5A
0224: 8E 54 00 00 80 11 B2 F9
0232: C0 A8 01 66 3D AC F9 8A
0240: C2 35 1F 40 00 46 23 2C
0248: 05 01 00 01 82 5D 90 01
0256: 1F 02 16 08 00 00 00 00
0264: 00 00 00 00 00 00 00 00
0272: 00 00 00 00 01 02 5E FD
0280: 00 01 01 00 00 00 00 42
0288: 62 0B 9F 27 F3 D9 FB 05
0296: C6 54 E3 7F 01 E4 B4 01
0304: 00 00 00 00 04 00 3F 44
0312: 32 29 00 06 F6 48 00 00
0320: 00 B3 00 00 00 B3 01 00
0328: 5E FF FF FA 00 06 25 60
0336: F4 C0 08 00 45 00 00 A1
0344: 00 4C 00 00 04 11 F9 CE
0352: 18 C0 B3 77 EF FF FF FA
0360: 04 09 07 6C 00 8D 91 43
0368: 4D 2D 53 45 41 52
Tcpdump文件格式:
首先我們看到的是最外面的一張包裝紙:tcpdump的文件格式。它的格式是這樣的(詳細的描述可以參考:libpcap-format的資料):
文件頭 | 數據包頭 | 鏈路層數據 | 數據包頭 |鏈路層數據| ....
首先,每個文件以一個24字節長的文件頭開頭,我們需要知道的是最前面的四個字節是:A1 B2 C3 D4,如果不是這個標識,那么就不是tcpdump生成的數據文件(如果是PC上的windump生成的文件,那么則是D4 C3 B2 A1,以表明PC上的endian不同,我們這里不用關心這個區別)。
跳過這24個字節,下面就是以“數據包頭|鏈路層數據”為一組的這樣一組組的數據。數據包頭不是網絡上真正傳輸的數據,它包含的信息主要是截獲這個包的時間等信息。它的長度16個字節。我們關心的是第8-11和9-15字節(我們按編程的習慣,把第一個字節稱為第0字節,下同)。前者表明后面的鏈路層數據包在文件里面的長度,后者表明它的實際長度。兩者可能不同是因為可能存在截斷的情況。由于我們使用了-s 0參數,所以他們應該是相同的。從數據包頭結束,到長度指明的字節數為止,是實際在網絡中傳輸的鏈路層數據包。然后,就是下一個數據包頭。這樣,我們就可以逐個把tcpdump文件的封裝去掉,獲得一個一個實際在網絡中傳輸的數據包了。例如,我們忽略文件頭,從第24字節開始的3F 44 32 28 ...就是數據包,數據包的第8-11字節:00 00 00 96就是這個后面數據鏈路層數據包的長度。也就是說,從40字節開始00 06 25 60...的150(0x96的轉換成10進制)個字節就是實際網絡傳輸的鏈路層數據包。然后,我們在第190(40+150)字節的位置又看到了3F 44 32 29...的下一個數據包頭。
我們這樣就獲得了一個個的鏈路層數據包。我們上面例子中的第一個是:
0000: 00 06 25 60 F4 C0 00 03
0008: 93 A7 09 38 08 00 45 00
0016: 00 88 8E 53 00 00 80 11
0024: 9D 9D C0 A8 01 66 CA 68
0032: 81 FD C2 34 1F 40 00 74
0040: C3 AD 02 08 16 00 22 00
0048: 10 01 82 5D 90 6F 30 FD
0056: 96 3B B1 0F E5 FF 8E 3E
0064: 4B 38 E2 86 E1 8A F7 C8
0072: CA B2 01 76 B6 ED 9E 2B
0080: 97 FD B9 7F 23 B2 09 02
0088: 71 22 94 E3 4B E8 E2 8F
0096: FD FF 02 87 83 0B 32 57
0104: 73 91 7F EF 7B 7A 60 CB
0112: 44 A4 B5 CA 13 19 F6 CE
0120: D5 EC 2F D5 8A 88 22 48
0128: 14 4E 44 08 18 37 9D 8D
0136: AA 42 9C 88 A4 AB 44 0D
0144: 4B 23 74 AC ED 03
鏈路層數據包:
下面我們要撕去鏈路層數據包這個第二層包裝紙。鏈路層數據包格式是和傳輸的方式有關的:如果我們是在局域網里面共享上網,那么一般是用稱為RFC894以太網協議,少數情況下也會是RFC 1042的802.3協議。如果你用Modem撥號上網,那么可能會是RFC 1055的SLIP協議,如果是用ADSL,那么將會是RFC 1548的PPP協議。
鏈路層數據對我們來說意義不大,我們要做的是剝去這層包裝紙而已。
RFC894/RFC1042/RFC 1548:
這三種協議的形式都是:
包頭|IP數據包|(包尾)
對RFC894,包頭是14字節;RFC1042,包頭是22字節;RFC 1548,包頭是5個字節。我們跨過這些字節,就是IP包的數據了。包尾如何并不要緊,因為IP包的內容本身會告訴我們它的長度。
在上面的鏈路層數據包中,我們跳過14個字節,第14字節以45 00 00 88開始的就是IP包的數據。其它的協議也可以這樣處理。
RFC 1055:
IP數據包被封裝在一對的0xc0字符中間。但是,由于數據包中間就不能有0xc0字符,所以原來的0xc0字符被其它代替了,我們要把它還原。方法是搜索這個數據包,把0xdb 0xdc轉換為0xc0;0xdb 0xdd轉換為0xdb。比較麻煩,所以,最后不要使用它來截取數據。
IP包的第2-3字節是它的長度,上面我們看到的第14字節開始的IP包,它的長度就是00 88。也就是136個字節。所以,從14字節開始的136個字節就是IP數據包。這樣,我們就剝去了鏈路層的包裝紙,獲取了IP包。
我們上面的例子的第一個IP包是:
0000: 45 00 00 88 8E 53 00 00
0008: 80 11 9D 9D C0 A8 01 66
0016: CA 68 81 FD C2 34 1F 40
0024: 00 74 C3 AD 02 08 16 00
0032: 22 00 10 01 82 5D 90 6F
0040: 30 FD 96 3B B1 0F E5 FF
0048: 8E 3E 4B 38 E2 86 E1 8A
0056: F7 C8 CA B2 01 76 B6 ED
0064: 9E 2B 97 FD B9 7F 23 B2
0072: 09 02 71 22 94 E3 4B E8
0080: E2 8F FD FF 02 87 83 0B
0088: 32 57 73 91 7F EF 7B 7A
0096: 60 CB 44 A4 B5 CA 13 19
0104: F6 CE D5 EC 2F D5 8A 88
0112: 22 48 14 4E 44 08 18 37
0120: 9D 8D AA 42 9C 88 A4 AB
0128: 44 0D 4B 23 74 AC ED 03
IP包
IP包是網絡上傳送的與傳輸線路無關的數據包,也是我們開始需要真正關心的數據。IP包的格式是:
IP包頭|IP包數據(我們這里就是UDP數據包)
IP包頭,除了我們剛才說的包長度(第2-3字節)以外,還有幾個重要的信息是我們所需要關心的:
第12-15和第16-19分別為源和目的IP地址。它用四個字節來代表一個IP地址,把每個字節轉換成十進制,就是我們熟悉的IP地址。比如,上面的源IP地址:C0 A8 01 66就是192.168.1.102,這是我局域網的IP地址,所以,這是一個從我的機器上發出的包。目的地址是CA 68 81 FD就是202.104.129.253。從后面我們對QQ數據包的了解我們知道這是一個發往服務器的包,所以我們就獲得了一個QQ服務器的IP地址。(注意,并不是全部發出的包都是發往服務器的?。?/P>
如果,找到一個原來不知道的服務器,那么是一個很重要的發現。
第0個字節,高4位為IP的版本號,低四位為IP包頭的長度。比如說,我們上面的數據包第一個字節為45,它的高4位為4,表明它是我們通常所說的IPv4協議,低四位為5,表明IP包頭的長度為5X4=20字節(頭的長度是以四字節為單位的)。這樣表明從第20字節開始就是IP包的數據部分,也就是UDP包的內容了。這樣我們可以剝離出UDP包:
0000: C2 34 1F 40 00 74 C3 AD
0008: 02 08 16 00 22 00 10 01
0016: 82 5D 90 6F 30 FD 96 3B
0024: B1 0F E5 FF 8E 3E 4B 38
0032: E2 86 E1 8A F7 C8 CA B2
0040: 01 76 B6 ED 9E 2B 97 FD
0048: B9 7F 23 B2 09 02 71 22
0056: 94 E3 4B E8 E2 8F FD FF
0064: 02 87 83 0B 32 57 73 91
0072: 7F EF 7B 7A 60 CB 44 A4
0080: B5 CA 13 19 F6 CE D5 EC
0088: 2F D5 8A 88 22 48 14 4E
0096: 44 08 18 37 9D 8D AA 42
0104: 9C 88 A4 AB 44 0D 4B 23
0112: 74 AC ED 03
UDP包
UDP包是多數即時通訊軟件采用的協議。它的格式是:
UDP包頭|UDP包數據(這里就是騰訊QQ協議包)
UDP包頭是固定8個字節。
第0-1字節是源端口號,第2-3是目的端口號。一般,我們客戶端的端口號可以隨便選?。ㄓ匈Y料說是4000,但是實際發現,新版的QQ已經是隨便選取,沒有限制了)。從上面的UDP包,我們從以前IP包的信息知道是我們發送出去數據包,所以目的端口號就是服務器所使用的端口號。這里是1F 40,也就是8000號端口,目前還沒有發現使用其他端口的,所以,如果發現有服務器使用其他端口,也將是一個很重要的信息。
第4-5字節是UDP包的長度,這不是很重要,但是也可以用它來檢驗一下我們的剝離過程有沒有錯誤。
我們去除掉頭8個字節,剩下的就是QQ協議包了:
0000: 02 08 16 00 22 00 10 01
0008: 82 5D 90 6F 30 FD 96 3B
0016: B1 0F E5 FF 8E 3E 4B 38
0024: E2 86 E1 8A F7 C8 CA B2
0032: 01 76 B6 ED 9E 2B 97 FD
0040: B9 7F 23 B2 09 02 71 22
0048: 94 E3 4B E8 E2 8F FD FF
0056: 02 87 83 0B 32 57 73 91
0064: 7F EF 7B 7A 60 CB 44 A4
0072: B5 CA 13 19 F6 CE D5 EC
0080: 2F D5 8A 88 22 48 14 4E
0088: 44 08 18 37 9D 8D AA 42
0096: 9C 88 A4 AB 44 0D 4B 23
0104: 74 AC ED 03
我們有一個命令行小工具showUDP,可以從tcpdump截取的文件中,直接顯示其中UDP包的內容。
QQ協議包
QQ協議包的構成是:
QQ協議包頭|QQ命令包|包尾
QQ包頭是7個字節:分別的意義是:
第0-0字節:總是02,表明是基本的QQ協議。在新版本的QQ中,我們發現還有使用06和01的,大約的作用似乎是:06是向服務器(和不同QQ使用的服務器不同)請求發送一些作用不明的文件。01是服務器向它進行發送這個文件。目前,我們明白作用的是02協議族。
第1-2字節:發送者的QQ軟件版本代碼。如果是01 00表示是發自服務器的包。這時候我們檢查源IP地址就可以獲得服務器的IP。
第3-4字節:QQ指令代碼。如果發現有新的指令,將是很重要的信息。
第5-6字節:指令序列號。QQ的指令總是成對出現的,也就是說,一方發出一個命令,將會收到另一方的同樣序列號的應答。另外,發送方每條指令的序列號都是上一條指令的加一。有兩個方面要注意的是,每一方都維持自己的序列號,也就是說,客戶端的當前序列號和服務器的當前序列號是不一致的,當客戶端為指令發出方的時候,它使用自己的當前序列號,而服務器作為應答方,在應答的時候使用的接受到的命令的序列號;反之,如果是服務器是指令的發出方,那么它就使用自己的當前序列號,而不用理會客戶端上一條指令的序列號。另外一個事情是,由于服務器會同時和多個客戶端通信,所以,對每個客戶端收到的服務器指令的序列號不是連續的,序列號的連續性不應該作為丟包的判斷依據。
另外,通信開始客戶端的第一個序列號是隨機選取的,但似乎沒有發現大過0x00ff的。最后的退出登錄數據包總是使用0xffff作為序列號,而且是不會有應答的。
包尾是一個字節,目前發現總是0x03。
由于我們截取的是機器上的全部UDP包,所以我們需要使用這些信息來綜合判斷我們當前分析的是不是QQ的命令。
這樣我們就可以剝離出QQ的命令包數據部分:
0000: 01 82 5D 90 6F 30 FD 96
0008: 3B B1 0F E5 FF 8E 3E 4B
0016: 38 E2 86 E1 8A F7 C8 CA
0024: B2 01 76 B6 ED 9E 2B 97
0032: FD B9 7F 23 B2 09 02 71
0040: 22 94 E3 4B E8 E2 8F FD
0048: FF 02 87 83 0B 32 57 73
0056: 91 7F EF 7B 7A 60 CB 44
0064: A4 B5 CA 13 19 F6 CE D5
0072: EC 2F D5 8A 88 22 48 14
0080: 4E 44 08 18 37 9D 8D AA
0088: 42 9C 88 A4 AB 44 0D 4B
0096: 23 74 AC ED
到這里為止,我們已經可以觀察網絡上客戶端往返的指令的大概情況,而了解QQ協議的大概框架。另外將敘述數據包文件的分析。