NetAnalyzer筆記 之 三. 用C++做一個抓包程序


[創建時間:2015-08-27 22:15:17]

NetAnalyzer下載地址

經過前兩篇的瞎扯,你是不是已經厭倦了呢,那么這篇讓我們來點有意思的吧,什么,用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抓包吧 ^_^

 

 

NetAnalyzer下載地址

NetAnalzyer交流群:39753670 (PS 只提供交流平台,群主基本不說話^_^)

[轉載請保留作者信息  作者:馮天文  網址:http://www.cnblogs.com/twzy/p/4765155.html]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM