NetAnalyzer笔记 之 三. 用C++做一个抓包程序
[创建时间: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]