新闻资讯
看你所看,想你所想

winpcap

winpcap

winpcap

winpcap(windows packet capture)是windows平台下一个免费,公共的网路访问系统。开发winpcap这个项目的目的在于为win32应用程式提供访问网路底层的能力。它用于windows系统下的直接的网路编程。

基本介绍

  • 中文名:winpcap
  • 外文名:windows packet capture
  • 使用平台:windows
  • 目的:为win32提供访问网路底层能力
  • 作用:网路分析,故障排除等方面

特点

Winpcap提供了一个强大的编程接口,它很容易地在各个作业系统之间进行移植,也很方便程式设计师进行开发。
什幺样的程式需要使用Winpcap
很多不同的工具软体使用Winpcap于网路分析,故障排除,网路安全监控等方面。Winpcap特别适用于下面这几个经典领域:
1、网路及协定分析
2、网路监控
3、通信日誌记录
4、traffic generators
5、用户级别的桥路和路由
6、网路入侵检测系统(NIDS)
7、网路扫描
8、安全工具
Winpcap有些方面不能做。它不依靠主机的诸如TCP/IP协定去收发数据包。这意味着它不能阻塞,不能处理同一台主机中各程式之间的通信数据。它只能“嗅探”到物理线路上的数据包。因此它不适用于traffic shapers,QoS调度,以及个人防火墙。
Winpcap内部结构
Winpcap是一个Win32平台下用于抓包和分析的系统。包括一个核心级别的packet filter,一个底层的DLL(packet.dll)和一个高级的独立于系统的DLL(Wpcap.dll)

驱动功能

  1. 捕获原始数据包,包括在共享网路上各主机传送/接收的以及相互之间交换的数据包;
  2. 在数据包发往应用程式之前,按照自定义的规则将某些特殊的数据包过滤掉;
  3. 在网路上传送原始的数据包;
  4. 收集网路通信过程中的统计信息。
winpcap的主要功能在于独立于主机协定(如TCP-IP)而传送和接收原始数据包。也就是说,winpcap不能阻塞,过滤或控制其他应用程式数据包的发收,它仅仅只是监听共享网路上传送的数据包。因此,它不能用于QoS调度程式或个人防火墙。winpcap开发的主要对象是windows NT/2000/XP,这主要是因为在使用winpcap的用户中只有一小部分是仅使用windows 95/98/Me,并且MS也已经放弃了对win9x的开发。因此本文相关的程式T-ARP也是面向NT/2000/XP用户的。其实winpcap中的面向9x系统的概念和NT系统的非常相似,只是在某些实现上有点差异,比如说9x只支持ANSI编码,而NT系统则提倡使用Unicode编码。有个软体叫snifferpro.可以作网管软体用,有很多功能,可监视网路运行情况,每台网内机器的数据流量,实时反映每台机器所访问IP以及它们之间的数据流通情况,可以抓包,可对过滤器进行设定,以便只抓取想要的包,比如POP3包,smtp包,ftp包等,并可从中找到信箱用户名和密码,还有ftp用户名和密码。它还可以在使用交换机的网路上监听,不过要在交换机上装它的一个软体。还有一个简单的监听软体叫Passwordsniffer,可截获信箱用户名和密码,还有ftp用户名和密码,它只能用在HUB网路上。着名软体tcpdump及idssnort都是基于libpcap编写的,此外Nmap扫描器也是基于libpcap来捕获目标主机返回的数据包的。
winpcap结构winpcap结构
winpcap提供给用户两个不同级别的编程接口:一个基于libpcap的wpcap.dll,另一个是较底层的packet.dll。对于一般的要与unix平台上libpcap兼容的开发来说,使用wpcap.dll是当然的选择。

内部结构

