网络编程-Windows平台下的抓包技术.ppt
虽然Unix平台上的BSD包截获系统提供了一组供应用程序直接调用的网络数据包截获函数,允许应用程序与网卡间直接进行交互,但在Win32平台上,目前主要使用WinPcap体系结构。WinPcap是基于Win32平台的网络包截获和分析的系统,它具有丰富的网络数据包处理函数,其功能比BSD包截获系统更强,如“包监视”和“包发送”等功能函数在早先的Unix平台上是不具备的。WinPcap是一个重要的抓包工具,它是libpcap的Windows版本Windows平台下的抓包技术WinPcap包括三个部分第一个模块:内核级的包过滤驱动程序内核级的包过滤驱动程序 NPF(Netgroup Packet Filter),是一个虚拟设备驱动程序文件,是架构的核心(在Win95/98中是一个VXD文件,在NT/2000中是一个SYS文件),它的主要功能是过滤数据包,在包上附加时间戳、数据包长度等信息。第二个模块:低级动态链接库低级动态链接库packet.dll,在Win32平台上提供了与NPF的一个通用接口。packet.dll数据包驱动程序库是与libpcap 相兼容的一组用户级的函数库。第三个模块:用户级的用户级的Wpcap.dll。通过调用packet.dll提供的函数生成,它包括了过滤器生成等一系列可以被用户级调用的高级函数,另外还有诸如数据包统计及发送功能。WinPcapWinPcap体系结构NPFPacket.dllPacket.dllPacket.dllPacket.dll相关的数据结构相关的数据结构typedef struct _ADAPTER*LPADAPTERtypedef struct _ADAPTER*LPADAPTER描述一个网络适配器。它包含了两个域:HANDLE hFile TCHAR SymbolicLinkhFile是一个指向驱动器句柄的指针。通过该句柄,我们可以直接与驱动器进行通信,如接收或发送数据包。SymbolicLink是一个字符串,它包含了当前打开的网络适配器的名称。Packet.dllPacket.dll相关的数据结构相关的数据结构typedef struct _PACKET*LPPACKETtypedef struct _PACKET*LPPACKET 描述一组网络数据包的结构。它包含了以下几个域:OVERLAPPED OverLapped PVOID Buffer UINT Length PVOID ulBytesReceived BOOLEAN bIoComplete OverLapped是用来处理对驱动器的异步调用。Buffer是用来指向缓存的指针,该缓存包含了数据包的数据。Length是该缓存区的大小。而ulBytesReceived表明了该缓存中包含的有效数据的大小。BIoComplete是在异步调用中用来表示该Packet是否包含有效的数据。Packet.dllPacket.dll相关的数据结构相关的数据结构struct bpf_hdrstruct bpf_hdr 数据报头部。它包含以下几个域:struct timeval bh_tstampUNIT bh_caplenUNIT bh_datalenUSHORT bh_hdrlen bh_tstamp是一个时间戳,它包含两个域:tv_sec和tv_usec,用来表示报文的捕获时间。bh_caplen是封装报文后的报文长度。bh_datalen是原始报文长度。bh_hdrlen是封装报文的报头长度。Packet.dllPacket.dll相关的数据结构相关的数据结构 typedef struct NetType NetType typedef struct NetType NetType 描述网络类型的数据结构。typedef struct npf_if_addr npf_if_addrtypedef struct npf_if_addr npf_if_addr 描述一个网络适配器的ip地址。Struct bpf_stat Struct bpf_stat 当前捕获数据报的统计信息Packet.dll相关函数 1LPPACKET PacketAllocatePacket(void)如果运行成功,返回一个_PACKET结构的指针,否则返回NULL。成功返回的结果将会传送到PacketReceivePacket()函数,接收来自驱动的网络数据报。2 VOID PacketFreePacket(LPPACKET lpPacket)释放参数提供的_PACKET结构。3VOID PacketCloseAdapter(LPADAPTER lpAdapter)关闭参数中提供的网络适配器,释放相关的ADAPTER结构。Packet.dll相关函数4BOOLEAN PacketGetAdapterNames(LPSTR pStr,PULONG BufferSize)返回可以得到的网络适配器列表及描述。5BOOLEAN PacketGetNetInfoEx(LPTSTR AdapterNames,npf_ip_addr*buff,PLONG NEntries)返回某个网络适配器的全面地址信息。其中npf_ip_addr结构包含:IPAddress:ip地址SubnetMask:子网掩码Broadcast:广播地址 Packet.dll相关函数6BOOLEAN PacketGetNetType(LPADAPTER AdapterObject,NetType*type)返回某个网络适配器的MAC类型。NetType结构里包含了LinkSpeed(速度)和LinkType(类型)。其中LinkType包含以下几种情况:NdisMedium802_3:Ethernet(802.3)NdisMediumWan:WANNdisMedium802_5:Token Ring(802.5)NdisMediumFddi:FDDINdisMediumAtm:ATMNdisMediumArcnet878_2:ARCNET(878.2)Packet.dll相关函数7BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat*s)返回几个关于当前捕获报告的统计信息。其中bpf_stat结构包含:bs_recv,bs_drop,ps_ifdrop,bs_captbs_recv:从网络适配器开始捕获数据报开始所接收到的所有数据报的数目,包括丢失的数据报;bs_drop:丢失的数据报数目。8PCHAR PacketGetVersion()返回关于dll的版本信息。Packet.dll相关函数9VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length)初始化一个_PACKET结构。10 LPADAPTER PacketOpenAdapter(LPTSTR AdapterName)打开一个网络适配器。11 BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync)从NPF驱动程序读取网络数据报及统计信息。数据报编码结构:|bpf_hdr|data|Padding|bpf_hdr|data|Padding|Packet.dll相关函数12 BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync)发送一个或多个数据报的副本。13 BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim)设置捕获数据报的内核级缓冲区大小。Packet.dll相关函数14 BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter)为接收到的数据报设置硬件过滤规则。以下为一些典型的过滤规则:NDIS_PACKET_TYPE_PROMISCUOUS:设置为混杂模式,接收所有流过的数据报;NDIS_PACKET_TYPE_DIRECTED:只有目的地为本地主机网络适配器的数据报才会被接收;NDIS_PACKET_TYPE_BROADCAST:只有广播数据报才会被接收;NDIS_PACKET_TYPE_MULTICAST:只有与本地主机网络适配器相对应的多播数据报才会被接收;NDIS_PACKET_TYPE_ALL_MULTICAST:所有多播数据报均被接收;NDIS_PACKET_TYPE_ALL_LOCAL:所有本地数据报均被接收。Packet.dll相关函数15 BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites)设置调用PacketSendPacket()函数发送一个数据报副本的最大重发次数。16 BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout)设置读操作等待时间。以上介绍的包含了packet.dll里的大部分函数。如果想更深层的了解winpcap,请访问相关网站,主页地址:http:/winpcap.polito.itPacket.dll监听流程图PacketGetAdapterName()选择网卡选择网卡PacketOpenAdapter()打开网络适配器打开网络适配器PacketSetHwFilter()设置接收模式(一般设置为混杂模式)设置接收模式(一般设置为混杂模式)PacketSetBpf()编辑设置过滤规则编辑设置过滤规则PacketSetBuff()设置核心缓冲区大小设置核心缓冲区大小PacketSetReadTimeout()设置读操作等待时间设置读操作等待时间PacketAllocatePacket()设置(分配)用户缓冲区设置(分配)用户缓冲区PacketInitPacket()初始化用户缓冲区初始化用户缓冲区PacketReceivePacket()捕获网络数据包捕获网络数据包Packet.dll应用步骤基本程序代码如下:if(!(dwVersion =0X80000000&dwWindowsMajorVersion =4)/Windows NTAdapterLength=sizeof(AdapterName);(1)得到网卡名称if(PacketGetAdapterNames(PTSTR)AdapterName,&AdapterLength)=FALSE)return FALSE;Packet.dll应用步骤2)打开指定的网卡lpAdapter=PacketOpenAdapter(AdapterList 0);if(!lpAdapter|(lpAdapter-hFile=INVALID_HANDLE_VALUE)dwErrorCode=GetLastError();sprintf(szErr,Unable to open the adapter,error code:%lx,dwErrorCode);AfxMessageBox(szErr);return FALSE;Packet.dll应用步骤3)设置过滤器,将网卡设置为混杂模式,这样可以监听流过本机的数据包if(PacketSetHwFilter(lpAdapter,NDIS_PACKET_TYPE_PROMISCUOUS)=FALSE)return FALSE;4)设置缓冲区大小if(PacketSetBuff(lpAdapter,512000)=FALSE)return FALSE;5)设置接收一个数据包的超时时间PacketSetReadTimeout(lpAdapter,1000)/set a 1 second read timeout Packet.dll应用步骤6)为Packet 结构分配内存if(lpPacket=PacketAllocatePacket()=NULL)return false;7)初始化一个Packet 结构,即将Packet 结构中的buffer 设置为传递的buffer 指针.PacketInitPacket(lpPacket,(char 3)buffer,256000)Packet.dll应用步骤8)从NPF driver 上读取网络数据包.while(!bStop)if(PacketReceivePacket(lpAdapter,lpPacket,TRUE)=FALSE)return FALSE;/显示捕获数据9)释放参数提供的Packet 结构.PacketFreePacket(lpPacket)10)关闭网卡.PacketCloseAdapter(lpAdapter)wpcap.dll库函数介绍 wpcap.dll为包捕获应用提供了一个高级的编程接口,它是从Libpcap发展而来并且相互兼容,所以wpcap.dll包含了Libpcap具有的函数。另外,由于它还增加了数据包发送和统计等功能,为此增加了以下的函数:pcap_setbuff:该函数用于设置包驱动器缓冲区的大小,一个适合大小的缓冲区不仅可以减少丢包率,还可以提供包捕获能力。pcap_setmode:该函数把网络适配器设置为统计方式。pcap_stats:这个函数用于获取包捕获过程的统计数据。Wpcap为了要与硬件接口,还直接调用了packet.dll提供的函数。wpcap.dll的相关数据结构 接口地址:struct pcap_addr struct pcap_addr*next;/*指到链表的下一个结点*/struct sockaddr*addr;/*指到sockaddr类型的结构*/struct sockaddr*netmask;/*指到addr相应的掩码*/struct sockaddr*broadaddr;/*addr相应的广播地址*/struct sockaddr*dstaddr;/*与addr对应的目标地址,如非点到点,则为NULL*/;wpcap.dll的相关数据结构libpcap dump文件的头结构:struct pcap_file_header bpf_u_int32 magic;/*/u_short version_major;/*主版本号*/u_short version_minor;/*次版本号*/bpf_int32 thiszone;/*本地时间*/bpf_u_int32 sigfigs;/*时间戳*/bpf_u_int32 snaplen;/*保存一个包中多大的数据*/bpf_u_int32 linktype;/*数据链路类型*/;wpcap.dll的相关数据结构接口数据结构:struct pcap_if struct pcap_if*next;/*本链下一个结点*/char*name;/*设备名称*/char*description;/*描述*/struct pcap_addr*addresses;u_int flags;/*如是一个回路接口,则设成PCAP_IF_LOOPBACK*/;wpcap.dll的相关数据结构dump file中包的头结构:struct pcap_pkthdr struct timeval ts;/*时间戳*/bpf_u_int32 caplen;/*长度*/bpf_u_int32 len;/*捕获包的长度*/;wpcap.dll的相关数据结构统计数据结构:struct pcap_stat u_int ps_recv;/*网上已传送的包数*/u_int ps_drop;/*丢弃的包数*/u_int ps_ifdrop;/*接口拒绝的包数,暂不支持*/#ifdef WIN32 u_int bs_capt;/*Win32专用,捕获的包数*/#endif/*WIN32*/;wpcap.dll主要函数(1)Int pcap_findalldevs(pcap_if_t*alldevsp,char*errbuf)功能:返回本机所有的网络接口设备。输入参数:两个参数全为空值返回:失败:返回-1,errbuf中包含错误信息。成功:alldevsp中包含全部网络接口设备。当用户无法了解自己机器的接口设备时在程序的首部调用该函数。(2)Char*pcat_lookupdev(char*errbuf)该函数用于返回可被pcap_open_live()或pcap_lookupnet()函数调用的网络设备名(一个字符串指针)。如果函数出错,则返回NULL,同时errbuf中存放相关的错误消息。wpcap.dll主要函数(3)int pcap_lookupnet(char*device,bpf_u_int32*netp,bpf_u_int32*maskp,char*errbuf)获得指定网络设备的IP地址和掩码。netp参数和maskp参数都是bpf_u_int32指针。如果函数出错,则返回-1,同时errbuf中存放相关的错误消息。(4)Pcap_dumper_t*pcap_dump_open(pcap_t*p,char*filename)打开一个保存数据包的文件,其文件格式是固定的,和tcpdump等文件格式相兼容。wpcap.dll主要函数(5)Pcap_t*pcap_open_live(char*DeviceName,int snaplen,int promisc,int to_ms,char*errbuf)功能:打开一个捕获接口设备。输入参数:DeviceName:设备名;snaplen:一个包中截取的字节数;promisc:1杂凑模式,0正常模式;to_ms:时延(毫称);errbuf:错误信息返回:失败:返回非正数,errbuf中包含错误信息。成功:捕获句柄。wpcap.dll主要函数(6)intpcap_compile(pcap_t*p,struct bpf_program*fp,char*str,int optimize,bpf_u_int32 netmask)功能:编译过滤规则输入参数:Str规则串;optimize是否优化;返回:失败:返回-1。成功:捕获句柄wpcap.dll主要函数(7)int pcap_setfilter(pcap_t*p,struct bpf_program*fp)功能:设置过滤器规则输入参数:fp为指到结构体 bpf_program 的指针,pcap_compile()函数的返回值。返回:失败:返回-1。wpcap.dll主要函数(8)int pcap_dispatch(pcap_t*p,int cnt,pcap_handler callback,u_char*user)捕获并处理数据包。cnt参数指定函数返回前所处理数据包的最大值。cnt=-1表示在一个缓冲区中处理所有的数据包。cnt=0表示处理所有数据包,直到产生以下错误之一:读取到EOF;超时读取。callback参数指定一个带有三个参数的回调函数,这三个参数为:typedef void(*pcap_handler)(u_char*agrs,const struct pcap_pkthdr*header,const u_char*packet);其中agrs是从pcap_dispatch()函数传递过来的第四个形参,一般我们自己的包捕捉程序不需要提供它,总是为NULL;header指向pcap_pkthdr结构,该结构位于真正的物理帧前面,用于消除不同链路层支持的差异;packet指向所捕获报文的物理帧。参数user 为用户传递给回调函数的指针。如果成功则返回读取到的字节数。读取到EOF时则返回零值。出错时则返回-1,此时可调用pcap_perror()或pcap_geterr()函数获取错误消息。wpcap.dll主要函数(9)Int pcap_loop(pcap_t*p,int cnt,pcap_handler callback,u_char*user)功能:循环抓取网络数据报文。每捕获到cnt个报文就调用callback用户函数。输入参数:P句柄,cnt每一次抓包数,callback用户自定义的处理函数,user一般为null。注:该函数功能基本与pcap_dispatch()函数相同,只不过此函数在cnt个数据包被处理或出现错误时才返回,但读取超时不会返回。而如果为pcap_open_live()函数指定了一个非零值的超时设置,然后调用pcap_dispatch()函数,则当超时发生时pcap_dispatch()函数会返回。cnt参数为负值时pcap_loop()函数将始终循环运行,除非出现错误wpcap.dll主要函数(10)pcap_read()这个函数从包捕获驱动器中读取一组数据包并针对每一个包运行包过滤程序,然后把过滤后的数据送应用程序缓冲器u_char*pcap_next(pcap_t*p,struct pcap_pkthdr*h)返回指向下一个数据包的u_char指针。(11)void pcap_close(pcap_t*p)功能:关闭库。输入参数:P句柄。(12)Int pcap_setbuff(pcap_t*p,int dim)用来设置核心层的缓冲区。(13)Int pcap_setmode(pcap_t*p,int mode)用来设置网卡的工作模式:混杂/非混杂。(14)pcap_stats():这个函数用于获取包捕获过程的统计数据。(15)Int pcap_sendpacket(pcap_t*p,char*buf,int size)用来发送数据包。(16)FILE*pcap_file(pcap_t*p)返回被打开文件的文件名。(17)int pcap_fileno(pcap_t*p)返回被打开文件的文件描述字号码wpcap.dll捕获数据包的调用流程 Pcap_close:关闭库Pcap_lookupdev:返回设备类型Pcap_open_live/pcap_open_offline:打开设备或文件准备记取数据Pcap_compile:编译过滤规则Pcap_setfilter:设备过滤规则Pcap_loop:循环抓取网络数据报文wpcap.dll捕获数据包的调用流程首先调用pcap_lookupdev(char*errbuf)函数获得主机上的网络设备,该函数返回一个指向主机上的网络设备(如网卡)的指针;然后调用pcap_open_live(char*device,int snaplen,int promisc,int to_ms,char*ebuf)函数打开一个网络设备,该函数返回一个包捕获描述符pcap_t。其中,device 是要打开的网络设备字符串,snaplen 设定捕获的包的最大长度,promisc 确定接口是否被设为promiscuous(混杂)模式。在网络监视仪系统中,此参数设为promiscuous模式,以捕捉本地网络上的所有包。To_ms 设定读超时的毫秒数,ebuf 用来返回错误文本。wpcap.dll捕获数据包的调用流程然后调用intpcap_compile(pcap_t*p,struct bpf_program*fp,char*str,int optimize,bpf_u_int32 netmask)来编译过滤规则,用int pcap_setfilter(pcap_t*p,struct bpf_program*fp)来设置过滤器规则。接下来用pcap_loop(pcap_t*p,int cnt,pcap_handler callback,u_char*user)或pcap_next(pcap_t*p,struct pcap_pkthdr*h)函数捕获网络上所有的数据包给应用程序作分析用。最后用void pcap_close(pcap_t*p)来关闭库。发送数据包发送数据包 Winpcap中有发送单个包和发送多个包的方法。其中发送单个包的大致过程如下:通过名字打开一个设备pcap_open;自己构造一个原始数据包(原始数据包为链路帧,这个数据包会不经过任何处理就发送出去);使用pcap_sendpacket()发送数据包。统计网络流量统计网络流量 通过名字打开一个设备pcap_open通过 read_timeout来设置统计的时间间隔设置filterpcap_compile,pcap_setfilter(可选)设置设备的为统计模式 pcap_setmode(MODE_STAT);开始统计,pcap_loop/pcap_dispatch()在回调函数中的参数中就包含了统计信息wpcap.dll应用实例 下面程序给出利用wpcap.dll接口对网络数据包进行监听的简单实例。#include#include int main()pcap_t*handle;/*监听会话句柄*/char*dev;/*监听网络接口*/char errbufIPCAP_ERRBUF_SIZE;/*错误代码*/struct bpf_program filter;/*编译后过滤器表达式*/char filter_app=”port 23”;/*指定过滤条件*/bpf_u_int32 mask;/*网络接口掩码*/bpf_u_int32 net;/*网络接口地址*/*自动选择网络接口*/dev=pcap_lookupdev(errbuf);/*获取指定网络设备的网络地址和掩码*/wpcap.dll应用实例 pcap_lookupnet(dev,&net,&mask,errbuf);/*建立监听会话*/handle=pcap_open_live(dev,BUFSIZ,1,0,errbuf);/*编辑过滤器*/pcap_compile(handle,&filter,filter_app,0,net);/*设置过滤器*/pcap_setfilter(handle,&filter);/*循环捕获并处理合乎过滤要求的包,直到错误发生*/pcap_loop(handle,-1,diapatcher_handler,(const u_char*)handle);/*关闭监听会话*/pcap_close(handle);return(0);wpcap.dll应用实例/*对捕获的每一个数据包调用该回调函数对数据包进行处理*/void dispatcher_handler(u_char*uhandle,const pcap_pkthdr*pkthdr,const u_char*pkt)/*协议分析的代码*/