原来在Windows 2000下的SYN攻击很简单:
FillChar( LocalAdr, sizeof(LocalAdr), 0 );
LocalAdr.sin_family := AF_INET;
LocalAdr.sin_port := htons( LOCAL_PORT );
LocalAdr.sin_addr.S_addr := inet_addr('192.168.1.12'); //换成你的IP
FillChar( RemotAdr, sizeof(RemotAdr), 0 );
RemotAdr.sin_family := AF_INET;
RemotAdr.sin_port := htons( REMOT_PORT );
RemotAdr.sin_addr.S_addr := inet_addr( PChar(Edit1.Text) );
//
//创建一个接收数据用的socket
//
RecvSock := socket( AF_INET, SOCK_RAW, IPPROTO_IP );//Can not be -> IPPROTO_RAW
//bind是必须的,否则无法SIO_RCVALL
bind( RecvSock, @LocalAdr, sizeof(LocalAdr) );
//SIO_RCVALL -> 使用此参数的套接字必须同一个明确的本地接口bind,并且,
// 套接字地址家族必须是AF_INET. 类型必须是SOCK_RAW. 协议必须是IPPROTO_IP
arg := 1;
if ioctlsocket( RecvSock, SIO_RCVALL, arg ) = SOCKET_ERROR then
begin
ErrMsg( 'ioctlsocket() failed with error ' + IntToStr(WSAGetLastError) );
exit;
end;
if WSAAsyncSelect( RecvSock, handle, WM_SOCKet,FD_READ )=SOCKET_ERROR then
begin
ErrMsg( 'WSAAsyncSelect() failed with error ' + IntToStr(WSAGetLastError) );
exit;
end;
//
//创建一个发送数据用的socket
//
SendSock := socket( AF_INET, SOCK_RAW, IPPROTO_IP );//Also can be -> IPPROTO_RAW
//在Windows NT4、Windows 98中,SOCK_RAW时,只能使用IPPROTO_IGMP和IPPROTO_ICMP
//在Windows 2000中,SOCK_RAW时,可以使用IPPROTO_UDP、IPPROTO_IP以及IPPROTO_RAW
// 但是必须使用套接字选项IP_HDRINCL!!!
arg := 1;
if setsockopt( sendsock, IPPROTO_IP, IP_HDRINCL, @arg, sizeof(arg) )= SOCKET_ERROR then
begin
ErrMsg( 'setsockopt() failed with error ' + IntToStr(WSAGetLastError) );
exit;
end;
//socket创建好了,分配内存
cbData := 0;
pIPHdr := AllocMem( sizeof(YIPHeader) + sizeof(YTCPHeader) + cbData );
pTCPHdr := PTCPHeader( PChar(pIPHdr) + sizeof(YIPHeader) );
pData := PChar(pTCPHdr) + sizeof(YTCPHeader);
//开始SYN->ACK
dwSeq := RAW_INIT_SEQ;
dwAck := 0;
dwFlg := 2; //00000010 SYN=1 用来发起一个连接
FillIPHeader( pIPHdr, IPPROTO_TCP, cbData, 11111, RemotAdr.sin_addr.S_addr,
LocalAdr.sin_addr.S_addr );
FillTCPHeader( pTCPHdr, cbData, RemotAdr.sin_port, LocalAdr.sin_port,
dwSeq, dwAck, dwFlg, RemotAdr.sin_addr.S_addr, LocalAdr.sin_addr.S_addr );
if sendto( SendSock, pIPHdr^, sizeof(YIPHeader) + sizeof(YTCPHeader) + cbData,
0, RemotAdr, sizeof(RemotAdr) ) = SOCKET_ERROR then
begin
ErrMsg( 'sendto() failed with error ' + IntToStr(WSAGetLastError) );
exit;
end;
if recv( RecvSock, RecvBuf[0], MAX_PACKET_SIZE, 0 )= SOCKET_ERROR then
begin
errmsg( 'Call recv() failed with error '+IntToStr(WSAGetLastError) );
exit;
end;
DecodeTCPReply( @RecvBuf[0], DestSeq, DestAck );
dwSeq := DestAck;
dwAck := DestSeq+1;
dwFlg := 16; //00010000 ACK=1
FillIPHeader( pIPHdr, IPPROTO_TCP, cbData, 11111, RemotAdr.sin_addr.S_addr,
LocalAdr.sin_addr.S_addr );
FillTCPHeader( pTCPHdr, cbData, RemotAdr.sin_port, LocalAdr.sin_port,
dwSeq, dwAck, dwFlg, RemotAdr.sin_addr.S_addr, LocalAdr.sin_addr.S_addr );
if sendto( SendSock, pIPHdr^, sizeof(YIPHeader) + sizeof(YTCPHeader) + cbData,
0, RemotAdr, sizeof(RemotAdr) ) = SOCKET_ERROR then
begin
ErrMsg( 'sendto() failed with error ' + IntToStr(WSAGetLastError) );
exit;
end;
呵呵,以上是TCP三次握手的代码,应该没有什么问题吧?
但是在XP SP1下,根本接收不到服务器返回的任何数据~~~~~~~用IRIS监视一下,原来XP接收到服务器的ACK报文以后竟然自动发送了一个RST报文~~~~~~我倒~~~
附上几个函数:
//填充IP Header
procedure FillIPHeader( pip: PIPHeader; pro: U8; datalen,id,destip,fromip: U32 );
var
extln : u8;
begin
case pro of
IPPROTO_TCP : extln := sizeof(YTCPHeader);
IPPROTO_UDP : extln := sizeof(YUDPHeader);
else
extln := sizeof(YIPHeader);//IPPROTO_IP
end;
pip^.u8verlen := ( 4 shl 4 ) or (sizeof(YIPHeader) div sizeof(u32));
pip^.u8tos := 0;
pip^.u16totallen := htons( u16(sizeof(YIPHeader) + extln + datalen) );
pip^.u16id := htons( u16(id) );
pip^.u16offset := htons(1 shl 14);//do not fragment
pip^.u8ttl := 128;
pip^.u8protol := pro;
pip^.u16checksum := 0;
pip^.u32srcaddr := fromip;
pip^.u32destaddr := destip;
pip^.u16checksum := CheckSum( PU16(pip), sizeof(YIPHeader) );
end;
//填充UDP Header
procedure FillUDPHeader( pudp: PUDPHeader; datalen: u32; destport, fromport: U32 );
begin
pudp^.u16fromport := fromport;
pudp^.u16destport := destport;
pudp^.u16totlen := htons( sizeof(YUDPHeader) + datalen );
pudp^.u16chksum := 0;
end;
//
// 填充TCP Header,ptcp是指向TCP header的指针,要发送的数据应该在TCP header后
// 即:piphdr := allocmem( sizeof(IPHeader)+sizeof(TCPHeader)+datasize );
// ptcphdr := PByte(piphdr) + sizeof(IPHeader);
// pdata := PByte(ptcphdr) + sizeof(TCPHeader);
//
procedure FillTCPHeader( ptcp: PTCPHeader; datalen, destport, fromport, seq,
ack, flag, destip, fromip: U32 );
var
buf : TByteArray;
psd : YPSDHeader;
begin
ptcp^.u16fromport := fromport;
ptcp^.u16destport := destport;
ptcp^.u32seq := htonl( seq );
ptcp^.u32ack := htonl( ack );
ptcp^.u8hdrlen := ( (sizeof(YTCPHeader) div sizeof(u32)) shl 4 ) or 0;
ptcp^.u8flag := u8( flag );
ptcp^.u16wndsize := htons( RAW_WND_SIZE );
ptcp^.u16chksum := 0;
ptcp^.u16urgptr := 0;
psd.u32fromaddr := fromip;
psd.u32destaddr := destip;
psd.u8mbz := 0;
psd.u8ptcl := IPPROTO_TCP;
psd.u16length := htons( sizeof(YTCPHeader) + datalen );
Move( psd, buf[0], sizeof(psd) );
Move( ptcp^, buf[sizeof(psd)], sizeof(YTCPHeader) + datalen );
ptcp^.u16chksum := CheckSum( PU16(@buf[0]),
sizeof(psd) + sizeof(YTCPHeader) + datalen );
end;
function DecodeTCPReply( pbuf: PChar; var DestSeq, DestAck: u32 ):bool;
var
pIpHdr : PChar;
pTcphdr : PTCPHeader;
begin
pIpHdr := pbuf;
Inc( pIpHdr, (PIPHeader(pIpHdr)^.u8verlen and $0F) * 4 );
pTcpHdr := PTCPHeader(pIpHdr);
result := true;
DestSeq := ntohl(ptcphdr^.u32seq);
DestAck := ntohl(ptcphdr^.u32ack);
end;