基于WinPcap的网络嗅探器设计Word文档格式.docx
《基于WinPcap的网络嗅探器设计Word文档格式.docx》由会员分享,可在线阅读,更多相关《基于WinPcap的网络嗅探器设计Word文档格式.docx(18页珍藏版)》请在冰豆网上搜索。
4.2设计程序对话框10
4.3在的初始化对话框函数OnInitDialog()中添加列表控件的初始化:
11
4.4TCPconnect()扫描13
4.4UDP扫描:
14
4.41UDP相关代码截图:
15
5运行结果16
结论18
参考文献18
摘要
计算机信息网络的发展加速了信息化时代的进程,但是随着社会网络化程度的增加,对计算机网络的依赖也越来越大,网络安全问题也日益明显。
端口扫描技术是发现安全问题的重要手段之一。
本程序是在Windows系统中使用C语言用MFC完成的一个端口扫描程序。
此程序主要完成了TCPconnect()扫描和UDP扫描功能。
TCP扫描支持多线程,能对单个指定的主机进行扫描或对指定网段内的主机进行逐个扫描。
能扫描特定的部分端口号或对指定的端口段内的端口进行逐个扫描。
此端口扫描程序能快速地进行TCP扫描,准确地检测出对TCP协议开放的端口。
而对于UDP扫描只支持单线程,速度较慢。
扫描结果以列表的形式直观地展现出来。
关键词:
端口扫描、TCP、UDP扫描
1引言
1.1课题的背景及意义
网络中每台计算机犹如一座城堡,这些城堡中,有些是对外完全开放的,有些却是大门紧闭的。
入侵者们是如何找到,并打开它们的城门呢?
这些城门究竟通向何处?
在网络中,把这些城堡的“城门”称之为计算机的“端口”。
端口扫描是入侵者搜索信息的几种常用方法之一,也正是这一种方法最容易暴露入侵者的身份和意图。
一般说来,扫描端口有以下目的:
判断目标主机上开放了哪些服务
判断目标主机的操作系统
如果入侵者掌握了目标主机开放了哪些服务,运行何种操作系统,他们就能使用相应的手段实现入侵。
而如果管理员先掌握了这些端口服务的安全漏洞,就能采取有效的安全措施,防范相应的入侵。
1.2端口扫描现状
一个端口就是一个潜在的通信通道,也就是一个入侵通道。
对目标计算机进行端口扫描,能得到许多有用的信息。
扫描器通过选用远程TCP/IP不同的端口的服务,并记录目标给予的回答,通过这种方法,可以搜集到很多关于目标主机的各种有用的信息,从而发现目标机的某些内在的弱点。
2系统设计
2.1系统主要目标
本程序主要实现了:
简易的TCPconnect()扫描,支持多线程;
UDP扫描功能;
能对单个指定的主机进行扫描或扫描指定网段内的主机;
能扫描特定的部分端口号或对指定的端口段内的端口进行逐个扫描;
2.2开发环境及工具
测试平台:
WindowsXPProfessional
使用软件:
VisualC++6.0
开发语言:
C语言
2.3功能模块与系统结构
作为端口扫描程序,首先需要完成的功能就是对于系统操作系统的服务端口进行扫描,返回扫描结果。
对于端口的扫描,包括对于本机系统服务端口,局域网内目标机系统,以及远程IP的系统服务端口进行扫描。
有些时候,用户并不需要去扫描整个系统的所有端口,因为这样的话不仅会浪费大量的时间,而且可能导致难以找到自己需要了解的端口的扫描结果。
所以,对于选择性地对端口进行扫描也非常重要。
这当然也是扫描程序需要实现的功能之一。
用户在等待扫描的时候,往往希望知道它的工作进度。
这样用户可以更好地控制自己的操作。
站在用户的角度思考,设置进度是程序需要完成的,这样就能知道程序扫描的进度。
系统必须提供的服务是功能需求的基本,本着站在用户角度思考的原则,做出如上叙述需求,从简列举如下:
扫描功能;
地址选择功能;
端口选择功能;
端口扫描程序功能模块如下图所示:
3系统功能程序设计
本程序主要实现了简易的TCPconnect()扫描和UDP扫描功能,对TCP扫描支持多线程扫描,UDP扫描仅支持单线程。
TCP服务的网络应用,可以实现顺序、无差错的数据流传输,在通信过程中首先需要建立连接。
端口扫描程序所在的主机是客户机;
被扫描的目的主机是服务器。
图1给出了TCP连接的建立过程。
假设客户机向服务器发送SYN=1、ACK=0的TCP包,表示客户机请求与服务器建立连接;
客户机向服务器返回SYN=1、ACK=1的TCP包,表示服务器同意与客户机建立连接;
客户机再向服务器发送SYN=0、ACK=1的TCP包,表示客户机确认与服务器建立连接(即三次握手的过程)。
图1TCP建立连接的过程
TCP端口扫描采用的是Connect扫描,通过Connect系统调用尝试连接目的主机的端口。
如果这次TCP连接成功建立,说明该端口处于开启状态;
否则,说明该端口处于关闭状态。
Connect扫描的最大优点是原理简单,不需要具有管理员或超级用户权限。
首先,端口扫描程序调用socket()函数建立套接字,SOCK_STREAM表示流式套接字;
其次,调用connect()函数请求与目的主机的指定端口建立连接;
最后,根据TCP连接是否成功建立,判断目的主机中的端口状态。
TCP端口扫描流程
TCP端口扫描的流程如图2所示。
图2
图2给出了TCP端口扫描程序流程图。
第1步,客户机程序会初始化用户界面;
第2步,客户机建立Winsock库绑定关系,并且创建流式或数据报套接字;
第3步,客户机请求与目的主机的端口建立连接;
第4步,客户机根据连接建立情况判断端口状态;
第5步,客户机可能需要断开已经建立的连接;
第6步,客户机释放流式或数据报套接字,并且解除|Winsock库绑定关系。
3.3TCP端口扫描程序代码分析
下面给出的是TCP端口扫描的代码:
//建立与Winsock库的绑定
WSAStartup(MAKEWORD(2,2),&
WSAData);
//创建流式套接字
Socket=socket(AF_INET,SdOCK_STREAM,0);
//判断IP地址或主机名
If(m_Address为IP地址)
hostent*pHostent=gethostbyname(m_Address);
//填充目的主机的套接字地址
sockaddr_inDestHost;
DestHost.sin_port=htons(m_Port);
DestHost.sin_addr.s_addr=m_Address;
//向目的主机请求建立连接
connect(Socket,(sockaddr*)&
serveraddr,sizeof(serveraddr));
If(TCP连接建立)
目的主机的端口开启
断开TCP连接
else
目的主机的端口关闭
//释放流式套接字
closesocket(Socket);
//解除Winsock库的绑定
WSACleanup();
4设计步骤与实现
4.1使用vc++6.0创建一个工程
打开MicrosoftVisualC++6.0编程软件,在新建的向导界面中选择(MFCAppWizard[exe])创建一个基于对话框的工程,该工程的名称为201200824426,如图3所示:
图3创建工程
单击“下一步”按钮,然后选择基于对话框的方式创建应用程序,如图4所示。
图4创建工程201200824426的步骤1
勾选“WindowsSockets”复选框,如图5所示。
图5创建工程201200824426的步骤2
图6创建工程201200824426的步骤3
图7创建工程201200824426的步骤4
4.2设计程序对话框
增添控件,如图8所示。
图8添加对话框控件
在头文件中添加私有成员变量:
SOCKETSocket;
在MFCClassWizard中的MemberVariables中为控件添加变量,如图9所示。
图9为控件创建变量
BOOLCMy201200824426Dlg:
:
OnInitDialog()
{
CDialog:
OnInitDialog();
//Add"
About..."
menuitemtosystemmenu.
//IDM_ABOUTBOXmustbeinthesystemcommandrange.
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);
AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMenu);
}
}
//Settheiconforthisdialog.Theframeworkdoesthisautomatically
//whentheapplication'
smainwindowisnotadialog
SetIcon(m_hIcon,TRUE);
//Setbigicon
SetIcon(m_hIcon,FALSE);
//Setsmallicon
//TODO:
Addextrainitializationhere
LONGlStyle;
lStyle=GetWindowLong(m_list.m_hWnd,GWL_STYLE);
//获取当前窗口style
lStyle&
=~LVS_TYPEMASK;
//清除显示方式位
lStyle|=LVS_REPORT;
//设置style
SetWindowLong(m_list.m_hWnd,GWL_STYLE,lStyle);
//设置style
DWORDdwStyle=m_list.GetExtendedStyle();
dwStyle|=LVS_EX_FULLROWSELECT;
//选中某行使整行高亮(只适用与report风格的listctrl)
dwStyle|=LVS_EX_GRIDLINES;
//网格线(只适用与report风格的listctrl)
m_list.SetExtendedStyle(dwStyle);
//设置扩展风格
CRectrc;
m_list.GetClientRect(rc);
intwidth=rc.Width()/3;
m_list.InsertColumn(0,"
主机地址"
LVCFMT_CENTER,width);
m_list.InsertColumn(1,"
端口号"
m_list.InsertColumn(2,"
端口状态"
returnTRUE;
//returnTRUEunlessyousetthefocustoacontrol
}
4.4TCPconnect()扫描
这是最基本的TCP扫描。
操作系统提供的connect()系统调用,用来与每一个感兴趣的目标计算机的端口进行连接。
如果端口处于侦听状态,那么connect()就能成功。
否则,这个端口是不能用的,即没有提供服务。
这个技术的一个最大的优点是,你不需要任何权限。
系统中的任何用户都有权利使用这个调用。
另一个好处就是速度。
如果对每个目标端口以线性的方式,使用单独的connect()调用,那么将会花费相当长的时间,你可以通过同时打开多个套接字,从而加速扫描。
使用非阻塞I/O允许你设置一个低的时间用尽周期,同时观察多个套接字。
但这种方法的缺点是很容易被发觉,并且被过滤掉。
目标计算机的logs文件会显示一连串的连接和连接是出错的服务消息,并且能很快的使它关闭。
基本原理:
调用connect()函数,根据返回值来判断端口是否打开的,connect()函数返回0说明建立连接成功,说明该端口是打开的,就将该端口保存进静态字符串变量中,然后关闭连接,则线程数减一。
RunThreadNum是用来控制最大线程数量的。
在资源列表中选择对话框,双击按钮TCP,创建响应函数OnTcps(),在函数中添加代码:
voidCMy201200824426Dlg:
OnTcp()
Addyourcontrolnotificationhandlercodehere
UpdateData(true);
//MFC窗口函数,用来刷新数据
intcount=m_list.GetItemCount();
WSADATAWSAData;
if(WSAStartup(MAKEWORD(2,2),&
WSAData)!
=0)
MessageBox("
初始化Winsock失败!
"
);
return;
Socket=socket(AF_INET,SOCK_STREAM,0);
//创建连接套接字
if(Socket==INVALID_SOCKET)
创建Socket失败!
WSACleanup();
intIpAddress;
//判断域名或IP地址
IpAddress=inet_addr(m_Address);
if(IpAddress==INADDR_NONE)
hostent*pHostent=gethostbyname(m_Address);
if(pHostent)
IpAddress=(*(in_addr*)pHostent->
h_addr).s_addr;
}
sockaddr_inDestHost;
//定义套接字地址
memset(&
DestHost,0,sizeof(DestHost));
DestHost.sin_family=AF_INET;
DestHost.sin_port=htons(atoi(m_Port));
DestHost.sin_addr.s_addr=IpAddress;
intnConnect;
//与服务器建立连接
nConnect=connect(Socket,(sockaddr*)&
DestHost,sizeof(DestHost));
if(nConnect!
m_list.InsertItem(count,m_Address);
m_list.SetItemText(count,1,m_Port);
m_list.SetItemText(count,2,"
close"
else
open"
UpdateData(false);
closesocket(Socket);
WSACleanup();
这种方法由于使用的是UDP协议。
由于这个协议很简单,所以扫描变得相对比较困难。
这是由于打开的端口对扫描探测并不发送一个确认,关闭的端口也并不需要发送一个错误数据包。
幸运的是,许多主机在你向一个未打开的UDP端口发送一个数据包时,会返回一个ICMP_PORT_UNREACH错误。
这样就能发现哪个端口是关闭的。
UDP和ICMP错误都不保证能到达,因此这种扫描就不那么可靠。
而且这种扫描方法是很慢的,因为RFC对ICMP错误消息的产生速率做了规定,而且本程序的UDP扫描只支持单线程。
基本原理:
首先使用socket()函数创建套接字,再用bind()函数绑定套接字,然后向扫描的目的主机的目的端口发送UDP数据包,再等待目的主机的目的端口是否返回ICMP_PORT_UNREACH错误数据报,若收到返回的错误数据包,则说明该端口是关闭着的,否则该端口是打开的,再将打开的端口保存进静态数组中,以方便显示结果。
4.41UDP相关代码截图如图10和11。
图10UDP代码
图11
5运行结果
编译后运行,结果如图12所示:
图12运行结果
程序测试,结果如图13所示:
图13测试结果
结论
经过自己近一段时间的努力,设计一个满足基本要求的端口扫描程序。
完成后的程序实现了TCPconnect()扫描和UDP扫描功能,TCP扫描支持多线能对单个指定的主机进行扫描或扫描指定网段内的主机。
能对指定的端口段内的端口进行逐个扫描,或扫描特定的部分端口号,以避免在不需要了解的端口号上浪费时间。
系统设计期间,学习到很多课堂上没有的知识,还积累了很多实践经验,增强了动手能力和解决实际问题的能力。
通过这次的课程设计,对网络编程有了更深入的了解,进一步熟悉了TCP和UDP协议的内容,掌握了TCP、UDP扫描端口和三次握手的过程的基本原理,学会了运用sock套接字构造UDP数据包并发送,以及如何接收ICMP数据包。
对编程思想有了进一步的体会,养成了一些良好的编程习惯。
系统虽然完成,但还有很多不足之处,希望自己能不断学习和实践,争取以后做得更好。
虽然此软件实现了支持TCPconnect()扫描功能,和UDP扫描功能。
但也还有很多不足之处,如扫描功能单一,还需要进一步完善。
限于作者知识水平和经验有限,此程序还有许多有待完善和改正的地方,恳请各位老师和读者批评指正。
参考文献
[1]甘刚、闫丽丽、盛志伟、冼进.Linux/UNIX网络编程.中国水利水电出版社.2008年第1版。
[2]范建华、胥光辉、张涛等译.TCP/IP详解卷1:
协议.机械工业出版社.2009年第1版。
[3]黄维通.VisualC++面向对象与可视化程序设计(第2版).清华大学出版社.2007年第2版
[4]郑莉、董渊、张瑞丰.C++语言程序设计(第3版).清华大学出版社.2004年第3版