网络安全课程设计C#制作sniffer资料Word文件下载.docx
《网络安全课程设计C#制作sniffer资料Word文件下载.docx》由会员分享,可在线阅读,更多相关《网络安全课程设计C#制作sniffer资料Word文件下载.docx(32页珍藏版)》请在冰点文库上搜索。
随着计算机网络技术的快速发展,网络己成为人们生活中的必备工具,计算机网络在政治、经济、军事、社会生活等各个领域正发挥着日益重要的作用,人们对计算机网络的依赖性也大大增强,一些网络新业务如电子商务、移动支付等,这些都对网络安全提出了较高的要求。
但是由于计算机网络具有连接形式多样性、开放性、互联性等特点,而且多数都采用TCP/TP协议,而TCP/TP在设计上力求运行效率,并建立在相互信任的基础上,其本身就是造成网络不安全的主要因素,这也是TCP/TP协议在设计上的缺陷,从而导致针对网络系统的攻击事件频繁发生,所以网络安全已成为网络建设的一个非常重要的方面。
现在人们对计算机信息安全要求越来越高,随着计算机网络的资源共享进一步加强,随之而来的网络安全问题使得计算机网络安全保护将会变得越来越重要。
所以当我们在享受网络所带来的方便和快捷的同时也要认识到网络安全所面临的严峻考验。
在防范网络攻击方面,通过数据截取及分析输出结果可以捕获到透过防火墙而进入网络的非法数据,成功的监视记录黑客的入侵过程,保障网络的安全。
而且数据截取和协议分析是入侵检测系统的重要部分,是入侵检测系统的最基础的环节。
二、需求分析
2.1需求分析
实现Sniffer的基本功能。
Sniffer是一种用于监测网络性能、使用情况的工具。
能够侦听所有进出本主机的数据包,完整显示数据包网络层和传输层(ICMP、IP、TCP和UDP)的头信息。
比如,对IP头而言,需要显示版本、头长度、服务类型、数据包长度、标识、DF/MF标志、段内偏移、生存期、协议类型、源目的IP地址、选项内容。
要求显示数据的实际含义;
侦听来源于指定IP地址的数据,显示接收到的TCP数据包的全部实际内容。
需要考虑一个TCP包划分为多个IP包传输的情况;
功能验证手段:
在运行Sniffer的同时,执行标准的Ping、Telnet和浏览网页等操作,检查Sniffier能否返回预期的结果。
2.2功能分析
有于水平有限,不可能实现Sniffer或者wireshark那样复杂的设置和分析,所以我们只对抓取到的本机在网络中的通信数据(如协议类型,源、目的地址和端口、数据包的大小等)加以分析,实现一个简单的网络嗅探器。
一个窗体显示主页面,另一个页面显示详细的包信息。
详细信息页面,我们显示一下信息:
开始时间:
嗅探器抓取数据包的时间;
源端口:
源目的IP地址+端口号;
目的端口:
目的IP地址+端口号;
协议类型:
只分析一下类型,GPG,ICMP,IDP,IGMP,IP,ND,PUP,TCP,UDP,其他的不再分析;
抓包时间:
;
报头大小:
报文报首部大小;
报文总长:
整个数据报的大小;
三、概要设计
3.1功能图
数据包的显示
混杂模式的开启及套接字的调用
网卡信息的获取及本机IP的获取
数据包的过滤及显示
数据包的日志文件保存
数据包的捕获
图1网络嗅探器的功能结构图
3.2设计界面
工具:
Visualstudio2013
使用编程语言:
C#窗体编程
Button类实现的功能有:
开始,暂停,清除信息,显示所有信息,保存日志文件、过滤抓包信息
Textbox:
显示本机IP地址、输入IP地址用来过滤出所需的抓包信息
Listview:
显示抓包的详细信息,包括源IP,源端口,目的IP,目的端口,传输协议类型,时间,总长度,抓包信息显示
Richtextbox:
显示抓包的具体内容
Lable标签:
解释信息,显示具体的接收信息和抓包长度,做注释用
具体控件的定义
privateSystem.Windows.Forms.CheckBoxfilterCheckBox;
privateSystem.Windows.Forms.ButtonstartButton;
privateSystem.Windows.Forms.ButtonstopButton;
privateSystem.Windows.Forms.ToolTiptoolTip1;
privateSystem.Windows.Forms.TextBoxipTextBox;
privateSystem.Windows.Forms.LabelhintLabel;
privateMyButtonclearButton;
privateSystem.Windows.Forms.BindingSourcepacketBindingSource;
privateSystem.Windows.Forms.ListViewlistView;
privateColumnHeaderheader;
privateColumnHeadercolumnHeader1;
privateColumnHeadercolumnHeader2;
privateColumnHeadercolumnHeader3;
privateColumnHeadercolumnHeader4;
privateColumnHeadercolumnHeader5;
privateColumnHeadercolumnHeader6;
privateColumnHeadercolumnHeader7;
privateColumnHeadercolumnHeader8;
privateComboBoxtypeComboBox;
privateMyRichTextBoxhexTextBox;
privateMyRichTextBoxcharTextBox;
privateButtonallButton;
privateButtonfilterButton;
privateToolTiptoolTip2;
privateToolTiptoolTip3;
privateLabellabel1;
privateLabellabel2;
privateTextBoxtextBox1;
privateRichTextBoxrichTextBox1;
privateButtonbutton1;
privateLabellabel3;
privateButtonToolStripMenuItem;
四、详细设计与实现
4.1文字介绍实现的方法
具体到编程实现上,这种对网卡混杂模式的设置是通过原始套接字(rawsocket)来实现的,这也有别于通常经常使用的数据流套接字和数据报套接字。
在创建了原始套接字后,需要通过setsockopt()函数来设置IP头操作选项,然后再通过bind()函数将原始套接字绑定到本地网卡。
为了让原始套接字能接受所有的数据,还需要通过ioctlsocket()来进行设置,对数据包的获取仍象流式套接字或数据报套接字那样通过recv()函数来完成。
但是与其他两种套接字不同的是,原始套接字此时捕获到的数据包并不仅仅是单纯的数据信息,而是包含有IP头、TCP头等信息头的最原始的数据信息,这些信息保留了它在网络传输时的原貌。
通过对这些在低层传输的原始信息的分析可以得到有关网络的一些信息。
由于这些数据经过了网络层和传输层的打包,因此需要根据其附加的帧头对数据包进行分析。
4.1.1程序流程图
图2嗅探器工作流程
如图2所示,在利用套接字开发网络嗅探器程序时的一般步骤是:
首先,创建原始套接字,并设置其操作选项;
其次将原始套接字绑定到本地网卡地址上;
设置网卡为混杂模式,这样网卡就可以收到任何在网络中传输的数据包;
在以上条件下开始对数据包进行捕获、分析。
4.1.2关键技术
(1)socket创建
网络嗅探器作为一种网络通讯程序,是通过对网卡的编对网卡的编程是使用Socket函数来实现的。
是引用网络连接的特殊的文件描述符,是在客户和服务器之间通信的实体。
当客户连接到服务器时,就会有两socket:
客户方socket和对应的服务器端的套接字,这里将它们称作CLIENTSOCK和SERVERSOCK。
当客户方在CLIENTSOCK使用send()函数时,服务器方可以在SERVERSOCK上使用recv()函数来获取客户方发送的数据。
反之亦然。
socket由三个基本要素组成:
网络类型、数据传输类型、采用的网络协议。
socket编程是网络编程的核心。
以下是创建socket的代码:
SOCKET
conn;
Conn=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(conn=INVAILD_SOCKET);
return;
原始socket是允许访问底层传输协议的一种socket类型。
使用原始socket操作IP数据报,可以进行路由跟踪、Ping等。
另外,使用原始socket需要知道许多下层协议结构的知识。
原始socket有两种类型,第一种类型是在IP头中使用预定义的协议,ICMP;
如第二种类型是在IP头中使用自定义的协议[17]~[18]。
(2)数据类型分析
套接字程序接收到IP数据包之后,调用自定义函数DecodeIPPacket进行解析。
这个函数萃取出数据包中的协议头,向用户输出协议信息。
即在设置SIO_RCVALLioctl之后,在原始套接字上对recv/WSARecv的调用将返回IP数据报,其中包含了完整的IP头,头后面IP可能是UDP头,也可能是TCP头,这要看发送封包用户所使用的协议了。
数据从应用层到达传输层时,将添加TCP数据段头或者是UDP数据段头。
下面分别给出TCP数据包结构和UDP数据包结构。
其中TCP数据头比较麻烦,它以20个固定字节开而始,在固定头后面还可以有一些长度不固定的可选项。
UDP的数据段头相对来讲比较简单,它由8字节的头和数据部分组成。
此外,从封包中萃取出TCPHeader或UDPHeader之后,还可以根据目的端口号进一步分析用户在应用层使用协议类型,例如目的的端口号为25,则说明使用的是SMTP,端口号为110,则说明使用的是POP3。
4.2具体界面展示及运行结果
图3网络嗅探器的整体界面
图4开始抓包
图5双击鼠标显示抓包详细信息
图6通过源IP过滤抓包
图7通过目的IP抓包
图8清除所有抓包信息
图9保存抓包日志文件
图10打开抓包日志文件
4.3关键代码
(1)数据包的捕获
classMonitor//记录
{
privateconstintSECURITY_BUILTIN_DOMAIN_RID=0x20;
privateconstintDOMAIN_ALIAS_RID_ADMINS=0x220;
privateconstintIOC_VENDOR=0x18000000;
privateconstintIOC_IN=-2147483648;
//0x80000000;
privateconstintSIO_RCVALL=IOC_IN|IOC_VENDOR|1;
privateconstintBUF_SIZE=1024*1024;
//设置缓冲区大小保存抓包文件
privateSocketmonitor_Socket;
//监控函数套接字
privateIPAddressipAddress;
//获取IP
privatebyte[]buffer;
//缓冲区
publicMonitor(IPAddressip)
this.ipAddress=ip;
this.buffer=newbyte[BUF_SIZE];
//缓冲区的大小
}
~Monitor(){
stop();
publicvoidstart()//定义的开始基类
if(monitor_Socket==null)
try
if(ipAddress.AddressFamily==AddressFamily.InterNetwork)
monitor_Socket=newSocket(AddressFamily.InterNetwork,SocketType.Raw,System.Net.Sockets.ProtocolType.IP);
}
else
monitor_Socket=newSocket(AddressFamily.InterNetworkV6,SocketType.Raw,System.Net.Sockets.ProtocolType.IP);
monitor_Socket.Bind(newIPEndPoint(ipAddress,0));
monitor_Socket.IOControl(SIO_RCVALL,BitConverter.GetBytes((int)1),null);
monitor_Socket.BeginReceive(buffer,0,buffer.Length,SocketFlags.None,newAsyncCallback(this.OnReceive),null);
catch(Exceptione)
monitor_Socket.Close();
monitor_Socket=null;
Console.WriteLine(e.ToString());
publicvoidstop()
if(monitor_Socket!
=null)
privatevoidOnReceive(IAsyncResultar)//返回值处理
intlen=monitor_Socket.EndReceive(ar);
if(monitor_Socket!
byte[]receivedBuffer=newbyte[len];
Array.Copy(buffer,0,receivedBuffer,0,len);
Packetpacket=newPacket(receivedBuffer);
OnNewPacket(packet);
catch(ArgumentNullExceptionane)
Console.WriteLine(ane.ToString());
catch(ArgumentExceptionae)
Console.WriteLine(ae.ToString());
catch
stop();
protectedvoidOnNewPacket(Packetp)
if(newPacketEventHandler!
newPacketEventHandler(this,p);
publiceventNewPacketEventHandlernewPacketEventHandler;
publicdelegatevoidNewPacketEventHandler(Monitormonitor,Packetp);
///<
summary>
///检查当前用户是否是管理员;
/summary>
returns>
<
/returns>
privateboolIsUserAnAdmin()
WindowsIdentityidentity=WindowsIdentity.GetCurrent();
WindowsPrincipalprincipal=newWindowsPrincipal(identity);
returnprincipal.IsInRole(WindowsBuiltInRole.Administrator);
[DllImport("
advapi32.dll"
)]
privateexternstaticintAllocateAndInitializeSid(byte[]pIdentifierAuthority,bytenSubAuthorityCount,intdwSubAuthority0,intdwSubAuthority1,intdwSubAuthority2,intdwSubAuthority3,intdwSubAuthority4,intdwSubAuthority5,intdwSubAuthority6,intdwSubAuthority7,outIntPtrpSid);
privateexternstaticintCheckTokenMembership(IntPtrTokenHandle,IntPtrSidToCheck,refintIsMember);
privateexternstaticIntPtrFreeSid(IntPtrpSid);
(2)数据包的显示
在richtextbox中显示抓包信息:
privatevoidallButton_Click(objectsender,EventArgse)
this.listView.Items.Clear();
pList.Clear();
Packetp;
for(inti=0;
i<
allList.Count;
i++)
p=allList[i];
pList.Add(p);
this.listView.Items.Add(newListViewItem(newstring[]{p.Src_IP,p.Src_PORT,p.Des_IP,p.Des_PORT,
p.Type,p.Time,p.TotalLength.ToString(),p.getCharString()}));
clearDetail();
MessageBox.Show("
已重新加载信息!
"
);
在listview中显示抓包的情况:
privatevoidlistView_SelectedIndexChanged(objectsender,EventArgse)//抓包信息显示部分
ListViewlistView=senderasListView;
if(listView.SelectedItems!
=null&
&
listView.SelectedItems.Count!
=0)
Packetp=pList[listView.SelectedItems[0].Index];
//MessageBox.Show("
charLength:
+p.getCharString().Length+"
\n"
+"
hexLength:
+p.getHexString().Length);
this.hexTextBox.Text=p.getHexString();
this.charTextBox.Text=p.getCharString();
publicclassPacket//定义抓包的类型,包括抓包的协议类型,总长度,抓包的信息
privateconstintLineCount=30;
///使用枚举来标识协议类型;
enumProtocolType
GGP=3,
ICMP=1,
IDP=22,
IGMP=2,
IP=4,
ND=77,
PUP=12,
TCP=6,
UDP=17,
OTHERS=-1
///原始数据包对底层;
privatebyte[]raw_Packet;
///嗅探的时间;
privateDateTimedateTime;
///抓包的协议类型;
privateProtocolTypeprotocolType;
//抓包的协议类型
privateIPAddresssrc_IPAddress;
//源IP地址
privateIPAddressdes_IPAddress;
//目的IP地址
privateintsrc_Port;
//源端口
privateintdes_Port;
//目的端口
privateinttotalLength;
//包的总长度
privateintheadLength;
//头的长度
//尽用于测试
publicintHeadLength
get