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里面包含库文件,头文件,文档文件和一些例子。解压到一个指定的目录。

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

图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目录。

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

图2 VC6.0环境下Include目录与Lib目录配置

VS2010环境如图3所示,

Visual Studio 2010: 菜单栏 工具->选项->项目和解决方案/项目->VC++目录。有时候可能出现“目录编辑功能被否决”的情况,可以通过 菜单栏 项目->XXX属性->配置属性->VC++目录 中配置,本次使用的就是这种方式。

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

图3 Visual  Studio 2010环境下Include目录与Lib目录配置

通过上面的方式完成了文件引入部分的配置,接下来是导入库文件的方法,在VC6.0中也叫做链接库的配置。

VC6.0:菜单栏Project->Settings->Link->Object/library modules,在其中添加wpcap.lib,Packet.lib,点击OK即可。如图4

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

图4 VC6.0环境下链接库文件配置

Visual Studio 2010:右击 解决方案资源管理器->添加->现有项…导入Packet.lib和wpacp.lib库文件即可。如图5

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

图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所示

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

图6 Visual Studio 2010环境下WPCAP与HAVE_REMOTE标号的配置

 Winpcap编程实现

通过上面的配置完成了对Winpcap开发环境搭建,接下来我们就可以做一个小程序了。在做抓包程序之前,我们首先要确定从何处采集数据,大家首先想到的就是网卡,所以,第一步就是要获取网卡:

步骤:

(a)  打开Visual Studio 2010 新建项目,语言选择C++,类型选择Win32控制台应用程序,点击确定按钮。

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

图7 新建项目

(b)  进入想到页面,直接点击下一步,进入第二个页面,因为我们要使用C语言来制作该程序,但是在Visual Studio 2010并没用提供专用的C开发环境,所以上一步中我们选择的是C++模板,因此在接下来的页面,我们要在附加选项中选择“空项目”,这样开发环境就不会导入一些关于C++的东西了,点击完成。

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

图8 选择空项目

(c) 于是开发环境为我们配置了一个空项目,在解决方案资源管理器中选择源文件,右击在菜单中添加选择新建项,此时打开新建项对话框,找到C++文件,输入文件名称,注意,同时键入扩展名“.c,这样就可以建立一个C源文件,

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

图9 配置方案结果

(d) 然后按照上面的环境配置方案,对项目中Include目录lib目录进行配置;导入库文件;配置标识号;最后写入如下代码:

 #include "pcap.h"
main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int i=;
char errbuf[PCAP_ERRBUF_SIZE]; /* 获取本地机器设备列表 */
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL /* auth is not needed */, &alldevs, errbuf) == -)
{
fprintf(stderr,"Error in pcap_findalldevs_ex: %s\n", errbuf);
exit();
}
/* 打印列表 */
for(d= alldevs; d != NULL; 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 == )
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return;
}
/* 不再需要设备列表了,释放它 */
pcap_freealldevs(alldevs);
}

该段代码来自Winpcap开发文档中的第一节,主要的任务是获取主机网卡设备。

(e) 最后按Ctrl+F5启动,开始编译执行该段。

结果:如图10

这里的编程实现仅仅是为了演示,Winpcap的开发配置过程,更多更为详尽的实现过程请参阅Winpcap开发文档,从Winpcap官网即可获得,所以之后的一些实现原理并不是本书的重点,故不再赘述。

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

图10 获取网卡执行结果

如果只是,获取到网卡,那也没什么好讲的了,下面是一段示例中的代码,在这段代码中我们不但可以取到网卡,还可以进行数据分析

 #ifdef _MSC_VER
/*
* we do not want the warnings about the old deprecated and unsecure CRT functions
* since these examples can be compiled under *nix as well
*/
#define _CRT_SECURE_NO_WARNINGS
#endif #include "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); int main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=;
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) == -)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit();
} /* 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==)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return -;
} printf("Enter the interface number (1-%d):",i);
scanf("%d", &inum); /* Check if the user specified a valid adapter */
if(inum < || inum > i)
{
printf("\nAdapter number out of range.\n"); /* Free the device list */
pcap_freealldevs(alldevs);
return -;
} /* Jump to the selected adapter */
for(d=alldevs, i=; i< inum- ;d=d->next, i++); /* Open the adapter */
if ((adhandle= pcap_open_live(d->name, // name of the device
, // portion of the packet to capture.
// 65536 grants that the whole packet will be captured on all the MACs.
, // promiscuous mode (nonzero means promiscuous)
, // 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 -;
} /* 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 -;
} 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, , netmask) < )
{
fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -;
} //set the filter
if (pcap_setfilter(adhandle, &fcode)<)
{
fprintf(stderr,"\nError setting the filter.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -;
} 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, , packet_handler, NULL); return ;
} /* 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[];
ip_header *ih;
udp_header *uh;
u_int ip_len;
u_short sport,dport;
time_t local_tv_sec; /*
* unused parameter
*/
(VOID)(param); /* convert the timestamp to readable format */
local_tv_sec = header->ts.tv_sec;
ltime=localtime(&local_tv_sec);
strftime( timestr, sizeof timestr, "%H:%M:%S", ltime); /* print timestamp and length of the packet */
printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len); /* retireve the position of the ip header */
ih = (ip_header *) (pkt_data +
); //length of ethernet header /* retireve the position of the udp header */
ip_len = (ih->ver_ihl & 0xf) * ;
uh = (udp_header *) ((u_char*)ih + ip_len); /* convert from network byte order to host byte order */
sport = ntohs( uh->sport );
dport = ntohs( uh->dport ); /* print ip addresses and udp ports */
printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d\n",
ih->saddr.byte1,
ih->saddr.byte2,
ih->saddr.byte3,
ih->saddr.byte4,
sport,
ih->daddr.byte1,
ih->daddr.byte2,
ih->daddr.byte3,
ih->daddr.byte4,
dport);
}

在代码中只获取了UDP数据包,具体代码如下

  char packet_filter[] = "ip and udp"; 

执行结果:
NetAnalyzer笔记 之 三. 用C++做一个抓包程序
图11 UDP数据包分析结果
为了操作方便我把其他网卡禁用了

在Winpcap 的开发包中还有其他示例额,自己慢慢去看吧

本篇有卖弄嫌疑,但是也是让大家深入理解Winpcap的具体开发方法,在下一篇我们就一起使用winpcap抓包吧 ^_^

NetAnalyzer下载地址

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

[转载请保留作者信息  作者:冯天文  网址:http://www.cnblogs.com/twzy/p/4765155.html]

上一篇:设置python 命令行交互程序自己主动补齐


下一篇:.net升级到4.0之后,出现;System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798