CheckSum问题 ( 积分: 50 )

  • 主题发起人 主题发起人 cyradg
  • 开始时间 开始时间
C

cyradg

Unregistered / Unconfirmed
GUEST, unregistred user!
即:计算TCP头部的Checksum值,如下:


tsd_hdr=packed record //定义TCP伪首部
saddr:ULONG; //源地址
daddr:ULONG; //目的地址
mbz:byte;
ptcl:byte; //协议类型
tcpl:USHORT; //TCP头部长度
end;
///////////////////////////////////////////
tcp_header= packed record
sport:USHORT; // 源端口号
dport:USHORT; // 目标端口号
seq_number:DWORD; //32位序号
ack_number:DWORD; //32位确认号
res_thl:UCHAR; //TCP头长度(4Bits;其值X4),保留值(4Bits)
flags_fo:UCHAR; //TCP 8位标志位
windowsize:USHORT; //16位窗口大小
checksum:USHORT; //16位校验和
urgent_pointer:USHORT; //16位紧急指针
// op_pad:UINT; //选项目,可选,注意,通常TCP头部长度为20,如果如此
//op_pad是不需要的
end;
////////////////////////////////////////////////////////

class function TWinPCap.checksum(buffer:PUSHORT;size:Integer):USHORT;
var
cksum:ULONG;
begin
cksum :=0;
while size>1 do
begin
Inc(cksum,buffer^);
Inc(buffer);
Dec(size,sizeof(USHORT));
end;
if Boolean(size) then
Inc(cksum,PByte(buffer)^);
cksum:=(cksum shr 16)+(cksum and $FFFF);
cksum:=(cksum shr 16)+cksum;
result:=USHORT(not cksum);
end;
////////////////////////////////////////////////////////////////////

procedure TMainForm.ToolButton3Click(Sender: TObject);
var
tsd:tsd_hdr;
tcp:tcp_header;
a:array [0..3] of byte;
b:array [0..300] of byte;
p:PByte;
begin
a[0] :=192;a[1] :=168;a[2] := 1;a[3] :=8;
CopyMemory(@tsd.saddr,@a,4);
a[0] :=220;a[1] :=194;a[2] :=57;a[3] :=88;
CopyMemory(@tsd.daddr,@a,4);
tsd.mbz :=0;
tsd.ptcl :=IPPROTO_TCP;
tsd.tcpl :=htons(sizeof(tcp_Header));
tcp.sport :=1125;
tcp.dport :=80;
tcp.seq_number :=662445656;
tcp.ack_number :=2772731560;
tcp.res_thl :=$50;
tcp.flags_fo :=$10;
tcp.windowsize :=65535;//$FF
tcp.checksum :=0;
tcp.urgent_pointer :=0;
p :=@b;
// ZeroMemory(p,sizeof(b));
CopyMemory(p,@tsd,sizeof(tsd));
Inc(p,sizeof(tsd));
CopyMemory(p,@tcp,sizeof(tcp));
tcp.checksum :=TWinPCap.checksum(PUSHORT(p),sizeof(tsd)+sizeof(tcp));
Caption :=inttohex(tcp.checksum,8);
end;
////////////////////////////////
得到的tcp.checksum是0x6735,但正确结果是0x6193,以上数据是是监视软件给的数据,照抄而已,但checksum结

果不对,哪位高手知道??
 
即:计算TCP头部的Checksum值,如下:


tsd_hdr=packed record //定义TCP伪首部
saddr:ULONG; //源地址
daddr:ULONG; //目的地址
mbz:byte;
ptcl:byte; //协议类型
tcpl:USHORT; //TCP头部长度
end;
///////////////////////////////////////////
tcp_header= packed record
sport:USHORT; // 源端口号
dport:USHORT; // 目标端口号
seq_number:DWORD; //32位序号
ack_number:DWORD; //32位确认号
res_thl:UCHAR; //TCP头长度(4Bits;其值X4),保留值(4Bits)
flags_fo:UCHAR; //TCP 8位标志位
windowsize:USHORT; //16位窗口大小
checksum:USHORT; //16位校验和
urgent_pointer:USHORT; //16位紧急指针
// op_pad:UINT; //选项目,可选,注意,通常TCP头部长度为20,如果如此
//op_pad是不需要的
end;
////////////////////////////////////////////////////////

class function TWinPCap.checksum(buffer:PUSHORT;size:Integer):USHORT;
var
cksum:ULONG;
begin
cksum :=0;
while size>1 do
begin
Inc(cksum,buffer^);
Inc(buffer);
Dec(size,sizeof(USHORT));
end;
if Boolean(size) then
Inc(cksum,PByte(buffer)^);
cksum:=(cksum shr 16)+(cksum and $FFFF);
cksum:=(cksum shr 16)+cksum;
result:=USHORT(not cksum);
end;
////////////////////////////////////////////////////////////////////

