先附上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控件(结果如图示)。
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头部类似(具体代码有待更新,最好自己尝试写)。