Winpcap是针对Win32平台上的抓包和网路分析的一个架构。它包括一个核心态的包过滤器,一个底层的动态程式库(packet.dll)和一个高层的不依赖于系统的库(wpcap.dll)。
Winpcap的各个组成部分Winpcap的各个组成部分
为什幺使用“architecture”而不是“library”呢?因为抓包是一个要求与网路适配器(网卡)和作业系统互动的底层机制,而且与网路的实施也有密切关係,所以仅用“library”不能充分表达Winpcap的作用。
下图表明了Winpcap的各个组成部分:
首先,抓包系统必须绕过作业系统的协定栈来访问在网路上传输的原始数据包(raw packet),这就要求一部分运行在作业系统核心内部,直接与网路接口驱动互动。这个部分是系统依赖(system dependent)的,在Winpcap的解决方案里它被认为是一个设备驱动,称作NPF(Netgroup Packet Filter)。Winpcap开发小组针对Windows95,Windows98,WindowsME,Windows NT 4,Windows2000和WindowsXP提供了不同版本的驱动。这些驱动不仅提供了基本的特性(例如抓包和injection),还有更高级的特性(例如可程式的过滤器系统和监视引擎)。前者可以被用来约束一个抓包会话只针对网路通信中的一个子集(例如,仅仅捕获特殊主机产生的ftp通信的数据包),后者提供了一个强大而简单的统计网路通信量的机制(例如,获得网路负载或两个主机间的数据交换量)。
其次,抓包系统必须有用户级的程式接口,通过这些接口,用户程式可以利用核心驱动提供的高级特性。Winpcap提供了两个不同的库:packet.dll和wpcap.dll。前者提供了一个底层API,伴随着一个独立于Microsoft作业系统的编程接口,这些API可以直接用来访问驱动的函式;后者导出了一组更强大的与libpcap一致的高层抓包函式馆(capture primitives)。这些函式使得数据包的捕获以一种与网路硬体和作业系统无关的方式进行。

NPF驱动

网路数据包过滤器(Netgroup Packet Filter,NPF)是Winpcap的核心部分,它是Winpcap完成困难工作的组件。它处理网路上传输的数据包,并且对用户级提供可捕获(capture)、传送(injection)和分析性能(analysis capabilities)。

NPF和NDIS

NDIS(Network Driver Interface Specification)是一个定义网路适配器(或者说成是管理网路适配器的驱动程式)与协定驱动(例如TCP/IP的实现)之间通信的规範。NDIS最主要的目的是作为一个允许协定驱动传送和接收网路(LAN或WAN)上的数据包而不必关心特定的适配器或特定的Win32作业系统的封装。
NDIS支持三种类型的网路驱动:
(1)网路接口卡NIC驱动(Network interface card or NIC drivers)。NIC驱动直接管理着网路接口卡(NIC)。NIC驱动接下边与硬体连线,从上边表现为一个接口,该接口允许高层传送数据包到网路上,处理中断,重置NIC,停止NIC,查询和设定驱动的运行特徵。NIC驱动可以是小连线埠(miniport)或完全的NIC驱动(full NIC driver)。
Miniport驱动仅仅实现了管理NIC的必要操作,包括在NIC上传送和接收数据。对于所有最底层的NIC驱动的操作由NDIS提供,例如同步(synchronization)。小连线埠(miniport)不直接调用作业系统函式,它们对于作业系统的接口是NDIS。
小连线埠仅仅是向上传递数据包给NDIS并且NDIS确保这些数据包被传递给正确的协定。
完全NIC驱动(Full NIC driver)完成硬体细节的操作和所有由NDIS完成的同步和查询操作。例如,完全NIC驱动维持接收到的数据的绑定信息。
(2) 中间层驱动(Intermediate drivers)中间层驱动位于高层驱动(例如协定驱动)和小连线埠之间。对于高层驱动,中间层驱动看起来像是小连线埠;对于小连线埠,中间层驱动看起来像协定驱动。一个中间层协定驱动可以位于另一个中间层驱动之上,儘管这种分层可能对系统性能带来负面影响。开发中间层驱动的一个关键原因是在现存的遗留协定驱动(legacy protocol driver)和小连线埠之间形成媒体的转化。例如,中间层驱动可以将LAN协定转换成ATM协定。中间层驱动不能与用户模式的应用程式通信,但可以与其他的NDIS驱动通信。
(3) 传输驱动或协定驱动(Transport drivers or protocol drivers)协定驱动实现了网路协定栈,例如IPX/SPX或TCP/IP,在一个或多个网路接口卡上提供它的服务。在协定驱动的上面,它为套用层客户程式服务;在它的下面,它与一个或多个NIC驱动或中间层NDIS驱动连线。
NPF是一个协定驱动。从性能方面来看,这不是最好的选择,但是它合理地独立于MAC层并且有权使用原始通信(raw traffic)。
NPF在NDIS栈中的位置NPF在NDIS栈中的位置
下图表现了NPF在NDIS栈中的位置:

NPF结构基础

下图表现了伴随着NPF驱动细节的Winpcap的结构。
伴随着NPF驱动细节的Winpcap的结构伴随着NPF驱动细节的Winpcap的结构

抓包