procedure TMainForm.ToolButton3Click(Sender: TObject);
var
tsd:tsd_hdr;
tcp:tcp_header;
a:array [0..3] of byte;
b:array [0..300] of byte;
p:PByte;
begin
a[0] :=192;a[1] :=168;a[2] := 1;a[3] :=8;
CopyMemory(@tsd.saddr,@a,4);
a[0] :=220;a[1] :=194;a[2] :=57;a[3] :=88;
CopyMemory(@tsd.daddr,@a,4);
tsd.mbz :=0;
tsd.ptcl :=IPPROTO_TCP;
tsd.tcpl :=htons(sizeof(tcp_Header));
tcp.sport :=1125;
tcp.dport :=80;
tcp.seq_number :=662445656;
tcp.ack_number :=2772731560;
tcp.res_thl :=$50;
tcp.flags_fo :=$10;
tcp.windowsize :=65535;//$FF
tcp.checksum :=0;
tcp.urgent_pointer :=0;
p :=@b;
// ZeroMemory(p,sizeof(b));
CopyMemory(p,@tsd,sizeof(tsd));
Inc(p,sizeof(tsd));
CopyMemory(p,@tcp,sizeof(tcp));
tcp.checksum :=TWinPCap.checksum(PUSHORT(p),sizeof(tsd)+sizeof(tcp));
Caption :=inttohex(tcp.checksum,8);
end;
////////////////////////////////
得到的tcp.checksum是0x6735,但正确结果是0x6193,以上数据是是监视软件给的数据,照抄而已,但checksum结

果不对,哪位高手知道??
 
非常奇怪,当b的长度变化时,checksum返回值会变.
 
Long i ,全部该加的,加起来,最后 Mod 0x10000 ,ok
 
能不能给一份源码给我?谢谢

goodhelp@qq.com
 
我也发现有相同问题
 
TCP发送SYN及隐藏发送方IP
很郁闷,没有成功。用VC6可以了发送成功。
现在把代码发上来大家研究一下。

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, WinSock2, ComCtrls;

type
ip_header = record // IP 头
h_verlen : Byte; //4位首部长度,4位IP版本号
tos : Byte; //8位服务类型TOS
total_len : Word; //16位总长度(字节)
ident : Word; //16位标识
frag_and_flags : Word; //3位标志位 (如SYN,ACK,等)
ttl : Byte; //8位生存时间 TTL
proto : Byte; //8位协议 (如ICMP,TCP等)
checksum : Word; //16位IP首部校验和
sourceIP : LongWord; //32位源IP地址
destIP : LongWord; //32位目的IP地址
end;

tcp_header = record //定义TCP首部
th_sport: Word ; //16位源端口
th_dport: Word ; //16位目的端口
th_seq:dword; //32位序列号
th_ack:dword; //32位确认号
th_lenres: Byte ; //4位首部长度/6位保留字
th_flag: Byte ; //6位标志位
th_win: Word ; //16位窗口大小
th_sum: Word ; //16位校验和
th_urp: Word ; //16位紧急数据偏移量
end;

tsd_header = record//定义TCP伪首部
saddr: LongWord; //源地址
daddr: LongWord; //目的地址
mbz: Byte;
ptcl: Byte; //协议类型
tcpl: Word; //TCP长度
end;

type
TForm1 = class(TForm)
StatusBar1: TStatusBar;
procedure FormCreate(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
private
{ Private declarations }
FSock : TSocket;
Remote : TSockAddr; //目标地址
ipHeader:ip_header;
tcpHeader:tcp_header;
psdHeader:tsd_header;
szSendBuf:array[0..63]of char;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}
const IP_HDRINCL = 2; // IP Header Include
g_destIP='61.233.65.154';
g_desPort=2200;
FAKE_IP ='10.168.150.1'; //伪装IP的起始值,本程序的伪装IP覆盖一个B类网段

function CheckSum(Var Buffer; Size : integer) : Word;
type
TWordArray = Array[0..1] of Word;
var
ChkSum : LongWord;
i : Integer;
begin
ChkSum := 0;
i := 0;
While Size > 1 do
begin
ChkSum := ChkSum + TWordArray(Buffer);
inc(i);
Size := Size - SizeOf(Word);
end;
if Size=1 then ChkSum := ChkSum + Byte(TWordArray(Buffer));
ChkSum := (ChkSum shr 16) + (ChkSum and $FFFF);
ChkSum := ChkSum + (Chksum shr 16);
Result := Word(ChkSum);
end;


