在網上看了半天,沒看明白,現在總算明白了。
下面是一條最簡單的指令,沒有資料
45 0 0 34 4D C5 40 0 72 6 20 E1 D3 93 4 CC C0 A8 1 16
4E 23 6 8F 36 CA 45 A3 EC 73 CB FB 80 10 1E E8 D0 2A 0 0
1 1 8 A 15 F AC FE 0 0 A1 EF
第一行是IP包頭,
(2-3)位元組0 34 表示包總長hex(34)=52
計算校正和時,先把(10-11)16位IP首部校正和置0(如果不置0,算出的校正和是0,這就相當於檢測原來的校正和是否正確),在去用網上流傳的checksum 函數就可算出來了。(20 E1)和指令中的一致。
4500+0034+4DC5+4000+7206+0(20E1置0)+D393+4CC+c0A8+116=2DF1C
2+DF1C=DF1E
~DF1E=20E1
第二行是TCP包頭,
(12)80 表示TCP包頭長hex(80/4)=32,後面的12個位元組是TCP包頭的可選項(可憐我一直以為是TCP的偽包頭,實際上TCP的偽包頭是不發的,根本就不存在)。
計算TCP的校正和時,有三部分:TCP偽包頭+TCP包頭+資料。
這條指令沒有資料,就只用算兩部分,
偽包頭自己寫,
源IP地址 目的IP地址 置空(0) 協議類型 TCP包的總長度
D3 93 4 CC C0 A8 1 16 0 6 0 20
源IP地址,目的IP地址,協議類型在IP包頭中有,直接移過來, TCP包的總長度用IP包中的總長度0x34-IP包的長度0x14(定長20)=0x20。
然後把TCP偽包頭+TCP包頭+資料三部分合起來(TCP包頭的(16-17)校正和置0),再用鼎鼎大名的checksum函數,就可算出校正和 D0 2A .
_________________________________________________________________________________
unsigned short checksum(unsigned short *buf, int nword)
{
unsigned long sum;
for(sum = 0; nword > 0; nword--)
sum += *buf++;
sum = (sum>>16) + (sum&0xffff);
sum += (sum>>16);
return ~sum;
}
Type IPHeader
lenver As Byte '(0)4位首部長度+4位IP版本號碼
tos As Byte '(1)8位服務類型TOS
len As Integer '(2-3)16位總長度(位元組)* 包括資料
ident As Integer '(4-5)16位標識**
flags As Integer '(6-7)3位標誌位
ttl As Byte '(8)8位存留時間 TTL
proto As Byte '(9)8位協議 (TCP, UDP 或其他)
CheckSum As Integer '(10-11)16位IP首部校正和 **
sourceIP As Long '(12-15)32位源IP地址*
destIP As Long '(16-19)32位目的IP地址*
End Type
Type TcpHeader
srcPort As Integer '(0-1)源連接埠
dstPort As Integer '(2-3)目的連接埠
seqNum As Long '(4-7)順序號**
ackNum As Long '(8-11)期待獲得對方的TCP包編號**
h_len As Byte '(12)以32位元為單位的TCP前序長度,h_len / 4 即得到實際長度,包括ipheader和TCP偽首部的長度
flags As Byte '(13)標誌(URG、ACK等)
indow As Integer '(14-15)視窗大小**
chksum As Integer '(16-17)校正和**
urgptr As Integer '(18-19)緊急指標
End Type
'TCP偽首部 用於進行TCP校正和的計算,保證TCP效驗的有效性
Type TcpPsdHeader
sourceIP As Long '(0-3)源IP地址
destIP As Long '(4-7)目的IP地址
mbz As Byte ' '(8)置空(0)
ptcl As Byte '(9)協議類型(IPPROTO_TCP)
tcpl As Integer '(10-11)TCP包的總長度(單位:位元組)*
End Type