最后一章是要将解析数据写的GUI上,先来回顾一下GUI长什么样,这样就对要在界面上写什么数据心中有数了,如下这两图:
可以看出,要写在GUI上的数据主要有五个部分:
1、 参数设置:网卡接口、过滤项
2、 数据包捕获列表,显示数据包简要信息
3、 树形目录,显示被选中的数据包头详细信息
4、 文本框,显示被选中的数据包十六进制信息
5、 统计信息:各类包的数量
限于篇幅接下来不会对所有信息是怎么放、每个控件怎么操作一一讲解了。首先会简单讲解一下是如何将数据放到界面上的;同时再对一些要点:第2点信息中如何根据数据包类型显示不同颜色背景,第4点信息中如何将数据包内容以格式化的方式显示出来做一下讲解。
一、控件写数据的基本操作
由于我们选择的是对话框的形式的界面,所以主界面只有一个,放置在主界面上的各个控件都可以通过主界面的this指针调用,并设置控件的值,例如:
this->m_listCtrl.SetItemText(nItem,2,buf);
其中m_listCtrl是放置于主界面上的一个列表控件,至于参数是什么意思查MSDN吧。各种控件上的数据也就基本通过这样的方式调用
程序中我们新开了一个线程来处理数据,线程中每收到一个数据包都需要更新一下界面,这样就可以实时看到捕获的数据及统计信息了,这需要我们把主界面的this指针传递给线程,如下:
m_ThreadHandle=CreateThread(NULL,0,lixsinff_CapThread,this,0,threadCap);
线程处理函数原型如下:
DWORD WINAPI lixsinff_CapThread(LPVOID lpParameter);
这里的lpParameter就是刚刚传递进来的this指针了,在函数中使用如下:
Cmcf6Dlg*pthis = (Cmcf6Dlg*) lpParameter;
其他的使用就跟前面一样了。
有时候需要根据事件来显示数据,那么控件的事件怎么添加呢,一个简单的办法就是打开资源视图,选择某一控件,再点击“闪电”形的按钮,就可以看到IDE已经早就为控件设置好各种事件了,你只需要选择某一事件,并增加自定义函数就行了。如下图
二、两个要点
下面两个要点是我在显示数据的时候遇到的实际困难,因为其他的数据都是直接将数据写到控件里就完事了,而这里则要先做一些预处理,将这个贴出来节省大家时间。
2.1根据不同协议显示不同颜色
从下面这幅图可以看到,List控件有一个事件是NM_CUSTOMDRAW,每次有新的一行加入的时候,都触发该事件,然后调用相关的处理函数进行自定义绘制,可以注册一个该事件,代码见下
voidCmcf6Dlg::OnNMCustomdrawList1(NMHDR *pNMHDR, LRESULT *pResult)
{
//LPNMCUSTOMDRAWpNMCD = reinterpret_cast(pNMHDR);
LPNMLVCUSTOMDRAWpNMCD = (LPNMLVCUSTOMDRAW)pNMHDR;
*pResult= 0;
//TODO: 在此添加控件通知处理程序代码
if(CDDS_PREPAINT==pNMCD->nmcd.dwDrawStage)
{
*pResult= CDRF_NOTIFYITEMDRAW;
}elseif(CDDS_ITEMPREPAINT ==pNMCD->nmcd.dwDrawStage){
COLORREFcrText;
charbuf[10];
memset(buf,0,10);
POSITION pos =this->m_localDataList.FindIndex(pNMCD->nmcd.dwItemSpec);
struct datapkt * local_data =(struct datapkt *)this->m_localDataList.GetAt(pos);
strcpy(buf,local_data->pktType);
if(strcmp(buf,"IPV6")==0)
crText= RGB(111,224,254);
elseif(strcmp(buf,"UDP")==0)
crText= RGB(194,195,252);
elseif(strcmp(buf,"TCP")==0)
crText= RGB(230,230,230);
elseif(strcmp(buf,"ARP")==0)
crText= RGB(226,238,227);
elseif(strcmp(buf,"ICMP")==0)
crText= RGB(49,164,238);
elseif(strcmp(buf,"HTTP")==0)
crText= RGB(238,232,180);
elseif(strcmp(buf,"ICMPv6")==0)
crText= RGB(189,254,76);
pNMCD->clrTextBk=crText;
*pResult= CDRF_DODEFAULT;
}
}
首先通过下面这段代码获得新加入到List列表中的数据位置
POSITION pos = this->m_localDataList.FindIndex(pNMCD->nmcd.dwItemSpec);
然后通过下面代码获得新加入行中存储的数据
structdatapkt * local_data = (struct datapkt *)this->m_localDataList.GetAt(pos);
最后根据数据中对应的协议设置不同的显示颜色。这样,一个界面友好的列表就设置好了。
2.2对数据格式化显示
主要通过下面这个函数实现,下面这个函数主要做了两件事:1、将数据是16进制的形式显示;2、将数据以字符形式显示。代码相信大家都看得懂,就不做过多解释了。
void print_packet_hex(const u_char* pkt,intsize_pkt,CString *buf)
{
inti=0,j = 0,rowcount;
u_char ch;
char tempbuf[256];
memset(tempbuf,0,256);
for(i= 0;iAppendFormat(_T("%04x: "),(u_int)i);
rowcount= (size_pkt-i) > 16 ? 16 : (size_pkt-i);
for(j = 0; j < rowcount; j++)
buf->AppendFormat(_T("%02x "),(u_int)pkt[i+j]);
//不足16,用空格补足
if(rowcount<16)
for(j=rowcount;j<16;j++)
buf->AppendFormat(_T(" "));
for(j = 0; j < rowcount; j++)
{
ch = pkt[i+j];
ch = isprint(ch) ? ch : '.';
buf->AppendFormat(_T("%c"),ch);
}
buf->Append(_T("\r\n"));
if(rowcount<16)
return;
}
}
至此,如何应用MFC写一个sniffer就完整地结束了,未讲清楚的,可直接参考代码,这里可进行代码下载
http://download.csdn.net/download/litingli/4110529