基于WinPcap和MFC实现的网络嗅探器

Brokenner

发布日期: 2019-02-11 17:10:11 浏览量: 656
评分:
star star star star star star star star star star_border
*转载请注明来自write-bug.com

一、实验目的

  • 掌握嗅探器的工作原理

  • 熟悉 WinPcap 的使用

  • 掌握基于 WinPcap 网络嗅探器的开发过程

二、实验内容

开发出一个 Windows 平台上的网络嗅探工具,能显示所捕获的数据包,并能做相应的分析和统计。主要内容如下:

  • 列出监测主机的所有网卡,选择一个网卡,设置为混杂模式进行监听

  • 捕获所有流经网卡的数据包,并利用 WinPcap 函数库设置过滤规则

  • 分析捕获到的数据包的包头和数据,按照各种协议的格式进行格式化显示

  • 将所开发工具的捕获和分析结果与常用的嗅探器,如 Wireshark,进行比较,完善程序代码

三、开发环境

  • WinPcap 支持库

  • Visual C++ 语言,MFC 支持库

  • Visual Studio 2008 集成开发环境

  • Windows 2007 操作系统

四、系统设计

本次课程设计主要完成基于 WinPcap 的网络嗅探器软件的设计与实现。通过WinPcap 支持库我们可以获取本机网卡信息,并读取经过一个网卡的所有数据包。

通过对数据包的结构化分析,我们可以获得所有数据包的类型及具体内容,然后通过 MFC 可视化控件显示到软件界面上。系统流程图如图 1 所示。

五、模块实现

本次课程设计所实现的嗅探器主要分为四个模块:WinPcap 抓包模块、数据包分析模块、程序界面模块、交互设计模块。各模块的实现如下。

5.1 WinPcap 抓包模块

该模块主要包括:获取本机网卡信息、设置数据包过滤规则、抓取数据包三个功能。其程序框架图如图 2 所示。

5.2 数据包分析模块

该模块是软件实现的重点模块。我们捕获的数据包是以太网帧,通过对帧结构中部分字段进行判别,我们可以识别出该数据包具体属于哪种协议的数据包。

在本次试验中,我们具体分析 TCP,UDP,ICMP,ARP,HTTP 数据包。部分数据包首部定义如下:

  1. //Mac头部,总长度14字节
  2. typedef struct ethernet_header
  3. {
  4. u_char dstmac[6]; //目标mac地址
  5. u_char srcmac[6]; //源mac地址
  6. u_short eth_type; //以太网类型
  7. }ethernet_header;
  8. /* 4 bytes IP address */
  9. typedef struct ip_address{
  10. u_char byte1; //IP地址第1个字段
  11. u_char byte2; //IP地址第2个字段
  12. u_char byte3; //IP地址第3个字段
  13. u_char byte4; //IP地址第4个字段
  14. }ip_address;
  15. //IP头部,总长度20字节
  16. typedef struct ip_header
  17. {
  18. #if LITTLE_ENDIAN
  19. u_char ihl:4; //首部长度
  20. u_char version:4;//版本
  21. #else
  22. u_char version:4;//版本
  23. u_char ihl:4; //首部长度
  24. #endif
  25. u_char tos; //服务类型
  26. u_short tot_len; //总长度
  27. u_short id; //标识号
  28. #if LITTLE_ENDIAN
  29. u_short frag_off:13;//分片偏移
  30. u_short flag:3; //标志
  31. #else
  32. u_short flag:3; //标志
  33. u_short frag_off:13;//分片偏移
  34. #endif
  35. u_char ttl; //生存时间
  36. u_char protocol; //协议
  37. u_short chk_sum; //检验和
  38. struct ip_address srcaddr; //源IP地址
  39. struct ip_address dstaddr; //目的IP地址
  40. }ip_header;
  41. //TCP头部,总长度20字节 TCP头部与TCP数据包不是一个概念;
  42. typedef struct tcp_header
  43. {
  44. u_short src_port; //源端口号
  45. u_short dst_port; //目的端口号
  46. u_int seq_no; //序列号
  47. u_int ack_no; //确认号
  48. #if LITTLE_ENDIAN
  49. u_char reserved_1:4; //保留6位中的4位首部长度
  50. u_char offset:4; //tcp头部长度
  51. u_char flag:6; //6位标志
  52. u_char reserved_2:2; //保留6位中的2位
  53. #else
  54. u_char offset:4; //tcp头部长度
  55. u_char reserved_1:4; //保留6位中的4位首部长度
  56. u_char reserved_2:2; //保留6位中的2位
  57. u_char flag:6; //6位标志
  58. #endif
  59. u_short wnd_size; //16位窗口大小
  60. u_short chk_sum; //16位TCP检验和
  61. u_short urgt_p; //16为紧急指针
  62. }tcp_header;
  63. //UDP头部,总长度8字节
  64. typedef struct udp_header
  65. {
  66. u_short src_port; //远端口号
  67. u_short dst_port; //目的端口号
  68. u_short uhl; //udp头部长度
  69. u_short chk_sum; //16位udp检验和
  70. }udp_header;
  71. //ICMP头部,总长度4字节
  72. typedef struct icmp_header
  73. {
  74. u_char type; //类型
  75. u_char code; //代码
  76. u_short chk_sum; //16位检验和
  77. }icmp_header;

