[創建時間:2015-08-27 22:15:17]
經過前兩篇的瞎扯,你是不是已經厭倦了呢,那么這篇讓我們來點有意思的吧,什么,用C#。不,這篇我們先來C++的
Winpcap開發環境配置
完成了對Winpcap的介紹,什么,你沒看到Winpcap的介紹,左轉,百度(其實,真的是不想復制)。我們就需要做一點有用的事情,比如寫一個簡單的數據采集工具。當然在此之前,我們需要配置Winpcap的開發環境。
(1) 運行環境設置
Win32 平台下Winpcap應用程序需要以下四個動態鏈接庫才能正常運行:wpcap.dll Packet.dll WanPacket.dll pthreadVC.dll,這四個動態鏈接庫在WinPcap驅動程序里。如果沒有這個驅動程序,需要到WinPcap官方網站上下載,下載地址為:www.WinPcap.org。下載完后點擊安裝即可完成Winpcap核心驅動的配置,即計算機有了最初的運行基礎。
(2) 開發環境的配置
本次開發使用的組件是由Winpcap官方提供的SDK,從http://www.WinPcap.org 下載Winpcap 的SDK ——WpdPack,
也可以直接在這里下載:http://pan.baidu.com/s/1hqKtsOk
當然在此之前你的愛機一定要裝Winpcap
WinPcap SDk里面包含庫文件,頭文件,文檔文件和一些例子。解壓到一個指定的目錄。
圖1 WpdPack
其中的docs為E文,如果E實在不行 點這里http://pan.baidu.com/s/1hqHB6Pu
示例我已經在Visual Studio 2010 下成功過通過
接下來我們看看如何配置
解壓縮后把Include目錄與Lib目錄添加到開發環境中。VC6.0環境如圖2所示,
VC6.0: 菜單欄Tools->Option->Directory,在下拉列表Show directories for:中選擇Include files對話框中配置Include目錄,我將該文件放在D:\WPDPACK\INCLUDE文件夾下。同樣改變Show directories for:選中Library files配置Lib目錄。
圖2 VC6.0環境下Include目錄與Lib目錄配置
VS2010環境如圖3所示,
Visual Studio 2010: 菜單欄 工具->選項->項目和解決方案/項目->VC++目錄。有時候可能出現“目錄編輯功能被否決”的情況,可以通過 菜單欄 項目->XXX屬性->配置屬性->VC++目錄 中配置,本次使用的就是這種方式。
圖3 Visual Studio 2010環境下Include目錄與Lib目錄配置
通過上面的方式完成了文件引入部分的配置,接下來是導入庫文件的方法,在VC6.0中也叫做鏈接庫的配置。
VC6.0:菜單欄Project->Settings->Link->Object/library modules,在其中添加wpcap.lib,Packet.lib,點擊OK即可。如圖4
圖4 VC6.0環境下鏈接庫文件配置
Visual Studio 2010:右擊 解決方案資源管理器->添加->現有項…導入Packet.lib和wpacp.lib庫文件即可。如圖5
圖5 .Net中導入的庫文件
完成了庫文件的配置,現在開始本次配置的最后一步:
新的版本里WinPcap支持遠程數據包獲取,所以還應當添加一個頭文件remote-ext.h ,即#include "remote-ext.h"(記住這條語句要放在#include”pcap.h”之后,否則會出錯!)
否則會發生下面的錯誤:
error C2065: “PCAP_SRC_IF_STRING”: 未聲明的標識符
error C3861: “pcap_findalldevs_ex”: 找不到標識符
error C2065: “PCAP_OPENFLAG_PROMISCUOUS”: 未聲明的標識符
error C3861: “pcap_open”: 找不到標識符
雖然上面提供了一些解決方法,但似乎沒什么作用,於是需要在開發環境中進行配置,因為VC6.0在Windows7下兼容問題,嘗試多次未成功運行,所以此處只給出Visual Studio 2010中的配置結果
或者不用添加#include "remote-ext.h".在VC.NET提供的IDE環境中,可以通過執行“項目”菜單中的的“屬性”進入該項目的屬性配置頁,通過選擇“配置屬性”樹中的“C/C++預處理庫”選項就增加”WPCAP”和”HAVE_REMOTE”兩個標號,。如圖6所示
圖6 Visual Studio 2010環境下WPCAP與HAVE_REMOTE標號的配置
Winpcap編程實現
通過上面的配置完成了對Winpcap開發環境搭建,接下來我們就可以做一個小程序了。在做抓包程序之前,我們首先要確定從何處采集數據,大家首先想到的就是網卡,所以,第一步就是要獲取網卡:
步驟:
(a) 打開Visual Studio 2010 新建項目,語言選擇C++,類型選擇Win32控制台應用程序,點擊確定按鈕。
圖7 新建項目
(b) 進入想到頁面,直接點擊下一步,進入第二個頁面,因為我們要使用C語言來制作該程序,但是在Visual Studio 2010並沒用提供專用的C開發環境,所以上一步中我們選擇的是C++模板,因此在接下來的頁面,我們要在附加選項中選擇“空項目”,這樣開發環境就不會導入一些關於C++的東西了,點擊完成。
圖8 選擇空項目
(c) 於是開發環境為我們配置了一個空項目,在解決方案資源管理器中選擇源文件,右擊在菜單中添加選擇新建項,此時打開新建項對話框,找到C++文件,輸入文件名稱,注意,同時鍵入擴展名“.c”,這樣就可以建立一個C源文件,
圖9 配置方案結果
(d) 然后按照上面的環境配置方案,對項目中Include目錄lib目錄進行配置;導入庫文件;配置標識號;最后寫入如下代碼:
1 #include "pcap.h" 2 main() 3 { 4 pcap_if_t *alldevs; 5 pcap_if_t *d; 6 int i=0; 7 char errbuf[PCAP_ERRBUF_SIZE]; 8 9 /* 獲取本地機器設備列表 */ 10 if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL /* auth is not needed */, &alldevs, errbuf) == -1) 11 { 12 fprintf(stderr,"Error in pcap_findalldevs_ex: %s\n", errbuf); 13 exit(1); 14 } 15 /* 打印列表 */ 16 for(d= alldevs; d != NULL; d= d->next) 17 { 18 printf("%d. %s", ++i, d->name); 19 if (d->description) 20 printf(" (%s)\n", d->description); 21 else 22 printf(" (No description available)\n"); 23 } 24 25 if (i == 0) 26 { 27 printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); 28 return; 29 } 30 /* 不再需要設備列表了,釋放它 */ 31 pcap_freealldevs(alldevs); 32 }
該段代碼來自Winpcap開發文檔中的第一節,主要的任務是獲取主機網卡設備。
(e) 最后按Ctrl+F5啟動,開始編譯執行該段。
結果:如圖10
這里的編程實現僅僅是為了演示,Winpcap的開發配置過程,更多更為詳盡的實現過程請參閱Winpcap開發文檔,從Winpcap官網即可獲得,所以之后的一些實現原理並不是本書的重點,故不再贅述。
圖10 獲取網卡執行結果
如果只是,獲取到網卡,那也沒什么好講的了,下面是一段示例中的代碼,在這段代碼中我們不但可以取到網卡,還可以進行數據分析
1 #ifdef _MSC_VER 2 /* 3 * we do not want the warnings about the old deprecated and unsecure CRT functions 4 * since these examples can be compiled under *nix as well 5 */ 6 #define _CRT_SECURE_NO_WARNINGS 7 #endif 8 9 #include "pcap.h" 10 11 /* 4 bytes IP address */ 12 typedef struct ip_address 13 { 14 u_char byte1; 15 u_char byte2; 16 u_char byte3; 17 u_char byte4; 18 }ip_address; 19 20 /* IPv4 header */ 21 typedef struct ip_header 22 { 23 u_char ver_ihl; // Version (4 bits) + Internet header length (4 bits) 24 u_char tos; // Type of service 25 u_short tlen; // Total length 26 u_short identification; // Identification 27 u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits) 28 u_char ttl; // Time to live 29 u_char proto; // Protocol 30 u_short crc; // Header checksum 31 ip_address saddr; // Source address 32 ip_address daddr; // Destination address 33 u_int op_pad; // Option + Padding 34 }ip_header; 35 36 /* UDP header*/ 37 typedef struct udp_header 38 { 39 u_short sport; // Source port 40 u_short dport; // Destination port 41 u_short len; // Datagram length 42 u_short crc; // Checksum 43 }udp_header; 44 45 /* prototype of the packet handler */ 46 void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data); 47 48 49 int main() 50 { 51 pcap_if_t *alldevs; 52 pcap_if_t *d; 53 int inum; 54 int i=0; 55 pcap_t *adhandle; 56 char errbuf[PCAP_ERRBUF_SIZE]; 57 u_int netmask; 58 char packet_filter[] = "ip and udp"; 59 struct bpf_program fcode; 60 61 /* Retrieve the device list */ 62 if(pcap_findalldevs(&alldevs, errbuf) == -1) 63 { 64 fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); 65 exit(1); 66 } 67 68 /* Print the list */ 69 for(d=alldevs; d; d=d->next) 70 { 71 printf("%d. %s", ++i, d->name); 72 if (d->description) 73 printf(" (%s)\n", d->description); 74 else 75 printf(" (No description available)\n"); 76 } 77 78 if(i==0) 79 { 80 printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); 81 return -1; 82 } 83 84 printf("Enter the interface number (1-%d):",i); 85 scanf("%d", &inum); 86 87 /* Check if the user specified a valid adapter */ 88 if(inum < 1 || inum > i) 89 { 90 printf("\nAdapter number out of range.\n"); 91 92 /* Free the device list */ 93 pcap_freealldevs(alldevs); 94 return -1; 95 } 96 97 /* Jump to the selected adapter */ 98 for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++); 99 100 /* Open the adapter */ 101 if ((adhandle= pcap_open_live(d->name, // name of the device 102 65536, // portion of the packet to capture. 103 // 65536 grants that the whole packet will be captured on all the MACs. 104 1, // promiscuous mode (nonzero means promiscuous) 105 1000, // read timeout 106 errbuf // error buffer 107 )) == NULL) 108 { 109 fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n"); 110 /* Free the device list */ 111 pcap_freealldevs(alldevs); 112 return -1; 113 } 114 115 /* Check the link layer. We support only Ethernet for simplicity. */ 116 if(pcap_datalink(adhandle) != DLT_EN10MB) 117 { 118 fprintf(stderr,"\nThis program works only on Ethernet networks.\n"); 119 /* Free the device list */ 120 pcap_freealldevs(alldevs); 121 return -1; 122 } 123 124 if(d->addresses != NULL) 125 /* Retrieve the mask of the first address of the interface */ 126 netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr; 127 else 128 /* If the interface is without addresses we suppose to be in a C class network */ 129 netmask=0xffffff; 130 131 132 //compile the filter 133 if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 ) 134 { 135 fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n"); 136 /* Free the device list */ 137 pcap_freealldevs(alldevs); 138 return -1; 139 } 140 141 //set the filter 142 if (pcap_setfilter(adhandle, &fcode)<0) 143 { 144 fprintf(stderr,"\nError setting the filter.\n"); 145 /* Free the device list */ 146 pcap_freealldevs(alldevs); 147 return -1; 148 } 149 150 printf("\nlistening on %s...\n", d->description); 151 152 /* At this point, we don't need any more the device list. Free it */ 153 pcap_freealldevs(alldevs); 154 155 /* start the capture */ 156 pcap_loop(adhandle, 0, packet_handler, NULL); 157 158 return 0; 159 } 160 161 /* Callback function invoked by libpcap for every incoming packet */ 162 void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) 163 { 164 struct tm *ltime; 165 char timestr[16]; 166 ip_header *ih; 167 udp_header *uh; 168 u_int ip_len; 169 u_short sport,dport; 170 time_t local_tv_sec; 171 172 /* 173 * unused parameter 174 */ 175 (VOID)(param); 176 177 /* convert the timestamp to readable format */ 178 local_tv_sec = header->ts.tv_sec; 179 ltime=localtime(&local_tv_sec); 180 strftime( timestr, sizeof timestr, "%H:%M:%S", ltime); 181 182 /* print timestamp and length of the packet */ 183 printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len); 184 185 /* retireve the position of the ip header */ 186 ih = (ip_header *) (pkt_data + 187 14); //length of ethernet header 188 189 /* retireve the position of the udp header */ 190 ip_len = (ih->ver_ihl & 0xf) * 4; 191 uh = (udp_header *) ((u_char*)ih + ip_len); 192 193 /* convert from network byte order to host byte order */ 194 sport = ntohs( uh->sport ); 195 dport = ntohs( uh->dport ); 196 197 /* print ip addresses and udp ports */ 198 printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d\n", 199 ih->saddr.byte1, 200 ih->saddr.byte2, 201 ih->saddr.byte3, 202 ih->saddr.byte4, 203 sport, 204 ih->daddr.byte1, 205 ih->daddr.byte2, 206 ih->daddr.byte3, 207 ih->daddr.byte4, 208 dport); 209 }
在代碼中只獲取了UDP數據包,具體代碼如下
char packet_filter[] = "ip and udp";
執行結果:

圖11 UDP數據包分析結果
為了操作方便我把其他網卡禁用了
在Winpcap 的開發包中還有其他示例額,自己慢慢去看吧
本篇有賣弄嫌疑,但是也是讓大家深入理解Winpcap的具體開發方法,在下一篇我們就一起使用winpcap抓包吧 ^_^
NetAnalzyer交流群:39753670 (PS 只提供交流平台,群主基本不說話^_^)
[轉載請保留作者信息 作者:馮天文 網址:http://www.cnblogs.com/twzy/p/4765155.html]