抓包是NPF最重要的操作。在抓包的时候,驱动使用一个网路接口监视着数据包,并将这些数据包完整无缺地投递给用户级应用程式。
抓包过程依赖于两个主要组件:
一个数据包过滤器,它决定着是否接收进来的数据包并把数据包拷贝给监听程式。数据包过滤器是一个有布尔输出的函式。如果函式值是true,抓包驱动拷贝数据包给应用程式;如果是false,数据包将被丢弃。NPF数据包过滤器更複杂一些,因为它不仅决定数据包是否应该被保存,而且还得决定要保存的位元组数。被NPF驱动採用的过滤系统来源于BSD Packet Filter(BPF),一个虚拟处理器可以执行伪彙编书写的用户级过滤程式。应用程式採用用户定义的过滤器并使用wpcap.dll将它们编译进BPF程式。然后,应用程式使用BIOCSETF IOCTL写入核心态的过滤器。这样,对于每一个到来的数据包该程式都将被执行,而满足条件的数据包将被接收。与传统解决方案不同,NPF不解释(interpret)过滤器,而是执行(execute)它。由于性能的原因,在使用过滤器前,NPF提供一个JIT编译器将它转化成本地的80x86函式。当一个数据包被捕获,NPF调用这个本地函式而不是调用过滤器解释器,这使得处理过程相当快。
一个循环缓冲区,用来保存数据包并且避免丢失。一个保存在缓冲区中的数据包有一个头,它包含了一些主要的信息,例如时间戳和数据包的大小,但它不是协定头。此外,以伫列插入的方式来保存数据包可以提高数据的存储效率。可以以组的方式将数据包从NPF缓冲区拷贝到应用程式。这样就提高了性能,因为它降低了读的次数。如果一个数据包到来的时候缓冲区已经满了,那幺该数据包将被丢弃,因此就发生了丢包。

实例

获得网卡接口。在普通的SOCKET编程中,对双网卡编程是不行的。当主机为双网卡时,本程式可分别获得两张网卡各自的描述结构及地址,然后可以对它们分别进行操作。返回的alldevs伫列首部为逻辑网卡,一般不对它进行什幺操作。

获得网卡接口

#include "pcap.h"void main(){    pcap_if_t *alldevs;    /*struct pcap_if_t{    pcap_if_t *next;    char *name;    char *description;    pcap_addr *addresses;    U_int falgs;    }    */    pcap_if_t *d;    int i=0;    char errbuf[PCAP_ERRBUF_SIZE];    /* Retrieve the device list */    if (pcap_findalldevs(&alldevs, errbuf) == -1)//返回网卡列表,alldevs指向表头    {        fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);        exit(1);    }    /* Print the list */    for(d=alldevs;d;d=d->next)    {        printf("%d. %s", ++i, d->name);        if (d->description)        printf(" (%s)\n", d->description);        else printf(" (No description available)\n");    }    if(i==0)    {        printf("\nNo interfaces found! Make sure WinPcap is installed.\n");        return;    }    /* We don't need any more the device list. Free it */    pcap_freealldevs(alldevs);}
--------------------------------------------------------------------------------

抓包

