一步一步开发sniffer(Winpcap+MFC)(六)千呼万唤始出来,不抱琵琶也露面——将解析数据写到GUI上

来源:互联网 发布:重装linux系统有pe 编辑:程序博客网 时间:2024/04/29 02:07

最后一章是要将解析数据写的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<LPNMCUSTOMDRAW>(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;i<size_pkt;i+=16)         {                   buf->AppendFormat(_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





原创粉丝点击