在捕获数据包之后,我们需要对特定字段进行识别,以判断该数据包具体属于哪个协议,分析数据包流程如图 3 所示:

5.3 程序界面模块

  • 界面上方的 button : 用于用户交互,控制整个软件的运行

  • 界面上方的 Combo Box : 用于选择监听的网口

  • 左上方的 Group Box :用户统计不同数据包的个数

  • 左方中间的 Group Box : 用于设置数据包过滤器

  • 中间主体部分 List Control: 结构化显示捕获数据包的信息

  • 左下方的 Tree-view Control: 分析数据包各个字段代表的含义

  • 右下方的 Edit Control: 显示数据包的内容

5.4 交互设计模块

结构化显示数据包:

  1. // 显示选中的网卡数据包pkt信息到List Control列表框中
  2. void CYGSnifferDlg::DispSelectedtoListCtrl(packet *tmp_pkt)
  3. {
  4. packet *pkt = new packet;
  5. const struct pcap_pkthdr *header = new pcap_pkthdr;
  6. const u_char *pkt_data = new u_char;
  7. pkt = tmp_pkt;
  8. header = pkt->header;
  9. pkt_data = pkt->pkt_data;
  10. //No
  11. int iNoCount = m_listAdapterInfo.GetItemCount();
  12. int iNoDisp = iNoCount + 1;
  13. TCHAR strNo[10];
  14. _itow_s(iNoDisp,strNo,10);
  15. //TimeStamp
  16. struct tm lTime = {0,0,0,0,0,0,0,0,0};
  17. struct tm *plTime = &lTime;
  18. char strTime[16];
  19. time_t local_tv_sec;
  20. local_tv_sec = header->ts.tv_sec;
  21. localtime_s(plTime,&local_tv_sec);
  22. strftime(strTime,sizeof strTime,"%H:%M:%S",plTime);
  23. //Length
  24. int iLength = header->len;
  25. TCHAR strLength[10];
  26. _itow_s(iLength,strLength,10);
  27. //Ethernet - Mac
  28. ethernet_header *eth_hdr = (ethernet_header *)pkt_data;
  29. TCHAR eth_srcMac[18];
  30. TCHAR eth_dstMac[18];
  31. CString eth_strType = NULL;
  32. GetMacAddress(eth_srcMac,eth_hdr->srcmac);
  33. GetMacAddress(eth_dstMac,eth_hdr->dstmac);
  34. GetMacType(eth_strType,ntohs(eth_hdr->eth_type),true); // ntohs() is to swap network to host
  35. // IP
  36. ip_header *ip_hdr = (ip_header *)(pkt_data+14); // get ip pos
  37. TCHAR ip_srcAddr[16];
  38. TCHAR ip_dstAddr[16];
  39. CString ip_strProtocol = NULL;
  40. GetIPAddress(ip_srcAddr,&ip_hdr->srcaddr);
  41. GetIPAddress(ip_dstAddr,&ip_hdr->dstaddr);
  42. GetIPType(ip_strProtocol,ip_hdr->protocol,true);
  43. IsHTTP(pkt_data);
  44. //=========== show ============
  45. m_listAdapterInfo.InsertItem(iNoCount,strNo);
  46. USES_CONVERSION;
  47. m_listAdapterInfo.SetItemText(iNoCount,1,A2W(strTime));
  48. m_listAdapterInfo.SetItemText(iNoCount,2,strLength);
  49. m_listAdapterInfo.SetItemText(iNoCount,3,eth_strType);
  50. m_listAdapterInfo.SetItemText(iNoCount,4,eth_srcMac);
  51. m_listAdapterInfo.SetItemText(iNoCount,5,eth_dstMac);
  52. m_listAdapterInfo.SetItemText(iNoCount,6,ip_strProtocol);
  53. m_listAdapterInfo.SetItemText(iNoCount,7,ip_srcAddr);
  54. m_listAdapterInfo.SetItemText(iNoCount,8,ip_dstAddr);
  55. if(pkt)
  56. {
  57. delete pkt;
  58. pkt = NULL;
  59. }
  60. if(header)
  61. {
  62. delete header;
  63. header = NULL;
  64. }
  65. if(pkt_data)
  66. {
  67. delete pkt_data;
  68. pkt_data = NULL;
  69. }
  70. }

