基于winpcap的嗅探器设计与实现设计说明.docx
《基于winpcap的嗅探器设计与实现设计说明.docx》由会员分享,可在线阅读,更多相关《基于winpcap的嗅探器设计与实现设计说明.docx(26页珍藏版)》请在冰豆网上搜索。
基于winpcap的嗅探器设计与实现设计说明
计算机与信息学院
《计算机网络系统实践》报告
设计题目:
嗅探器的设计与实现
学生XX:
***
学号:
2010****
专业班级:
信息安全****
2013年9月25
一、设计要求
1.不限平台,可以使用Libpcap、WinPcap或Linux的原始套接字;
2.实现一个功能比较简单的、具有图形界面的Sniffer,主线程响应用户界面操作,工作线程完成抓包等工作;
3.能够解析出IP层和传输层的协议头,能够过滤TCP、UDP等数据包;
4.能够输出文本方式传送的数据包的容;
5.能够进行简单的流量统计。
二、开发环境与工具
操作系统:
windows7
开发工具:
visualstudio
开发语言:
C++
附加库:
Winpcap
三、设计原理
网络嗅探器是一种常用的监听网络的工具。
所谓嗅探器(Sniffer),是一种利用计算机网络接口截获网络数据的软件或硬件,可用于网络管理、网络协议分析以与网络安全等众多方面。
嗅探器不同于一般的键捕获工具,后者只能捕获当地终端控制台上的按键容,而嗅探器所“嗅”到的是动态的以信息包形式(如IP数据包或者以太网包)封装的信息流。
其中可能携带了重要数据或敏感信息。
可以将这些捕获到的信息包存档,以利用相应工具可以作进一步分析。
计算机网络的设计为嗅探器的使用创造了最基本的条件。
在目前的网络环境中,所有计算机节点都是共享传输介质,任意节点发出或发往任意节点的数据帧必将经过网每一个节点的网络接口,此时只需对嗅探节点的网络接口(网卡)进行适当的设置便可为实现嗅探的做好准备工作。
在计算机网络系统中,网卡是用来接收网络上其他节点发来的数据帧,其嵌的单片处理程序会检测数据帧来源的MAC地址,并根据网卡所设置的接收方式来是否接收处理数据,如果认为应该处理,则网卡就会产生中断信号通知中央处理器,接收该数据帧并传输给操作系统处理。
否则就简单丢弃,所对应节点的网卡就截断,计算机的中央处理器并不参与。
网卡是网络中节点主机的关键硬件设备。
对数据的接收一般有四种设置模式:
广播模式:
接收在网络中进行广播数据信息。
组播模式:
接收组播数据信息。
单播模式:
只有匹配的目的网卡才能接收数据信息。
混杂模式:
网卡能够可以接收一切通过它的数据信息。
四、系统功能描述与软件模块划分
系统功能设计
本系统的基本功能为实现网络数据包的捕获,并将其数据容解析显示。
网络数据包捕获功能主要负责从网络中捕获和过滤数据,这可以通过调用winPcap提供的丰富的API函数来实现;数据解析与显示部分主要负责界面数据转化、解析、处理、格式化、协议分析等,这一部分主要通过MFC来设计一个单文档图形用户界面GUI,解析结果将通过MFC的类库显示到GUI中
系统总系结构
网络嗅探器的整体设计由三个模块组成,自底向上分别是嗅探器设置模块,数据包捕获模块,解析和显示模块。
嗅探器设置模块主要调用winPcaP提供的API,分为获取网络设备信息,设置并编译过滤器,打开网络设备三个步骤。
数据包捕获模块创建了新的线程,利用了winPcap的非回调函数Pcap_next_ex()函数从winPcap底层驱动的数据缓冲区中读取数据包,并将数据包存储在系统临时文件中,以便之后的分析。
用Pcap_open_offline()函数从离线文件中读取包。
读取到的任意一个符合捕获条件数据包,将其容解析,并显示本数据包。
捕获完成后,进人解析和显示模块。
(嗅探器总体结构如图1)
图1.嗅探器总体结构
五、设计步骤
嗅探器的设置模块
a.获取已连接的网络设备列表,winPcap提供了pcap_findalldevs_ex()函数,这个函数返回一个PcaP-if结构的链表,每个这样的结构都包含了一个适配器的详细信息。
b.打开网络设备,winPcap提供了pcap_open()函数,该函数第一参数制定要捕获数据包的哪些部分,第二参数用来制定适配器是否为混杂模式,第三参数为读取数据的超时时间,当适配器被打开后,就可以进行捕获工作了;
c.设置过滤器,winPcap中用来过滤数据包的函数是pcap_compile()和pcap_setfilter()。
pcap_compile()它将一个高层的布尔过滤表达式编译成一个能够被过滤引擎所解释的低层的字节码。
pcap_setfilter()将一个过滤器与核捕获会话相关联。
当pcap_set_filter()被调用时,这个过滤器将被应用到来自网络的所有数据包,并且,所有的符合要求的数据包(即那些经过过滤器以后,布尔表达式为真的包),将会立即复制给应用程序。
数据包的捕获模块
该部分创建了一个用于捕获数据包的线程,在该线程中调用winPcap提供的pcap_next_ex()函数从底层驱动数据缓冲区中读取数据包,该函数接受已打开的网络设备句柄,返回捕获数据包的实体,并用pcap_dump函数将每一个数据包写人临时文件中。
解析与显示模块
该部分在接收到用户发出的捕获完成消息后,将数据包从离线文件中逐条取出并进行解析和显示。
将解析完毕数据包中的各项容填人已经预先声明的协议的数据结构中,包括(序号,捕获时间,以太帧长度,传输层协议,源IP地址,目的IP地址,源MAC地址,目的MAC地址),然后将数据结构添加到列表视图中
六、关键问题与其解决方法
界面初始化
BOOLCzszhangDlg:
:
OnInitDialog()
{
CDialog:
:
OnInitDialog();
ASSERT((IDM_ABOUTBOX&0xFFF0)==IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX<0xF000);
CMenu*pSysMenu=GetSystemMenu(FALSE);
if(pSysMenu!
=NULL)
{
CStringstrAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if(!
strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMenu);
}
}
SetIcon(m_hIcon,TRUE);//设置大图标
SetIcon(m_hIcon,FALSE);//设置小图标
ShowWindow(SW_MINIMIZE);
m_listCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
m_listCtrl.InsertColumn(0,_T("编号"),3,30);//1表示右,表示中,表示左
m_listCtrl.InsertColumn(1,_T("时间"),3,130);
m_listCtrl.InsertColumn(2,_T("长度"),3,72);
m_listCtrl.InsertColumn(3,_T("源MAC地址"),3,140);
m_listCtrl.InsertColumn(4,_T("目的MAC地址"),3,140);
m_listCtrl.InsertColumn(5,_T("协议"),3,70);
m_listCtrl.InsertColumn(6,_T("源IP地址"),3,145);
m_listCtrl.InsertColumn(7,_T("目的IP地址"),3,145);
m_combobox.AddString(_T("请选择一个网卡接口(必选)"));
m_comboBoxRule.AddString(_T("请选择过滤规则(可选)"));
if(sniffer_initCap()<0)
returnFALSE;/*初始化接口列表*/
for(dev=alldev;dev;dev=dev->next)
{
if(dev->description)
m_combobox.AddString(CString(dev->description));
}
/*初始化过滤规则列表*/
m_comboBoxRule.AddString(_T("tcp"));
m_comboBoxRule.AddString(_T("udp"));
m_comboBoxRule.AddString(_T("ip"));
m_comboBoxRule.AddString(_T("icmp"));
m_comboBoxRule.AddString(_T("arp"));
m_combobox.SetCurSel(0);
m_comboBoxRule.SetCurSel(0);
m_buttonStop.EnableWindow(FALSE);
m_buttonSave.EnableWindow(FALSE);
returnTRUE;//除非将焦点设置到控件,否则返回TRUE
}
捕获数据包
//开始捕获
intCzszhangDlg:
:
sniffer_startCap()
{
intif_index,filter_index,count;
u_intnetmask;
structbpf_programfcode;
CStringNcard;
sniffer_initCap();
//获得接口和过滤器索引
if_index=this->m_combobox.GetCurSel();
filter_index=this->m_comboBoxRule.GetCurSel();
if(0==if_index||CB_ERR==if_index)
{
MessageBox(_T("请选择一个合适的网卡接口"));
return-1;
}
if(CB_ERR==filter_index)
{
MessageBox(_T("过滤器选择错误"));
return-1;
}
/*获得选中的网卡接口*/
dev=alldev;
for(count=0;countdev=dev->next;
if((adhandle=pcap_open_live(dev->name,//设备名
65536,//捕获数据包长度
1,//混杂模式(非意味着是混杂模式)
1000,//读超时设置
errbuf//错误信息
))==NULL)
{
MessageBox(_T("无法打开接口:
"+CString(dev->description)));
pcap_freealldevs(alldev);
return-1;
}
/*检查是否为以太网*/
if(pcap_datalink(adhandle)!
=DLT_EN10MB)
{
MessageBox(_T("这不适合于非以太网的网络!
"));
pcap_freealldevs(alldev);
return-1;
}
if(dev->addresses!
=NULL)
netmask=((structsockaddr_in*)(dev->addresses->netmask))->sin_addr.S_un.S_addr;
else
netmask=0xffffff;
//编译过滤器
if(0==filter_index)
{
charfilter[]="";
if(pcap_compile(adhandle,&fcode,filter,1,netmask)<0)
{
MessageBox(_T("语法错误,无法编译过滤器"));
pcap_freealldevs(alldev);
return-1;
}
}else{
CStringstr;
char*filter;
intlen,x;
this->m_comboBoxRule.GetLBText(filter_index,str);
len=str.GetLength()+1;
filter=(char*)malloc(len);
for(x=0;x{
filter[x]=str.GetAt(x);
}
if(pcap_compile(adhandle,&fcode,filter,1,netmask)<0)
{
MessageBox(_T("语法错误,无法编译过滤器"));
pcap_freealldevs(alldev);
return-1;
}
}
//设置过滤器
if(pcap_setfilter(adhandle,&fcode)<0)
{
MessageBox(_T("设置过滤器错误"));
pcap_freealldevs(alldev);
return-1;
}
/*设置数据包存储路径*/
CFileFindfile;
charthistime[30];
structtm*ltime;
memset(filepath,0,512);
memset(filename,0,64);
if(!
file.FindFile(_T("SavedData")))
{
CreateDirectory(_T("SavedData"),NULL);
}
time_tnowtime;
time(&nowtime);
ltime=localtime(&nowtime);
strftime(thistime,sizeof(thistime),"%Y%m%d%H%M%S",ltime);
strcpy(filepath,"SavedData\\");
strcat(filename,thistime);
strcat(filename,".zsz");
strcat(filepath,filename);
dumpfile=pcap_dump_open(adhandle,filepath);
if(dumpfile==NULL)
{
MessageBox(_T("文件创建错误!
"));
return-1;
}
pcap_freealldevs(alldev);
/*接收数据,新建线程处理*/
LPDWORDthreadCap=NULL;
m_ThreadHandle=CreateThread(NULL,0,sniffer_CapThread,this,0,threadCap);
if(m_ThreadHandle==NULL)
{
intcode=GetLastError();
CStringstr;
str.Format(_T("创建线程错误,代码为%d."),code);
MessageBox(str);
return-1;
}
return1;
}
数据包处理
DWORDWINAPIsniffer_CapThread(LPVOIDlpParameter)
{
intres,nItem;
structtm*ltime;
CStringtimestr,buf,srcMac,destMac;
time_tlocal_tv_sec;
structpcap_pkthdr*header;//数据
constu_char*pkt_data=NULL,*pData=NULL;//网络中收到的字节流数据
u_char*ppkt_data;
CzszhangDlg*pthis=(CzszhangDlg*)lpParameter;
if(NULL==pthis->m_ThreadHandle)
{
MessageBox(NULL,_T("线程句柄错误"),_T("提示"),MB_OK);
return-1;
}
while((res=pcap_next_ex(pthis->adhandle,&header,&pkt_data))>=0)
{
if(res==0)//超时
continue;
structdatapkt*data=(structdatapkt*)malloc(sizeof(structdatapkt));
memset(data,0,sizeof(structdatapkt));
if(NULL==data)
{
MessageBox(NULL,_T("空间已满,无法接收新的数据包"),_T("Error"),MB_OK);
return-1;
}
//分析出错或所接收数据包不在处理围
if(analyze_frame(pkt_data,data,&(pthis->npacket))<0)
continue;
//将数据包保存到打开的文件中
if(pthis->dumpfile!
=NULL)
{
pcap_dump((unsignedchar*)pthis->dumpfile,header,pkt_data);
}
//更新各类数据包计数
pthis->sniffer_updateNPacket();
//将本地化后的数据装入一个链表中,以便后来使用
ppkt_data=(u_char*)malloc(header->len);
memcpy(ppkt_data,pkt_data,header->len);
pthis->m_localDataList.AddTail(data);
pthis->m_netDataList.AddTail(ppkt_data);
/*预处理,获得时间、长度*/
data->len=header->len;//链路中收到的数据长度
local_tv_sec=header->ts.tv_sec;
ltime=localtime(&local_tv_sec);
data->time[0]=ltime->tm_year+1900;
data->time[1]=ltime->tm_mon+1;
data->time[2]=ltime->tm_mday;
data->time[3]=ltime->tm_hour;
data->time[4]=ltime->tm_min;
data->time[5]=ltime->tm_sec;
/*为新接收到的数据包在listControl中新建一个item*/
buf.Format(_T("%d"),pthis->npkt);
nItem=pthis->m_listCtrl.InsertItem(pthis->npkt,buf);
/*显示时间戳*/
timestr.Format(_T("%d/%d/%d%d:
%d:
%d"),data->time[0],
data->time[1],data->time[2],data->time[3],data->time[4],data->time[5]);
pthis->m_listCtrl.SetItemText(nItem,1,timestr);
/*显示长度*/
buf.Empty();
buf.Format(_T("%d"),data->len);
pthis->m_listCtrl.SetItemText(nItem,2,buf);
/*显示源MAC*/
buf.Empty();buf.Format(_T("%02X-%02X-%02X-%02X-%02X-%02X"),data->ethh->src[0],data->ethh->src[1],
data->ethh->src[2],data->ethh->src[3],data->ethh->src[4],data->ethh->src[5]);
pthis->m_listCtrl.SetItemText(nItem,3,buf);
/*显示目的MAC*/
buf.Empty();
buf.Format(_T("%02X-%02X-%02X-%02X-%02X-%02X"),data->ethh->dest[0],data->ethh->dest[1],
data->ethh->dest[2],data->ethh->dest[3],data->ethh->dest[4],data->ethh->dest[5]);
pthis->m_listCtrl.SetItemText(nItem,4,buf);
/*获得协议*/
pthis->m_listCtrl.SetItemText(nItem,5,CString(data->pktType));
/*获得源IP*/
buf.Empty();
if(0x0806==data->ethh->type)
{
buf.Format(_T("%d.%d.%d.%d"),data->arph->ar_srcip[0],
data->arph->ar_srcip[1],data->arph->ar_srcip[2],data->arph->ar_srcip[3]);
}elseif(0x0800==data->ethh->type){
structin_addrin;
in.S_un.S_addr=data->iph->saddr;
buf=CString(inet_ntoa(in));
}elseif(0x86dd==data->ethh->type){
intn;
for(n=0;n<8;n++)
{
if(n<=6)
buf.AppendFormat(_T("%02x:
"),data->iph6->saddr[n]);
else
buf.AppendFormat(_T("%02x"),data->iph6->saddr[n]);
}
}
pthis->m_listCtrl.SetItemText(nItem,6,buf);
/*获得目的IP*/
buf.Empty();
if(0x0806==data->ethh->type)
{
buf.Format(_T("%d.%d.%d.%d"),data->arph->ar_destip[0],
data->arph->