winpcap

公共的網路訪問系統

winpcap(windowspacketcapture)是windows平台下一個免費,公共的網路訪問系統。開發winpcap這個項目的目的在於為win32應用程序提供訪問網路底層的能力。它用於windows系統下的直接的網路編程。

主要功能


● ● 捕獲原始數據包,包括在共享網路上各主機發送/接收的以及相互之間交換的數據包;
● ● 在數據包發往應用程序之前,按照自定義的規則將某些特殊的數據包過濾掉;
● ● 在網路上發送原始的數據包;
● ● 收集網路通信過程中的統計信息。
winpcap
winpcap
winpcap的主要功能在於獨立於主機協議(如TCP-IP)而發送和接收原始數據包。也就是說,winpcap不能阻塞,過濾或控制其他應用程序數據包的發收,它僅僅只是監聽共享網路上傳送的數據包。因此,它不能用於QoS調度程序或個人防火牆。winpcap開發的主要對象是windowsNT/2000/XP,這主要是因為在使用winpcap的用戶中只有一小部分是僅使用windows95/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提供給用戶兩個不同級別的編程介面:一個基於libpcap的wpcap.dll,另一個是較底層的packet.dll。對於一般的要與unix平台上libpcap兼容的開發來說,使用wpcap.dll是當然的選擇。

內部結構