显示数据包详细信息(以 IP 协议为例):

  1. // 显示IP协议的详细信息
  2. void CYGSnifferDlg::ShowIPDetail(HTREEITEM &hItem,const u_char *pkt_data)
  3. {
  4. // =================== IP ======================
  5. ip_header *ip_hdr = (ip_header *)(pkt_data+14);
  6. hItem = m_treeDetailInfo.InsertItem(TEXT("IP LAYER"));
  7. CString str = NULL;
  8. // Version
  9. u_char ip_version = ip_hdr->version;
  10. str.Format(TEXT("Version = %d"),ip_version);
  11. m_treeDetailInfo.InsertItem(str, hItem);
  12. // Header Length
  13. u_char ip_length = ip_hdr->ihl;
  14. str.Format(TEXT("Header Length = %d"),ip_length);
  15. m_treeDetailInfo.InsertItem(str, hItem);
  16. // Type of service
  17. u_char ip_tos = ip_hdr->tos;
  18. str.Format(TEXT("Service Type = %0X"),ip_tos);
  19. m_treeDetailInfo.InsertItem(str, hItem);
  20. // Total Length
  21. u_short ip_totalLen = ip_hdr->tot_len;
  22. str.Format(TEXT("Total Length = %d"),ntohs(ip_totalLen));
  23. m_treeDetailInfo.InsertItem(str, hItem);
  24. // Identification
  25. str.Format(TEXT("Identification = %d"),ntohs(ip_hdr->id));
  26. m_treeDetailInfo.InsertItem(str, hItem);
  27. // Flags
  28. TCHAR ip_strFlag[4];
  29. u_short ip_flag = (ip_hdr->flag);
  30. _itow_s(ip_flag,ip_strFlag,4,2);
  31. str.Format(TEXT("Flag = %03s"),ip_strFlag);// 填充字符串方法:CString szTemp; szTemp.Format("%06d", n); //n=123(000123)|456(000456)
  32. m_treeDetailInfo.InsertItem(str, hItem);
  33. // Flagment offset
  34. u_short ip_flagoff = ip_hdr->frag_off;
  35. str.Format(TEXT("Flagment offset = %d"),ip_flagoff);
  36. m_treeDetailInfo.InsertItem(str, hItem);
  37. // Time to live
  38. u_char ip_ttl = ip_hdr->ttl;
  39. str.Format(TEXT("Time to live = %d"),ip_ttl);
  40. m_treeDetailInfo.InsertItem(str, hItem);
  41. // IP Protocol
  42. CString ip_strProtocol = NULL;
  43. u_char ip_protocol = ip_hdr->protocol;
  44. GetIPType(ip_strProtocol,ip_protocol,false); // get ip protocol by call function -> GetIPType()
  45. str.Format(TEXT("IP Protocol = %s"),ip_strProtocol);
  46. m_treeDetailInfo.InsertItem(str, hItem);
  47. // Header CheckSum
  48. u_short ip_chksum = ip_hdr->chk_sum;
  49. str.Format(TEXT("Header CheckSum = %0X"),ntohs(ip_chksum));
  50. m_treeDetailInfo.InsertItem(str, hItem);
  51. // Source IP
  52. TCHAR ip_srcAddr[16];
  53. TCHAR ip_dstAddr[16];
  54. GetIPAddress(ip_srcAddr,&ip_hdr->srcaddr);
  55. GetIPAddress(ip_dstAddr,&ip_hdr->dstaddr);
  56. str.Format(TEXT("Source IP = %s"),ip_srcAddr);
  57. m_treeDetailInfo.InsertItem(str, hItem);
  58. str.Format(TEXT("Dest IP = %s"),ip_dstAddr);
  59. m_treeDetailInfo.InsertItem(str, hItem);
  60. }

