码迷,mamicode.com
首页 > 编程语言 > 详细

NetAnalyzer笔记 之 三. 用C++做一个抓包程序

时间:2015-08-29 21:33:27      阅读:275      评论:0      收藏:0      [点我收藏+]

标签:

[创建时间: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]

NetAnalyzer笔记 之 三. 用C++做一个抓包程序

标签:

原文地址:http://www.cnblogs.com/twzy/p/4765155.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!