Winpcap是針對Win32平台上的抓包和網路分析的一個架構。它包括一個核心態的包過濾器,一個底層的動態鏈接庫(packet.dll)和一個高層的不依賴於系統的庫(wpcap.dll)。
winpcap
winpcap
為什麼使用“architecture”而不是“library”呢?因為抓包是一個要求與網路適配器(網卡)和操作系統交互的底層機制,而且與網路的實施也有密切關係,所以僅用“library”不能充分表達Winpcap的作用。
下圖表明了Winpcap的各個組成部分:
首先,抓包系統必須繞過操作系統的協議棧來訪問在網路上傳輸的原始數據包(rawpacket),這就要求一部分運行在操作系統核心內部,直接與網路介面驅動交互。這個部分是系統依賴(systemdependent)的,在Winpcap的解決方案里它被認為是一個設備驅動,稱作NPF(NetgroupPacketFilter)。Winpcap開發小組針對Windows95,Windows98,WindowsME,WindowsNT4,Windows2000和WindowsXP提供了不同版本的驅動。這些驅動不僅提供了基本的特性(例如抓包和injection),還有更高級的特性(例如可編程的過濾器系統和監視引擎)。前者可以被用來約束一個抓包會話只針對網路通信中的一個子集(例如,僅僅捕獲特殊主機產生的ftp通信的數據包),後者提供了一個強大而簡單的統計網路通信量的機制(例如,獲得網路負載或兩個主機間的數據交換量)。
其次,抓包系統必須有用戶級的程序介面,通過這些介面,用戶程序可以利用內核驅動提供的高級特性。Winpcap提供了兩個不同的庫:packet.dll和wpcap.dll。前者提供了一個底層API,伴隨著一個獨立於Microsoft操作系統的編程介面,這些API可以直接用來訪問驅動的函數;後者導出了一組更強大的與libpcap一致的高層抓包函數庫(captureprimitives)。這些函數使得數據包的捕獲以一種與網路硬體和操作系統無關的方式進行。
NPF驅動
網路數據包過濾器(NetgroupPacketFilter,NPF)是Winpcap的核心部分,它是Winpcap完成困難工作的組件。它處理網路上傳輸的數據包,並且對用戶級提供可捕獲(capture)、發送(injection)和分析性能(analysiscapabilities)。
NPF和NDIS
NDIS(NetworkDriverInterfaceSpecification)是一個定義網路適配器(或者說成是管理網路適配器的驅動程序)與協議驅動(例如TCP/IP的實現)之間通信的規範。NDIS最主要的目的是作為一個允許協議驅動發送和接收網路(LAN或WAN)上的數據包而不必關心特定的適配器或特定的Win32操作系統的封裝。
NDIS支持三種類型的網路驅動:
(1)網路介面卡或NIC驅動(NetworkinterfacecardorNICdrivers)。NIC驅動直接管理著網路介面卡(NIC)。NIC驅動接下邊與硬體連接,從上邊表現為一個介面,該介面允許高層發送數據包到網路上,處理中斷,重置NIC,停止NIC,查詢和設置驅動的運行特徵。NIC驅動可以是小埠(miniport)或完全的NIC驅動(fullNICdriver)。
Miniport驅動僅僅實現了管理NIC的必要操作,包括在NIC上發送和接收數據。對於所有最底層的NIC驅動的操作由NDIS提供,例如同步(synchronization)。小埠(miniport)不直接調用操作系統函數,它們對於操作系統的介面是NDIS。
小埠僅僅是向上傳遞數據包給NDIS並且NDIS確保這些數據包被傳遞給正確的協議。
完全NIC驅動(FullNICdriver)完成硬體細節的操作和所有由NDIS完成的同步和查詢操作。例如,完全NIC驅動維持接收到的數據的綁定信息。
(2)中間層驅動(Intermediatedrivers)中間層驅動位於高層驅動(例如協議驅動)和小埠之間。對於高層驅動,中間層驅動看起來像是小埠;對於小埠,中間層驅動看起來像協議驅動。一個中間層協議驅動可以位於另一個中間層驅動之上,儘管這種分層可能對系統性能帶來負面影響。開發中間層驅動的一個關鍵原因是在現存的遺留協議驅動(legacyprotocoldriver)和小埠之間形成媒體的轉化。例如,中間層驅動可以將LAN協議轉換成ATM協議。中間層驅動不能與用戶模式的應用程序通信,但可以與其他的NDIS驅動通信。
(3)傳輸驅動或協議驅動(Transportdriversorprotocoldrivers)協議驅動實現了網路協議棧,例如IPX/SPX或TCP/IP,在一個或多個網路介面卡上提供它的服務。在協議驅動的上面,它為應用層客戶程序服務;在它的下面,它與一個或多個NIC驅動或中間層NDIS驅動連接。
winpcap
winpcap
NPF是一個協議驅動。從性能方面來看,這不是最好的選擇,但是它合理地獨立於MAC層並且有權使用原始通信(rawtraffic)。
下圖表現了NPF在NDIS棧中的位置:
NPF結構基礎
下圖表現了伴隨著NPF驅動細節的Winpcap的結構。
抓包
抓包是NPF最重要的操作。在抓包的時候,驅動使用一個網路介面監視著數據包,並將這些數據包完整無缺地投遞給用戶級應用程序。
抓包過程依賴於兩個主要組件:
一個數據包過濾器,它決定著是否接收進來的數據包並把數據包拷貝給監聽程序。數據包過濾器是一個有布爾輸出的函數。如果函數值是true,抓包驅動拷貝數據包給應用程序;如果是false,數據包將被丟棄。NPF數據包過濾器更複雜一些,因為它不僅決定數據包是否應該被保存,而且還得決定要保存的位元組數。被NPF驅動採用的過濾系統來源於BSDPacketFilter(BPF),一個虛擬處理器可以執行偽彙編書寫的用戶級過濾程序。應用程序採用用戶定義的過濾器並使用wpcap.dll將它們編譯進BPF程序。然後,應用程序使用BIOCSETFIOCTL寫入核心態的過濾器。這樣,對於每一個到來的數據包該程序都將被執行,而滿足條件的數據包將被接收。與傳統解決方案不同,NPF不解釋(interpret)過濾器,而是執行(execute)它。由於性能的原因,在使用過濾器前,NPF提供一個JIT編譯器將它轉化成本地的80x86函數。當一個數據包被捕獲,NPF調用這個本地函數而不是調用過濾器解釋器,這使得處理過程相當快。
一個循環緩衝區,用來保存數據包並且避免丟失。一個保存在緩衝區中的數據包有一個頭,它包含了一些主要的信息,例如時間戳和數據包的大小,但它不是協議頭。此外,以隊列插入的方式來保存數據包可以提高數據的存儲效率。可以以組的方式將數據包從NPF緩衝區拷貝到應用程序。這樣就提高了性能,因為它降低了讀的次數。如果一個數據包到來的時候緩衝區已經滿了,那麼該數據包將被丟棄,因此就發生了丟包。

實例