显示数据包内容:

  1. // 显示Packet Data数据信息,最下方控件显示;
  2. void CYGSnifferDlg::GetDataInfo(CEdit & eText, packet *pkt)
  3. {
  4. const struct pcap_pkthdr *header = pkt->header;
  5. const u_char *pkt_data = pkt->pkt_data;
  6. u_int pkt_dataLen = header->len; // 得到单个Packet_Data(注意:不是packet)数据包的长度
  7. CString strText = NULL;
  8. CString chrAppend = NULL;
  9. u_int eRows = 0;
  10. for(u_short i=0; i<pkt_dataLen; i++)
  11. {
  12. CString strAppend = NULL;
  13. if(0 == (i%16)) // 取余,换行
  14. {
  15. eRows++;
  16. if(0 == i)
  17. {
  18. strText +=chrAppend;
  19. strAppend.Format(TEXT(" 0X%04X -> "),eRows);
  20. strText += strAppend;
  21. }
  22. else
  23. {
  24. strText +=TEXT("==>> ") +chrAppend;
  25. strAppend.Format(TEXT("\x0d\x0a 0X%04X -> "),eRows); //0x0d:回车; 0x0a:换行;0X:表示16进制显示;%04x表示以4位的16进制显示并以0填充空位; eRows即显示行数(16进制格式显示)
  26. strText += strAppend;
  27. }
  28. chrAppend = ""; // reset null
  29. }
  30. strAppend.Format(TEXT("%02x "),pkt_data[i]);
  31. strText += strAppend;
  32. if(i>2 && pkt_data[i-1]==13 && pkt_data[i]==10)//如果遇到回车、换行,则直接继续,以免使显示字符换行
  33. continue;
  34. strAppend.Format(TEXT("%c"),pkt_data[i]);
  35. chrAppend += strAppend;
  36. }
  37. if(chrAppend !="")
  38. strText +=TEXT("==>> ") +chrAppend;
  39. eText.SetWindowTextW(strText);
  40. }

六、运行结果

将过滤器设置为选择 IP 和 UDP,程序运行结果如图 5 所示。

七、实验总结

7.1 遇到的问题

本次实验主要遇到的问题有两点:数据包的分析和 MFC 编程。

由于开始对网络协议及数据包结构不清楚,不知道如何解析数据包,也不知道怎样区分不同协议的数据包。于是在网上查了很多关于网络协议分层、数据包分析的资料,才终于明白各层协议之间的关系,并知道了怎样区分不同协议,并成功完成数据包分析工作。

问题二在于 MFC 编程,本科阶段我主攻 JAVA,C++ MFC 只是略有涉及。本次实验为了实现可视化,我找了很多资料,自学 MFC 编程,遇到问题的时候就像周围擅长 MFC 的同学请教,最终完成该软件的编写,虽然还有一些不足的地方,但也是一次成功的尝试。

7.2 收获与体会

通过本次实验,我对网络协议有了更深的理解,同时学会了如何处理数据包。对整个计算机网络知识的理解有了质的提升。同时,我还自学了 MFC 编程,编程水平有较大提高。总而言之,这次实验让我收获良多!

上传的附件 cloud_download 基于WinPcap和MFC实现的网络嗅探器.7z ( 4.74mb, 52次下载 )
error_outline 下载需要8点积分

发送私信

时间能冲淡一切,但却冲不掉一切

9
文章数
6
评论数
最近文章
eject