《Windows 2000下的Raw Socket编程.rtf》由会员分享,可在线阅读,更多相关《Windows 2000下的Raw Socket编程.rtf(7页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、Windows 2000下的Raw Socket编程Windows 2000下的Raw Socket编程创建时间:2002-02-01文章属性:原创文章提交:refdom(refdom_at_)作者:refdom()2002/1/31 Windows2000在TCP/IP协议组件上做了很多改进,功能也有增强。比如在协议栈上的调整,增大了默认窗口大小,以及高延迟链接新算法。同时在安全性上,可应用IPSec加强安全性,比NT下有不少的改进。Microsoft TCP/IP 组件包含“核心协议”、“服务”及两者之间的“接口”。传输驱动程序接口(TDI)与网络设备接口规范(NDIS)是公用的。此外,还
2、有许多用户模型应用程序的更高级接口。最常用的接口是 Windows Sockets、远程过程调用(RPC)和 NetBIOS。Windows Sockets 是一个编程接口,它是在加州大学伯克利分校开发的套接字接口的基础上定义的。它包括了一组扩展件,以充分利用 Microsoft Windows 消息驱动的特点。规范的 1.1 版是在 1993 年 1 月发行的,2.2.0 版在 1996 年 5 月发行。Windows 2000 支持 Winsock 2.2 版。在Winsock2中,支持多个传输协议的原始套接字,重叠I/O模型、服务质量控制等。这里介绍Windows Sockets的一些关
3、于原始套接字(Raw Socket)的编程。同Winsock1相比,最明显的就是支持了Raw Socket套接字类型,通过原始套接字,我们可以更加自如地控制Windows下的多种协议,而且能够对网络底层的传输机制进行控制。1、创建一个原始套接字,并设置IP头选项。SOCKET sock;sock=socket(AF_INET,SOCK_RAW,IPPROTO_IP);或者:s=WSASoccket(AF_INET,SOCK_RAW,IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);这里,我们设置了SOCK_RAW标志,表示我们声明的是一个原始套接字类型。创建原始套接
4、字后,IP头就会包含在接收的数据中,如果我们设定 IP_HDRINCL 选项,那么,就需要自己来构造IP头。注意,如果设置IP_HDRINCL 选项,那么必须具有 administrator权限,要不就必须修改注册表:HKEY_LOCAL_MACHINESystemCurrentControlSetServicesAfdParameter 修改键:DisableRawSecurity(类型为DWORD),把值修改为 1。如果没有,就添加。BOOL blnFlag=TRUE;setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char*)&blnFlag,sizeof(
5、blnFlag);对于原始套接字在接收数据报的时候,要注意这么几点:1、如果接收的数据报中协议类型和定义的原始套接字匹配,那么,接收的所有数据就拷贝到套接字中。2、如果绑定了本地地址,那么只有接收数据IP头中对应的远端地址匹配,接收的数据就拷贝到套接字中。3、如果定义的是外部地址,比如使用connect(),那么,只有接收数据IP头中对应的源地址匹配,接收的数据就拷贝到套接字中。2、构造IP头和TCP头 这里,提供IP头和TCP头的结构:/Standard TCP flags#define URG 0 x20#define ACK 0 x10#define PSH 0 x08#define R
6、ST 0 x04#define SYN 0 x02#define FIN 0 x01 typedef struct _iphdr/定义IP首部 unsigned char h_lenver;/4位首部长度+4位IP版本号 unsigned char tos;/8位服务类型TOS unsigned short total_len;/16位总长度(字节)unsigned short ident;/16位标识 unsigned short frag_and_flags;/3位标志位 unsigned char ttl;/8位生存时间 TTL unsigned char proto;/8位协议(TCP
7、,UDP 或其他)unsigned short checksum;/16位IP首部校验和 unsigned int sourceIP;/32位源IP地址 unsigned int destIP;/32位目的IP地址 IP_HEADER;typedef struct psd_hdr/定义TCP伪首部 unsigned long saddr;/源地址 unsigned long daddr;/目的地址 char mbz;char ptcl;/协议类型 unsigned short tcpl;/TCP长度 PSD_HEADER;typedef struct _tcphdr/定义TCP首部 USHOR
8、T th_sport;/16位源端口 USHORT th_dport;/16位目的端口 unsigned int th_seq;/32位序列号 unsigned int th_ack;/32位确认号 unsigned char th_lenres;/4位首部长度/6位保留字 unsigned char th_flag;/6位标志位 USHORT th_win;/16位窗口大小 USHORT th_sum;/16位校验和 USHORT th_urp;/16位紧急数据偏移量 TCP_HEADER;TCP伪首部并不是真正存在的,只是用于计算检验和。校验和函数:USHORT checksum(USHO
9、RT*buffer,int size)unsigned long cksum=0;while(size 1)cksum+=*buffer+;size-=sizeof(USHORT);if(size)cksum+=*(UCHAR*)buffer;cksum=(cksum 16)+(cksum&0 xffff);cksum+=(cksum 16);return(USHORT)(cksum);当需要自己填充IP头部和TCP头部的时候,就同时需要自己计算他们的检验和。3、发送原始套接字数据报 填充这些头部稍微麻烦点,发送就相对简单多了。只需要使用sendto()就OK。sendto(sock,(cha
10、r*)&tcpHeader,sizeof(tcpHeader),0,(sockaddr*)&addr_in,sizeof(addr_in);下面是一个示例程序,可以作为SYN扫描的一部分。#include#include#include#define SOURCE_PORT 7234#define MAX_RECEIVEBYTE 255 typedef struct ip_hdr/定义IP首部 unsigned char h_verlen;/4位首部长度,4位IP版本号 unsigned char tos;/8位服务类型TOS unsigned short total_len;/16位总长度(
11、字节)unsigned short ident;/16位标识 unsigned short frag_and_flags;/3位标志位 unsigned char ttl;/8位生存时间 TTL unsigned char proto;/8位协议(TCP,UDP 或其他)unsigned short checksum;/16位IP首部校验和 unsigned int sourceIP;/32位源IP地址 unsigned int destIP;/32位目的IP地址 IPHEADER;typedef struct tsd_hdr/定义TCP伪首部 unsigned long saddr;/源地址
12、 unsigned long daddr;/目的地址 char mbz;char ptcl;/协议类型 unsigned short tcpl;/TCP长度 PSDHEADER;typedef struct tcp_hdr/定义TCP首部 USHORT th_sport;/16位源端口 USHORT th_dport;/16位目的端口 unsigned int th_seq;/32位序列号 unsigned int th_ack;/32位确认号 unsigned char th_lenres;/4位首部长度/6位保留字 unsigned char th_flag;/6位标志位 USHORT t
13、h_win;/16位窗口大小 USHORT th_sum;/16位校验和 USHORT th_urp;/16位紧急数据偏移量 TCPHEADER;/CheckSum:计算校验和的子函数 USHORT checksum(USHORT*buffer,int size)unsigned long cksum=0;while(size 1)cksum+=*buffer+;size-=sizeof(USHORT);if(size)cksum+=*(UCHAR*)buffer;cksum=(cksum 16)+(cksum&0 xffff);cksum+=(cksum 16);return(USHORT)
14、(cksum);void useage()printf(*n);printf(TCPPingn);printf(t Written by Refdomn);printf(t Email:n);printf(Useage:TCPPing.exe Target_ip Target_port n);printf(*n);int main(int argc,char*argv)WSADATA WSAData;SOCKET sock;SOCKADDR_IN addr_in;IPHEADER ipHeader;TCPHEADER tcpHeader;PSDHEADER psdHeader;char szS
15、endBuf60=0;BOOL flag;int rect,nTimeOver;useage();if(argc!=3)return false;if(WSAStartup(MAKEWORD(2,2),&WSAData)!=0)printf(WSAStartup Error!n);return false;if(sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED)=INVALID_SOCKET)printf(Socket Setup Error!n);return false;flag=true;if(s
16、etsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char*)&flag,sizeof(flag)=SOCKET_ERROR)printf(setsockopt IP_HDRINCL error!n);return false;nTimeOver=1000;if(setsockopt(sock,SOL_SOCKET,SO_SNDTIMEO,(char*)&nTimeOver,sizeof(nTimeOver)=SOCKET_ERROR)printf(setsockopt SO_SNDTIMEO error!n);return false;addr_in.sin_fam
17、ily=AF_INET;addr_in.sin_port=htons(atoi(argv2);addr_in.sin_addr.S_un.S_addr=inet_addr(argv1);/填充IP首部 ipHeader.h_verlen=(44|sizeof(ipHeader)/sizeof(unsigned long);/ipHeader.tos=0;ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(tcpHeader);ipHeader.ident=1;ipHeader.frag_and_flags=0;ipHeader.ttl=128;ip
18、Header.proto=IPPROTO_TCP;ipHeader.checksum=0;ipHeader.sourceIP=inet_addr(本地地址);ipHeader.destIP=inet_addr(argv1);/填充TCP首部 tcpHeader.th_dport=htons(atoi(argv2);tcpHeader.th_sport=htons(SOURCE_PORT);/源端口号 tcpHeader.th_seq=htonl(0 x12345678);tcpHeader.th_ack=0;tcpHeader.th_lenres=(sizeof(tcpHeader)/44|0
19、);tcpHeader.th_flag=2;/修改这里来实现不同的标志位探测,2是SYN,1是FIN,16是ACK探测 等等 tcpHeader.th_win=htons(512);tcpHeader.th_urp=0;tcpHeader.th_sum=0;psdHeader.saddr=ipHeader.sourceIP;psdHeader.daddr=ipHeader.destIP;psdHeader.mbz=0;psdHeader.ptcl=IPPROTO_TCP;psdHeader.tcpl=htons(sizeof(tcpHeader);/计算校验和 memcpy(szSendBuf
20、,&psdHeader,sizeof(psdHeader);memcpy(szSendBuf+sizeof(psdHeader),&tcpHeader,sizeof(tcpHeader);tcpHeader.th_sum=checksum(USHORT*)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader);memcpy(szSendBuf,&ipHeader,sizeof(ipHeader);memcpy(szSendBuf+sizeof(ipHeader),&tcpHeader,sizeof(tcpHeader);memset(szSendBuf+si
21、zeof(ipHeader)+sizeof(tcpHeader),0,4);ipHeader.checksum=checksum(USHORT*)szSendBuf,sizeof(ipHeader)+sizeof(tcpHeader);memcpy(szSendBuf,&ipHeader,sizeof(ipHeader);rect=sendto(sock,szSendBuf,sizeof(ipHeader)+sizeof(tcpHeader),0,(struct sockaddr*)&addr_in,sizeof(addr_in);if(rect=SOCKET_ERROR)printf(sen
22、d error!:%dn,WSAGetLastError();return false;else printf(send ok!n);closesocket(sock);WSACleanup();return 0;4、接收数据 和发送原始套接字数据相比,接收就比较麻烦了。因为在WIN我们不能用recv()来接收raw socket上的数据,这是因为,所有的IP包都是先递交给系统核心,然后再传输到用户程序,当发送一个raws socket包的时候(比如syn),核心并不知道,也没有这个数据被发送或者连接建立的记录,因此,当远端主机回应的时候,系统核心就把这些包都全部丢掉,从而到不了应用程序上。所
23、以,就不能简单地使用接收函数来接收这些数据报。要达到接收数据的目的,就必须采用嗅探,接收所有通过的数据包,然后进行筛选,留下符合我们需要的。可以再定义一个原始套接字,用来完成接收数据的任务,需要设置SIO_RCVALL,表示接收所有的数据。SOCKET sniffersock;sniffsock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);DWORD lpvBuffer=1;DWORD lpcbBytesReturned=0;WSAIoctl(sniffersock,SIO_RCVALL,&lpvBuffer,sizeof(lpvBuffer),NULL,0,&lpcbBytesReturned,NULL,NULL);创建一个用于接收数据的原始套接字,我们可以用接收函数来接收数据包了。然后在使用一个过滤函数达到筛选的目的,接收我们需要的数据包。在 http:/ 提供了一个完整的发送和接收的程序,可以参考。-reference:1、MS Windows 2000 TCP-IP Implementation Details 2、zissRaw Sockets in Windows 2000/XP 3、MSDN Platform SDK:Windows Sockets 2
限制150内