獲得網卡介面。在普通的SOCKET編程中,對雙網卡編程是不行的。當主機為雙網卡時,本程序可分別獲得兩張網卡各自的描述結構及地址,然後可以對它們分別進行操作。返回的alldevs隊列首部為邏輯網卡,一般不對它進行什麼操作。
獲得網卡介面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "pcap.h"
void main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int i=0;
char errbuf[PCAP_ERRBUF_SIZE];
if (pcap_findalldevs(&alldevs, errbuf) == -1)//返回網卡列表,alldevs指向表頭
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
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;
}
pcap_freealldevs(alldevs);
}
抓包
本程序俘獲區域網內UDP報文。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include "pcap.h"
typedef struct ip_address{
u_char byte1;
u_char byte2;
u_char byte3;
u_char byte4;
}ip_address;
typedef struct ip_header{
u_char ver_ihl; // Version (4 bits) + Internet header length (4 bits)
u_char tos; // Type of service
u_short tlen; // Total length
u_short identification; // Identification
u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits)
u_char ttl; // Time to live
u_char proto; // Protocol
u_short crc; // Header checksum
ip_address saddr; // Source address
ip_address daddr; // Destination address
u_int op_pad; // Option + Padding
}ip_header;
typedef struct udp_header{
u_short sport; // Source port
u_short dport; // Destination port
u_short len; // Datagram length
u_short crc; // Checksum
}udp_header;
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;
if (pcap_findalldevs(&alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
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 -1;
}
printf("Enter the interface number (1-%d):",i);
scanf("%d", &inum);
if(inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");
pcap_freealldevs(alldevs);
return -1;
}
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
if ( (adhandle= pcap_open_live(d->name, // name of the device
65536, // portion of the packet to capture.
// 65536 grants that the whole packet will be captured on all the MACs.
1, // promiscuous mode
1000, // read timeout
errbuf // error buffer
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n");
pcap_freealldevs(alldevs);
return -1;
}
if(pcap_datalink(adhandle) != DLT_EN10MB)
{
fprintf(stderr,"\nThis program works only on Ethernet networks.\n");
pcap_freealldevs(alldevs);
return -1;
}
if(d->addresses != NULL)
netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
else
netmask=0xffffff;
//compile the filter
if(pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 ){
fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");
pcap_freealldevs(alldevs);
return -1;
}
//set the filter
if(pcap_setfilter(adhandle, &fcode)<0){
fprintf(stderr,"\nError setting the filter.\n");
pcap_freealldevs(alldevs);
return -1;
}
printf("\nlistening on %s...\n", d->description);
pcap_freealldevs(alldevs);
pcap_loop(adhandle, 0, packet_handler, NULL);
return 0;
}
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;
ltime=localtime(&header->v_sec);
strftime( timestr, sizeof timestr, "%H:%M:%S", ltime);
ih = (ip_header *) (pkt_data +
; //length of ethernet header
ip_len = (ih->ver_ihl & 0xf) * 4;
uh = (udp_header *) ((u_char*)ih + ip_len);
printf("%s.%.6d len:%d ", timestr, header->_usec, header->len);
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(),那樣應很方便。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include 
#include 
#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;
if (argc != 2)
{
printf("usage: %s inerface", argv[0]);
return;
}
if((fp =pcap_open_live(argv[1], 100, 1, 1000, error) ) == NULL)
{
fprintf(stderr,"\nError opening adapter: %s\n", error);
return;
}
packet[0]=1;
packet[1]=1;
packet[2]=1;
packet[3]=1;
packet[4]=1;
packet[5]=1;
packet[6]=2;
packet[7]=2;
packet[8]=2;
packet[9]=2;
packet[10]=2;
packet[11]=2;
for(i=12;i<100;i++){
packet=i%256;
}
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提供了一個強大的編程介面,它很容易地在各個操作系統之間進行移植,也很方便程序員進行開發。
什麼樣的程序需要使用Winpcap
很多不同的工具軟體使用Winpcap於網路分析,故障排除,網路安全監控等方面。Winpcap特別適用於下面這幾個經典領域:
1、網路及協議分析
2、網路監控
3、通信日誌記錄
4、trafficgenerators
5、用戶級別的橋路和路由
6、網路入侵檢測系統(NIDS)
7、網路掃描
8、安全工具
Winpcap有些方面不能做。它不依靠主機的諸如TCP/IP協議去收發數據包。這意味著它不能阻塞,不能處理同一台主機中各程序之間的通信數據。它只能“嗅探”到物理線路上的數據包。因此它不適用於trafficshapers,QoS調度,以及個人防火牆。
Winpcap內部結構
Winpcap是一個Win32平台下用於抓包和分析的系統。包括一個內核級別的packetfilter,一個底層的DLL(packet.dll)和一個高級的獨立於系統的DLL(Wpcap.dll)