procedure TForm1.FormCreate(Sender: TObject);
var wsa : TWSAData;
flag,nTimeOver,FakeIpNet,FakeIpHost,dwToIP: integer;
iIPVersion,iIPSize, iTotalSize,SourcePort,sleeptime:integer;
begin
WSAStartup(MAKEWORD(2,1), wsa );
FSock:=WSASocket(AF_INET,SOCK_RAW, IPPROTO_TCP,nil,0,WSA_FLAG_OVERLAPPED);
if (Fsock=INVALID_SOCKET) then
begin
StatusBar1.Panels[1].Text :='Socket Setup Error!' ;
exit;
end
else
StatusBar1.Panels[1].Text :='Socket Setup OK';
flag:=1;
if (setsockopt(Fsock,IPPROTO_IP, IP_HDRINCL,@flag,sizeof(flag))=SOCKET_ERROR) then
begin
StatusBar1.Panels[1].Text :='setsockopt IP_HDRINCL error!' ;
exit;
end;
nTimeOver:=1000;
if (setsockopt(Fsock, SOL_SOCKET, SO_SNDTIMEO, @nTimeOver, sizeof(nTimeOver))=SOCKET_ERROR) then //设置发送的时间
begin
StatusBar1.Panels[1].Text :='setsockopt SO_SNDTIMEO error!' ;
exit;
end;
sleeptime:=300;
FakeIpNet:=inet_addr(FAKE_IP);
FakeIpHost:=ntohl(FakeIpNet);
dwToIP:=inet_addr(g_destIP);

Remote.sin_family:=AF_INET;
Remote.sin_port:=htons(g_desPort);
Remote.sin_addr.S_addr:=FakeIpHost;
// 初始化 IP 头
iIPVersion := 4;
iIPSize := sizeof(ipHeader) div sizeof(LongWord);
iTotalSize:=sizeof(ipHeader) + sizeof(tcpHeader);

ipHeader.h_verlen := (iIPVersion shl 4) or iIPSize;
ipHeader.tos := 0; // IP type of service
ipHeader.total_len := htons(iTotalSize); // Total packet len
ipHeader.ident:= 1; //
ipHeader.frag_and_flags := 0; //无分片
ipHeader.ttl := 128; // Time to live
ipHeader.proto := IPPROTO_TCP; // 协议类型为 TCP
ipHeader.checksum := 0 ; // //效验位先初始为0
ipHeader.sourceIP:=FakeIpNet; //随机产生一个伪造的IP
ipHeader.destIP :=dwToIP; //目标IP

SourcePort:=Random(60000)+1000; //随机产生一个端口号
tcpHeader.th_dport:=Remote.sin_port; //发送的目的端口
tcpHeader.th_sport:=htons(SourcePort); //源端口号
tcpHeader.th_seq:=htonl($12345678); //SYN序列号
tcpHeader.th_ack:=0; //ACK序列号置为0
tcpHeader.th_lenres:=(sizeof(tcpHeader)div 4)shl 4; //TCP长度和保留位
tcpHeader.th_flag:=2; //为SYN请求
tcpHeader.th_win:=htons(512);
tcpHeader.th_urp:=0;
tcpHeader.th_sum:=0;

//填充TCP伪首部用来计算TCP头部的效验和
psdHeader.saddr:=ipHeader.sourceIP;
psdHeader.daddr:=ipHeader.destIP;
psdHeader.mbz:=0;
psdHeader.ptcl:=IPPROTO_TCP;
psdHeader.tcpl:=htons(sizeof(tcpHeader));
//计算校验和
fillchar(szSendBuf,sizeof(szSendBuf),0);
move(psdHeader,szSendBuf[0], sizeof(psdHeader));
move(tcpHeader,szSendBuf[sizeof(psdHeader)], sizeof(tcpHeader));
tcpHeader.th_sum:=checksum(szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader));
//把伪造好的IP头 和 TCP 头 放进 buf 准备发送
fillchar(szSendBuf,sizeof(szSendBuf),0);
move(ipHeader,szSendBuf[0], sizeof(ipHeader));
move(tcpHeader,szSendBuf[sizeof(ipHeader)], sizeof(tcpHeader));
//ipHeader.checksum:=checksum(szSendBuf,sizeof(ipHeader)+sizeof(tcpHeader));
//move(ipHeader,szSendBuf[0], sizeof(ipHeader));
//发送数据包
Remote.sin_family:=AF_INET;
Remote.sin_port:=htons(g_desPort);
Remote.sin_addr.S_addr:=dwToIP;

if sendto(Fsock, szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader), 0, Remote, sizeof(Remote))=SOCKET_ERROR then
begin
StatusBar1.Panels[1].Text :=format('send error!:%d',[WSAGetLastError()]);
end
else begin
StatusBar1.Panels[1].Text :='send OK!';
end;
closesocket(Fsock);
Fsock:=0;
end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if Fsock<>0 then
closesocket(Fsock);
WSACleanup();
end;

end.
 
所有的结构定义换成这样的
ip_header = record =》ip_header =Packed record
 
将:
CopyMemory(p,@tsd,sizeof(tsd));
Inc(p,sizeof(tsd));
CopyMemory(p,@tcp,sizeof(tcp));
改为
CopyMemory(p,@tsd,sizeof(tsd));
CopyMemory(Ptr(Integer(p)+sizeof(tsd)),@tcp,sizeof(tcp));
就可以了,不知为何?
 
后退
顶部