sniffer网络数据包抓取(Winpcap+MFC+vs)

先附上Wipcap中文文档,大部分代码来源于此:http://www.ferrisxu.com/WinPcap/html/main.html

抓包解析主要分为以下几个步骤:

 一:vs对于Winpcap的相关配置:

             所需文件Winpcap配置:http://pan.baidu.com/s/1i4DAvcx

             配置步骤   http://blog.csdn.net/gaohuaid/article/details/8851169


 二:总体画出需要显示的界面。


 三:获取本地网卡设备列表。

1.此处使用的是MFC中的Combo Box控件(结果如图示)。

sniffer网络数据包抓取(Winpcap+MFC+vs)_第1张图片

2.获取网卡设备代码。(结果保存在Dev数组里)

int MYWPCAP::GetLocalDev()
{
	//清空Dev中保存的值,防止用户的越界操作,Dev数组保存的为网卡设备
	for (int j = 0; j < 10; j++)
		Dev[j] = (CString)"";

	pcap_if_t *d;
	int i = 0;
	char errbuf[PCAP_ERRBUF_SIZE];
	if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
	{
		return -1;							//获取设备列表失败
	}

	//将获取到的设备列表名称保存在Dev数组中
	for (d = alldevs; d != NULL; d = d->next)
	{
		Dev[i] = d->name;
		i++;
	}

	if (i == 0)
	{
		return 0;							//设备列表为空
	}

	pcap_freealldevs(alldevs);				//释放设备列表
	
	return 1;								//获取设备列表成功
}
3.此处为显示设备名称代码(test为Combo Box控件名称)

test.GetLocalDev();
for (int i = 0; test.Dev[i] != ""; i++)
	devive.AddString(test.Dev[i]);
devive.SetCurSel(0);


四.跳转到选中的适配器(参数Dvname为选择网卡名称)

int MYWPCAP::OpenDev(CString Devname)
{	
	char errbuf[PCAP_ERRBUF_SIZE];
	if ((adhandle = pcap_open_live((LPSTR)(LPCTSTR)Devname,         // 设备名
		65535,            // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容
		PCAP_OPENFLAG_PROMISCUOUS,    // 混杂模式
		1000,             // 读取超时时间
		errbuf            // 错误缓冲池
		)) == NULL)
	{
		return -1;									//打开异常返回-1;
	}
	return 0;										//	打开正常返回0
}



五.捕获数据报。

1.对捕获的数据包进行过滤(代码具体解释见WipCap中文文档)

int MYWPCAP::SetSnifer()
{
	u_int netmask;
	char packet_filter[] = "ip";
	struct bpf_program fcode;
	

	/* 检查数据链路层,为了简单,我们只考虑以太网 */
	if (pcap_datalink(adhandle) != DLT_EN10MB)
	{
		pcap_freealldevs(alldevs);
		return -1;
	}
	netmask = 0xffffff;

	//编译过滤器
	if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0)
	{
		pcap_freealldevs(alldevs);
		return -1;
	}

	//设置过滤器
	if (pcap_setfilter(adhandle, &fcode)<0)
	{
		pcap_freealldevs(alldevs);
		return -1;
	}

	return 0;

}

2.开启对数据报进行捕获的线程,捕获代码如下:

UINT MYWPCAP::Hanter(LPVOID pParam)
{
	
	HantParam *mypcap = (HantParam*)pParam;
	
	int res;

	char timestr[16]; 
	struct pcap_pkthdr *header; 
	const u_char *pkt_data; 
	time_t local_tv_sec=time(0);
	struct tm ltime;

	while (1)
	{
        res = pcap_next_ex(mypcap->adhandle, &header, &pkt_data);
		if (res > 0)
		{
			//解析
			ip_header *ih;
			ih = (ip_header *)(pkt_data + 14); 

			MsgParam *msg = new MsgParam();
			msg->ih = ih;
			char *tmp = new char[100];
			strcpy_s(tmp,100,"ip");
			msg->msg = tmp;
			::SendMessage(mypcap->m_hWnd, WM_USER_THREADEND, 0, (LPARAM)ih);
			break;
		}
	}   

	local_tv_sec = header->ts.tv_sec;
	localtime_s(ts.tv_usec, header->len);
	if (res == -1)
	{
		return -1; 
	}
	return 0;
}


ps:其中::SendMessage(mypcap->m_hWnd, WM_USER_THREADEND, 0, (LPARAM)ih);为捕获到一个数据包时向主窗口发送一个消息,主窗口就可以使用这个消息传的参数,这里的参数为ih,即ip数据报的首部。主窗口收到该消息后,就会调用此此消息所映射的函数(这个函数为自定义)。
关于MFC自定义消息机制,详情可看:http://blog.csdn.net/qihailong123456/article/details/6777112


3.当主窗口接收的捕获数据报的消息后,此处将该消息映射的函数定义为MyMsg(WPARAM, LPARAM);此函数为解析数据包并显示在界面上,到此为止,程序框架已经出来了。
解析的步骤为,先解析ip头部,查看数据部分的协议类型,根据不同的类型,对数据部分的TCP,UDP,ICMP等数据包进行解析并显示,具体为使用对应的结构体对其进行封装,取出对应部分,和四.2的Hanter中解析出ip头部类似(具体代码有待更新,最好自己尝试写)。

你可能感兴趣的:(sniffer网络数据包抓取(Winpcap+MFC+vs))