282_半打开的端口扫描
1.无需注册登录,支付后按照提示操作即可获取该资料.
2.资料以网页介绍的为准,下载后不会有水印.资料仅供学习参考之用.
密 惠 保
1.6 端口扫描实现方法
本文通过对基于半打开的端口扫描技术的实现来介绍了现在一些主流的端口扫描技术,通过对程序的开发加深了对端口扫描技术的认识。经过对端口扫描技术的了解和认识,本文采用隐蔽性较好基于主机的SYN刺探技术来实现。
2 需求分析
2.1 端口扫描器的总体要求
2.1.1 设计背景
该端口扫描器是面向普通用户使用,以期成为一个普通用户用来检测端口网络主机端口并有效地保护自己。在采用SYN刺探方式进行扫描的基础上成为一个基于半打开的实用、简单、方便的端口扫描工具。
2.1.2 用户特点
由于该端口扫描系统是一个基于半打开的端口扫描器,其面向的是普通的对于端口扫描有需求的用户,因此需要提供一个简洁、方便、高效的界面和功能。
2.1.3 软件开发及运行环境
系统开发工具:Visual C++ 6.0
2.2 端口扫描器的需求分析
端口扫描器的一般需求:
(1)隐蔽性需求
作为扫描的一方来说,端口扫描除了要能扫出目标主机的端口信息以外,还需要能有一定的隐蔽性,以最大的可能不在目标主机留下访问信息。如果仍然采用基于TCP connect()的扫描则将很容易被目标主机记录,因此从隐蔽性上考虑SYN半打开扫描或者FIN扫描会是很好的选择。 【www.think58.com计算机毕业论文网】 本文来自think58 [资料来源:http://www.THINK58.com]
(2)端口选择需求
当我们在使用扫描软件对目标主机进行扫描的时候,有的时候是有目的性地扫描目标主机的某一个端口,然而在大部分时候却需要扫描批量端口或者是一些重要的指定端口。这个时候需要端口扫描系统具有自定义端口列表的功能。
(3)扫描结果存储需求
在进行完一次端口扫描之后,需要对结果进行保存。无论是攻击还是检测,端口扫描器是需要与其他的一些工具配合到一起使用的,所以要求端口扫描器一定要具有存储结果的功能,以将扫描得到的目标主机端口信息保存下来。
3 端口扫描器的实现
3.1 功能模块简介
所完成的端口扫描器的界面如图1所示,相关功能介绍如下:
图1 端口扫描器功能界面
目标IP范围选择模块:选择起始IP和结束IP以确定目标IP的范围。
端口范围选择模块:自定义起始端口和结束端口以确定扫描范围。
扫描结果存储模块:自定义扫描结果的显示方式,或将扫描结果保存下来。
自定义默认端口列表模块:对默认的重要端口进行添加或删除以更符合扫描需要。
3.2 程序实现流程
程序实现的流程如图2所示:
copyright think58 [来源:http://www.think58.com]
[资料来源:http://www.THINK58.com]
内容来自think58
[资料来源:http://think58.com]
copyright think58
[资料来源:http://THINK58.com]
内容来自think58
[来源:http://think58.com]
[资料来源:http://think58.com]
copyright think58
[资料来源:www.THINK58.com]
本文来自think58
[资料来源:http://www.THINK58.com]
内容来自think58
[来源:http://think58.com]
内容来自think58 [资料来源:www.THINK58.com]
copyright think58
copyright think58 [来源:http://www.think58.com]
内容来自think58
[资料来源:THINK58.com]
[来源:http://think58.com]
图2 程序实现流程图
主函数首先创建一个侦听线程以准备获得返回信息。然后调用FillLocalIP函数将本地IP写入IP列表中,接着读取要扫描的IP和端口,判断是否是本地IP,若是则调用函数scanlocal对本地IP和端口发起连接并获得扫描结果;如果不是本地IP就调用scan函数对远程IP发送SYN包,并通过创建的套接字rawsock得到从系统中返回的信息,分析数据后得到扫描结果。最后将扫描的结果插入结果树中排序并可保存为文本文件。
3.3 SYN探测的实现
定义了一个线程体ScanStart调用其他的函数来实现端口扫描。
(1)DWORD WINAPI ScanStart(LPVOID lpvoid)
{
CDWordArray& CPortList = *lpPortList;
//为侦听线程分配句柄空间
*handle = (HANDLE*)malloc(sizeof(HANDLE)*(numadapter-1));
//为LocalIP分配空间
*lpLocalIP= (ULONG*)malloc(sizeof(ULONG)*numadapter);
HANDLE* hListen=*handle;
//创建侦听线程 每块网卡绑定一个线程
while (InforL.num >=0)
{
hListen[InforL.num]=CreateThread(NULL,0,ListeningFunc,&InforL,NULL,NULL); //创建一个嗅包的线程,分析接收到的包。
if ( hListen[InforL.num] == NULL ) think58.com [资料来源:http://www.THINK58.com]
{
AfxMessageBox("创建侦听线程失败!");
}
Sleep(500); //Sleep 0.5s.使ListeningFunc线程初始化完毕.
InforL.num--;
}
pProGressCtrl->SetRange32(0,(EndIP-StartIP+1)*CPortList.GetSize());
// 设置显示扫描进度条的大小
// Fill LocalIP
FillLocalIPList(*lpLocalIP);//获取本地网卡的IP
//这是为了实现监听功能,接受返回的数据包
DWORD* lpLIP = *lpLocalIP;
IPANDPORT lpInfor={0};
lpInfor.hTree=lpTreeCtrl;
int all=0;
int k=1;
int TEMP=StartIP; think58.com
[资料来源:http://www.THINK58.com]
在对IP范围是否符合规则进行判断以后,将端口列表中的端口信息循环读入到lpInfor.PORT中,为即将开始的扫描做准备。
for (StartIP <= EndIP ; StartIP++) //从第一个IP到最后一个IP
{
lpInfor.NETIP=htonl(StartIP);
int Num= CPortList.GetSize();
for ( int i=0 ; i<Num ; i++)
{
//结束线程
if ( ! ::OK )
{
CPortList.RemoveAll(); //清空端口列表
return 0;
}
lpInfor.PORT=(USHORT)CPortList[i];
if ( k % 300 == 0 )
{
//等待监听线程
WaitForMultipleObjects(numadapter-1,hListen,FALSE,DelayTime); k=1;
} else k++; think58.com [资料来源:http://THINK58.com]
对本地IP和目标(非本地)IP的扫描方式是不同的,所以这里需要对获取的IP地址和本地IP地址作比较,通过函数IsLocalIP来实现。
if ( IsLocalIP(lpInfor.NETIP, lpLIP,numadapter) )
scanlocal(&lpInfor); //对本地IP进行扫描
else
{
scan(&lpInfor); //对目标IP,端口发送SYN包.
}
all++;
pProGressCtrl->SetPos(all);
}
} 本文来自think58
[资料来源:http://www.THINK58.com]
(2)扫描程序在开始的时候将LocalIPlist中的IP与scanIP对比,判断待扫描的IP是否是本地IP。因为在程序中对目标IP和本地IP的扫描方式是不一样的,所以需要在这里作出一个判断。
BOOL IsLocalIP(ULONG scanIP, ULONG* LocalIPlist, int num)
{
for (int i=0; i<num ; i++)
{
if (scanIP == LocalIPlist[i])
return TRUE;
}
return FALSE;
}
图3 SYN扫描连接示意图
如图3所示,在半打开扫描技术中,扫描主机自动向目标计算机的指定端口发送SYN数据段,表示发送建立连接请求。如果目标计算机的回应TCP报文中SYN=1,ACK=1,则说明该端口是活动的,接着扫描主机传送一个RST给目标主机拒绝建立TCP连接,从而导致三次握手过程的失败。如果目标计算机的回应是RST,则表示该端口为“死端口”,这种情况下,扫描主机不用做任何回应。由于扫描过程中,全连接尚未建立,所以大大降低了被目标计算机的记录的可能,并且加快了扫描的速度。
(3)在对目标IP进行端口扫描的时候,一方面要考虑到在扫描的时候在目标主机上留下较少的扫描记录,另一方面要能在较小的权限下对目标进行扫描。所以使用发送TCP SYN包的方式来对目标进行扫描。
内容来自think58
[资料来源:http://think58.com]
DWORD WINAPI scan(LPVOID lp)
{
SOCKET sock=NULL;
SOCKADDR_IN addr_in={0}; 本文来自think58
IPANDPORT* lpInfor=(IPANDPORT*)lp; //设置IP地址属性
USHORT port=lpInfor->PORT; //设置扫描的端口
addr_in.sin_family=AF_INET;
addr_in.sin_port=htons(port);
addr_in.sin_addr.S_un.S_addr=lpInfor->NETIP; //设置IP地址 [资料来源:http://www.THINK58.com]
int iErr;
ULONG ul=1;
if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)
{
AfxMessageBox("Socket Setup Error!\n");
}
//大多数扫描技术要发送原始套接字包来进行探测。因为只有原始套接字支持对IP报头的设置,即构造IP数据包。同时,原始套接字也支持发送和接收IP数据包。这样,原始套接字接口实际上成为网络层向上提供的接口。
iErr=ioctlsocket(sock,FIONBIO,(unsigned long*)&ul); //设置sock为非阻塞
if(iErr==SOCKET_ERROR ) //等待错误信息
{
AfxMessageBox("set socket FIONBIO false\n");
} think58.com [资料来源:THINK58.com]
在Windows XP中,程序使用原始套接字构造和发送SYN包。TCP/IP协议栈中不会记录该连接请求,所以对于服务器端返回的SYN|ACK包,TCP/IP协议栈会自动发送RST,不用在程序中实现SYN探测的第二步。
connect(sock,(struct sockaddr *)&addr_in,sizeof(addr_in)); //发送SYN包
//在发送完SYN包以后立即关闭SOCK连接,因为程序无法直接收到返回的信息,返回的数据是到达系统核心,然后通过嗅探抓包的方式获得目标主机返回信息。
closesocket(sock);
return 0;
} think58.com
本文来自think58 [资料来源:www.THINK58.com]
[资料来源:www.THINK58.com]