开发基于winPcap的嗅探器.
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
网络安全课程设计报告(2015-2016 第一学期)
题目开发基于winPcap的嗅探器
专业
学号姓名
指导教师
日期
评
分分
细
评分项优秀良好中等差遵守机房规章制度
实验原理分析与设计
课题功能实现情况
设计验收与答辩
课程设计报告书写
简
短
评
语
教师签名:
年月日评
分
等
级
备
注
开发基于winPcap的嗅探器
一、实验目的
开发一个winpcap的嗅探器,用它来捕获所有流经网卡的数据包,并进行分析。
二、实验环境
操作系统:Windows 2000/XP
编程环境:Visual c++6.0
附加库:Winpcap
三、实验内容和要求
内容:所开发的程序可以输出本机所有网卡的信息和捕获流经网卡的数据包并能够过滤出IP、TCP、UDP、ICM P等数据包
要求:掌握基于WinPcap的网络编程模式。
理解并能应用WinPcap设计并实现网络数据包的捕获与解析。
四、实验原理和步骤
原理:我们所要做的嗅探器是一种常用的网络数据收集软件,它是在广播式网络环境下利用计算机网络接口截获目的地为其它计算机的数据报文的一种工具。
在以太网中,信息是以明文的形式在网络上传输 ,当将网络适配器设置为混杂模式时,由于采用以太网广播信道争用的方式,使得监听系统与正常通信的网络能够并联连接,并可以捕获任何一个在同一冲突域上传输的数据包。
IEEE802.3标准的以太网采用的是持续CSMA的方式,正是由于以太网采用这种广播信道争用的方式,使得各个站点可以获得其他站点发送的数据。
运用这一原理使信息捕获系统能够拦截我们所要的信息,这是捕获数据包的物理基础。
首先,抓包系统必须绕过操作系统的协议栈来访问在网络上传输的原始数据包,这就要求一部分运行在操作系统核心内部,直接与网络接口驱动交互。
这个部分是系统依赖的,在Winpcap的解决方案里它被认为是一个设备驱动,称作NPF(Netgroup PacketFilter)。
Winpcap提供了两个不同的库:Packet.dll和Wpcap.dll。
Wpcap.dll提供了更加友好、功能更加强大的函数调用。
WinPcap的优势在于提供了一套标准的抓包接口,与libpcap兼容,可使得原来许多UNIX平台下的网络分析工具快速移植过来,便于开
发各种网络分析工具,充分考虑了各种性能和效率的优化,包括对于NPF内核层次上的过滤器支持,支持内核态的统计模式,提供了发送数据包的能力。
前者提供了一个底层API,伴随着一个独立于Microsoft操作系统的编程接口,这些API可以直接用来访问驱动的函数;后者导出了一组更强大的与libpcap一致的高层抓包函数库(captureprimitives)。
这些函数使得数据包的捕获以一种与网络硬件和操作系统无关的方式进行。
网络嗅探器工作在网络环境的底层,拦截所有正在网络上传送的数据,并且通过相应的解析处理,可以实时分析这些数据的内容,进而分析所处的网络状态和整体拓扑布局。
步骤:程序所实现嗅探器的总体结构
本机网卡信息描述
跳转到选择的网卡
选择过滤包类型(ip/tcp/udp/icmp)
开始嗅探
嗅探内容显示并分析
1.获得本地网络网卡列表
获取一个已经绑定的网卡列表,然后Winpcap对捕获网络数据端口进行设定。
通过pcap引擎找出并设定监听的网络接口。
Winpcap提供了pcap_findalldevs_ex()函数,这个函数返回一个指向pcap_if结构的链表,其中的每一项都包含了一个己经绑定的适配器(网卡)的全部信息。
其中name和description这两项分别包含了相应设备的名称和描述。
取得网卡列表后就在屏幕上显示出来,如果网卡没有被发现就显示有关错误,pcap_findalldevs()同其他的libpcap函数一样有一个errbuf参数,当有异常情况发生时,这个参数会被pcap填充为某个特定错误字串。
部分主要程序示意如下:
①主函数部分:
// 获取网卡列表
if(pcap_findalldevs(&alldevs, errbuf) == -1)
{ fprintf(stderr,"pcap_findalldevs发生错误: %s\n", errbuf);
exit(1);}
// 输出网卡信息
for(i=0,d=alldevs; d; d=d->next,i++)
{ ifprint(d,i+1)}
if(i==0)
{ printf("\n没有找到任何网卡,请确认Winpcap已经安装.\n");
return -1;}
②调用函数部分:
// 输出网卡信息
void ifprint(pcap_if_t *d, int num)
{pcap_addr_t *a;
printf("\n\n************网卡%d信息************\n",num);
// 输出网卡名称
printf("网卡名: %s \n",d->name);
// 网卡描述信息
if (d->description)
{ printf("网卡描述: %s \n",d->description);}
// 反馈
printf("反馈: %s \n",(d->flags & PCAP_IF_LOOPBACK)?"yes":"no"); // IP地址
for(a=d->addresses;a;a=a->next)
{ switch(a->addr->sa_family)
{ case AF_INET:
printf("IP地址类型: AF_INET\n");//打印网络地址类型
if (a->addr)//打印IP地址
printf("IP地址: %s\n",
iptos(((struct sockaddr_in *)a->addr)->sin_addr.s_addr));
if (a->netmask)//打印掩码
printf("掩码: %s\n",
iptos(((struct sockaddr_in *)a->netmask)->sin_addr.s_addr));
if (a->broadaddr)//打印广播地址
printf("广播地址: %s\n",
iptos(((struct sockaddr_in *)a->broadaddr)->sin_addr.s_addr));
if (a->dstaddr)//目的地址
printf("Destination Address: %s\n",
iptos(((struct sockaddr_in *)a->dstaddr)->sin_addr.s_addr));
break;
default:
printf("Address Family Name: Unknown\n");
break; }}}
2.选择一个网卡准备获取数据包:
获得网卡的信息后就可以算则其中一个网卡打开准备接受数据包。
打开网卡的功能是通过pcap_open_ live()来实现的。
它的函数原型定义如下: pcap_t3pcap_open_live(char3device,intsnaplen,intpromisc,intto_ms,char3ebuf) 在正常情况下网卡只接受去往它的包而去往其他主机的数据包则被忽略,相反当网卡处于混杂模式时它将接收所有的流经它的数据包,这就意味着在共享介质的情况下可以捕获到其它主机的数据包。
大部分的包捕获程序都将混杂模式设为默认。
部分主要代码如下:
// 打开网卡设备
if ((adhandle= pcap_open_live(d->name,// 设备名称
65536,// 捕获全部的数据包
1,// 设置网卡为混杂模式
1000,// 读超时为1秒
errbuf// 错误缓存
)) == NULL)
{fprintf(stderr,"\n不能打开网卡. %s 不被Winpcap支持\n");
// 释放设备列表
pcap_freealldevs(alldevs);
return -1;}
// 检测链接层,只支持以太网模式
if(pcap_datalink(adhandle) != DLT_EN10MB)
{fprintf(stderr,"\n此程序只能运行在以太网上.\n");
// 释放设备列表
pcap_freealldevs(alldevs);
return -1;}
if(d->addresses != NULL)
{// 返回接口的第一个地址的掩码
netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;}
else
{// 如果没有掩码,则默认设置为C类
netmask=0xffffff;}
3.选择一个过滤包类型(数据包的过滤设定)
通过设置数据流过滤规则(filter)来实现。
数据包过滤处理是嗅探技术中的难点和重点,Win2 pcap提供了最强大的数据流过滤引擎。
它采用了一种高效的方法来捕获网络数据流的某些数据且常常和系统的捕获机制相集成。
过滤数据的函数是pcap-compile()和pcap_setfilter()来实现的。
部分主要程序代码如下;
// 选择过滤包类型
int protocol_type; // 0->ip 1->tcp 2->udp 3->icmp
printf("\n请选择监听的数据包协议类型(0->ip 1->tcp 2->udp 3->icmp) : ");
scanf("%d",&protocol_type);
switch(protocol_type)
{case 0:
strcpy(packet_filter,"ip");
break;
case 1:
strcpy(packet_filter,"ip and tcp");
break;
case 2:
strcpy(packet_filter,"ip and udp");
break;
case 3:
strcpy(packet_filter,"ip and icmp");
break;
default:
break;}
// 编译过滤器
if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 )
{ fprintf(stderr,"\n不能编译过滤器. 请检测语法.\n");
// 释放设备列表
pcap_freealldevs(alldevs);
return -1;}
//设置过滤器
if (pcap_setfilter(adhandle, &fcode)<0)
{ fprintf(stderr,"\n设置过滤器出错.\n");
pcap_freealldevs(alldevs);
return -1;
}
4.捕获所选择的数据包
使用pcap_next_ex()从网络接口中读取一个数据包,该函数第一个参数是接口句柄,后两个参数由函数返回,分别为数据包的相关信息和数据包本身。
函数返回1表示正常接收一个数据包,返回0表示超时,-1表示发生错误。
每捕获到一个数据包,就调用PacketHandler()函数对数据包进行后续解析处理。
部分主要程序代码如下:
①主函数代码:
//循环捕获数据包
while((res=Pcap_next_ex(adhandle,&header,&Pkt--data))>=0)
{//接收超时继续循环
if(res==0)continue;
//处理收到的数据包
PacketHandler();}
②调用函数代码:
// 包处理回调函数,对于每个嗅探到的数据包
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) {ip_header *ih;
u_int ip_len;
// 返回IP首部的位置
ih = (ip_header *) (pkt_data +
14); //以太网的首部长度是14
// IP首部长度
ip_len = (ih->ver_ihl & 0xf) * 4;
printf("%s ",check_protocol(ih->proto));
// 输出源地址IP和目的地址IP
printf("%d.%d.%d.%d -> %d.%d.%d.%d ",
ih->saddr.byte1,
ih->saddr.byte2,
ih->saddr.byte3,
ih->saddr.byte4,
ih->daddr.byte1,
ih->daddr.byte2,
ih->daddr.byte3,
ih->daddr.byte4
);
decode_ip((char*)(pkt_data+14+ip_len),ih->proto);
printf("\n"); }
// 协议识别函数
char *check_protocol(int iProtocol)
{for(int i=0; i<MAX_PROTO_NUM;i++)
{// 如果找到对应的子协议,则返回名称
if(ProtoMap[i].ProtoNum == iProtocol)
{return ProtoMap[i].ProtoText;}
}
return "";}
// TCP解包函数
int decode_tcp(char *tcpbuf)
{
tcp_header *ptcpheader;
int i;
// 转换成TCP首部格式
ptcpheader = (tcp_header*)tcpbuf;
// 输出源端口和目的端口
printf(" Port : %d-->%d ",ntohs(ptcpheader->th_sport),ntohs(ptcpheader->th_dport)); unsigned char FlagMask = 1;
// 输出标志位
for(i=0;i<6;i++)
{if((ptcpheader->th_flag) & FlagMask)
{printf("%c",TcpFlag[i]);}
else
{printf("-");}
FlagMask = FlagMask<<1;
}
return true;}
// UDP 解包函数
int decode_udp(char *udpbuf)
{ udp_header *pudpheader;
pudpheader = (udp_header *)udpbuf;
// 输出端口和数据长度
printf(" Port : %d-->%d",ntohs(pudpheader->sport),ntohs(pudpheader->dport)); return true;
}
// ICMP 解包函数
int decode_icmp(char *icmpbuf)
{ icmp_header *picmpheader;
picmpheader = (icmp_header *)icmpbuf;
// 输出ICMP数据包类型、ID和SEQ
printf(" Type : %d,%d",picmpheader->i_type,picmpheader->i_code);
printf(" ID = %d SEQ = %d",picmpheader->i_id,picmpheader->i_seq);
return true;
}
// IP解包函数
int decode_ip(char *ipbuf, int protocol)
{ switch(protocol)
{ case IPPROTO_TCP: // TCP类型数据包
decode_tcp(ipbuf);
break;
case IPPROTO_UDP: // UDP类型数据包
decode_udp(ipbuf);
break;
case IPPROTO_ICMP: // ICMP类型数据包
decode_icmp(ipbuf);
break;
default:
break; }
return true; }
五、结果测试与分析
1.本机中所以网卡信息如图所示:本台计算机有两新虚拟机,所以网卡2和网卡4是虚
拟机网卡信息,网卡3为当前本机网卡信息,所以以下抓包情况都为在网卡3上进行
2.选择网卡和数据包协议类型:
所抓的TCP数据包里的信息有数据包的类型说明、源ip、目的ip、源端口号、目的端口号和标志位
所抓UDP数据包里有和上面一样有数据包的类型说明、源ip、目的ip、源端口号、目的端口号
这里面存在一些问题,所捕获的数据包里有些目的地址和源地址已经超出了本以太网所在的范围,有些端口号也发生了错误,检查后并没有找出问题所在,所以这方面还不够了解,以后还有待学习认识。
所抓的ICMP数据包内容有数据包的类型说明、源ip、目的ip、Type为ICMP的8位类型和8位代码,ID为识别号,SEQ为报文序列号
六、存在的问题
我们最终展现的程序运行是到捕获数据包结束的,并没有像wireshark中有对每个数据包的具体分析,这方面的功能还有待实现,同时如果我们有时间还想更加完善这个嗅探器,也可以把它向wireshark这个成品的软件靠拢,可以用windows编程实现对界面的设置,当然这方面我们并没有学,在以后还要多加学习这方面的内容才行。
七、总结
这次实验是开发基于winpcap的嗅探器,这与我们网络安全设计中的wireshark的软件功能贴近,由于有过这方面抓包的实际操作,所以我们拿到课题时很清楚的知道自己要设计的方向是什么,其中数据库的使用对我们来说比较新,我们要从网上查找相应的资料来学会如何在代码中链入数据库文件以及一些它们的功能调用。
其实在代码中的一些细节部分,像ip、tcp、udp、icmp这些数据包的结构组成设计需要我们清楚的掌握并应用计算机网络中学到的东西,这让我们复习了知识的同时更加深了对这些内容的理解与掌握,让我们在这次实验周的实验中收获更多。
八、参考文献
1.谢希仁.计算机网络第五版
2.Willan Stallings.网络安全基础应用与标准
3.谢小特,王勇军.基于Winpcap的捕包程序设计
4.胡晓元,史浩山.Winpcap包截获系统的分析及其应用
5.庄春兴,彭奇志.基于Winpcap的网络嗅探程序设计。