本程式俘获区域网路内UDP报文。
#include "pcap.h"/* 4 bytes IP address */typedef struct ip_address{u_char byte1;u_char byte2;u_char byte3;u_char byte4;}ip_address;/* IPv4 header */typedef struct ip_header{u_char ver_ihl; // Version (4 bits) + Internet header length (4 bits)u_char tos; // Type of serviceu_short tlen; // Total lengthu_short identification; // Identificationu_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits)u_char ttl; // Time to liveu_char proto; // Protocolu_short crc; // Header checksumip_address saddr; // Source addressip_address daddr; // Destination addressu_int op_pad; // Option + Padding}ip_header;/* UDP header*/typedef struct udp_header{u_short sport; // Source portu_short dport; // Destination portu_short len; // Datagram lengthu_short crc; // Checksum}udp_header;/* prototype of the packet handler */void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);main(){pcap_if_t *alldevs;pcap_if_t *d;int inum;int i=0;pcap_t *adhandle;char errbuf[PCAP_ERRBUF_SIZE];u_int netmask;char packet_filter[] = "ip and udp";struct bpf_program fcode;/* Retrieve the device list */if (pcap_findalldevs(&alldevs, errbuf) == -1){fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);exit(1);}/* Print the list */for(d=alldevs; d; d=d->next){printf("%d. %s", ++i, d->name);if (d->description)printf(" (%s)\n", d->description);elseprintf(" (No description available)\n");}if(i==0){printf("\nNo interfaces found! Make sure WinPcap is installed.\n");return -1;}printf("Enter the interface number (1-%d):",i);scanf("%d", &inum);if(inum < 1 || inum > i){printf("\nInterface number out of range.\n");/* Free the device list */pcap_freealldevs(alldevs);return -1;}/* Jump to the selected adapter */for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);/* Open the adapter */if ( (adhandle= pcap_open_live(d->name, // name of the device65536, // portion of the packet to capture.// 65536 grants that the whole packet will be captured on all the MACs.1, // promiscuous mode1000, // read timeouterrbuf // error buffer) ) == NULL){fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n");/* Free the device list */pcap_freealldevs(alldevs);return -1;}/* Check the link layer. We support only Ethernet for simplicity. */if(pcap_datalink(adhandle) != DLT_EN10MB){fprintf(stderr,"\nThis program works only on Ethernet networks.\n");/* Free the device list */pcap_freealldevs(alldevs);return -1;}if(d->addresses != NULL)/* Retrieve the mask of the first address of the interface */netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;else/* If the interface is without addresses we suppose to be in a C class network */netmask=0xffffff;//compile the filterif(pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 ){fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");/* Free the device list */pcap_freealldevs(alldevs);return -1;}//set the filterif(pcap_setfilter(adhandle, &fcode)<0){fprintf(stderr,"\nError setting the filter.\n");/* Free the device list */pcap_freealldevs(alldevs);return -1;}printf("\nlistening on %s...\n", d->description);/* At this point, we don't need any more the device list. Free it */pcap_freealldevs(alldevs);/* start the capture */pcap_loop(adhandle, 0, packet_handler, NULL);return 0;}/* Callback function invoked bylibpcapfor every incoming packet */void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data){struct tm *ltime;char timestr[16];ip_header *ih;udp_header *uh;u_int ip_len;/* convert the timestamp to readable format */ltime=localtime(&header->v_sec);strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);/* print timestamp and length of the packet *//* retireve the position of the ip header */ih = (ip_header *) (pkt_data +; //length of ethernet header/* retireve the position of the udp header */ip_len = (ih->ver_ihl & 0xf) * 4;uh = (udp_header *) ((u_char*)ih + ip_len);/* convert from network byte order to host byte order */printf("%s.%.6d len:%d ", timestr, header->_usec, header->len);/* print ip addresses */printf("%d.%d.%d.%d -> %d.%d.%d.%d\n",ih->saddr.byte1,ih->saddr.byte2,ih->saddr.byte3,ih->saddr.byte4,ih->daddr.byte1,ih->daddr.byte2,ih->daddr.byte3,ih->daddr.byte4);}
--------------------------------------------------------------------------------

发包

要在命令行下运行,给与参数:网卡描述符。或者添加代码findalldevs(),那样应很方便。
#include <stdlib.h>#include <stdio.h>#include "pcap.h"void usage();void main(int argc, char **argv) {pcap_t *fp;char error[PCAP_ERRBUF_SIZE];u_char packet[100];int i;/* Check the validity of the command line */if (argc != 2){printf("usage: %s inerface", argv[0]);return;}/* Open the output adapter */if((fp =pcap_open_live(argv[1], 100, 1, 1000, error) ) == NULL){fprintf(stderr,"\nError opening adapter: %s\n", error);return;}/* Supposing to be on ethernet, set mac destination to 1:1:1:1:1:1 */packet[0]=1;packet[1]=1;packet[2]=1;packet[3]=1;packet[4]=1;packet[5]=1;/* set mac source to 2:2:2:2:2:2 */packet[6]=2;packet[7]=2;packet[8]=2;packet[9]=2;packet[10]=2;packet[11]=2;/* Fill the rest of the packet */for(i=12;i<100;i++){packet=i%256;}/* Send down the packet */pcap_sendpacket(fp,packet,;return;}

卸载问题

winpcap卸载不乾净的解决方法
winpcap卸载不乾净的的时候,在windows下删除一些档案即可,删除下面的档案即可:
c:\windows\system32\Packet.dll
c:\windows\system32\drivers/npf.sys
c:\windows\system32\WanPacket.dll
c:\windows\system32\wpcap.dll
c:\windows\system32\pthreadVC.dll

转载请注明出处海之美文 » winpcap

相关推荐

    声明:此文信息来源于网络,登载此文只为提供信息参考,并不用于任何商业目的。如有侵权,请及时联系我们:ailianmeng11@163.com