編輯本段winpcap 驅動各項功能
1> 捕獲原始數據包,包括在共享網絡上各主機發送/接收的以及相互之間交換的數據
winpcap結構
包; 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編碼。有個軟件叫
sniffer pro.可以作網管軟件用,有很多功能,可監視網絡運行情況,每臺網內機器的數據流量,實時反映每臺機器所訪問IP以及它們之間的數據流通情況,可以抓包,可對過濾器進行設置,以便只抓取想要的包,比如
POP3包,
smtp包,ftp包等,並可從中找到郵箱用戶名和密碼,還有
ftp用戶名和密碼。它還可以在使用交換機的網絡上監聽,不過要在交換機上裝它的一個軟件。還有一個簡單的監聽軟件叫Passwordsniffer,可截獲郵箱用戶名和密碼,還有ftp用戶名和密碼,它只能用在HUB網絡上。著名軟件
tcpdump及
ids snort都是基於
libpcap編寫的,此外
Nmap掃描器也是基於libpcap來捕獲目標主機返回的數據包的。
winpcap提供給用戶兩個不同級別的編程接口:一個基於libpcap的wpcap.dll,另一個是較底層的packet.dll。對於一般的要與unix平臺上libpcap兼容的開發來說,使用wpcap.dll是當然的選擇。
編輯本段Winpcap的內部結構
Winpcap的各個組成部分
Winpcap是針對Win32平臺上的抓包和
網絡分析的一個架構。它包括一個核心態的包過濾器,一個底層的動態鏈接庫(packet.dll)和一個高層的不依賴於系統的庫(wpcap.dll)。 爲什麼使用“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在NDIS棧中的位置
NPF是一個協議驅動。從性能方面來看,這不是最好的選擇,但是它合理地獨立於MAC層並且有權使用原始通信(raw traffic)。 下圖表現了NPF在NDIS棧中的位置:
伴隨着NPF驅動細節的Winpcap的結構
〖NPF結構基礎〗 下圖表現了伴隨着NPF驅動細節的
Winpcap的結構。
〖抓包〗 抓包是NPF最重要的操作。在抓包的時候,驅動使用一個網絡接口監視着數據包,並將這些數據包完整無缺地投遞給用戶級應用程序。 抓包過程依賴於兩個主要組件: 一個數據包
過濾器,它決定着是否接收進來的數據包並把數據包
拷貝給監聽程序。數據包過濾器是一個有
布爾輸出的函數。如果
函數值是true,
抓包驅動拷貝數據包給應用程序;如果是false,數據包將被丟棄。NPF數據包過濾器更復雜一些,因爲它不僅決定數據包是否應該被保存,而且還得決定要保存的字節數。被NPF驅動採用的過濾系統來源於BSD Packet Filter(BPF),一個虛擬處理器可以執行僞彙編書寫的用戶級過濾程序。應用程序採用用戶定義的過濾器並使用wpcap.dll將它們編譯進BPF程序。然後,應用程序使用BIOCSETF IOCTL寫入核心態的過濾器。這樣,對於每一個到來的數據包該程序都將被執行,而滿足條件的數據包將被接收。與傳統解決方案不同,NPF不解釋(interpret)過濾器,而是執行(execute)它。由於性能的原因,在使用過濾器前,NPF提供一個
JIT編譯器將它轉化成本地的80x86函數。當一個數據包被捕獲,NPF調用這個本地函數而不是調用過濾器
解釋器,這使得處理過程相當快。 一個循環緩衝區,用來保存數據包並且避免丟失。一個保存在
緩衝區中的數據包有一個頭,它包含了一些主要的信息,例如
時間戳和
數據包的大小,但它不是協議頭。此外,以隊列插入的方式來保存數據包可以提高數據的存儲效率。可以以組的方式將數據包從NPF緩衝區拷貝到應用程序。這樣就提高了性能,因爲它降低了讀的次數。如果一個數據包到來的時候緩衝區已經滿了,那麼該數據包將被丟棄,因此就發生了
丟包。
編輯本段Winpcap程序實例
獲得
網卡接口。在普通的
SOCKET編程中,對
雙網卡編程是不行的。當主機爲雙網卡時,本程序可分別獲得兩張網卡各自的描述結構及地址,然後可以對它們分別進行操作。返回的alldevs隊列首部爲邏輯網卡,一般不對它進行什麼操作。
(一)獲得網卡接口 #i nclude "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報文。 #i nclude "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 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; /* UDP 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; /* 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); 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"); /* 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 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"); /* 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 filter if(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 filter if(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 by libpcap for 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->ts.tv_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 + 14); //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->ts.tv_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(),那樣應很方便。 #i nclude <stdlib.h> #i nclude <stdio.h> #i nclude 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, 100); return; }
編輯本段winpcap卸載不乾淨的解決方法
[1][2]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