构造SYN包,最好选用较大的端口号作为发送端口,以免和应用程序正在使用的端口发生冲突。在这里我们选用的是8288。另外在构造TCP头的时候,还添加了TCP选项SACK,保证TCP连接请求被接受。 http://www.paper51.com addr_in.sin_port=htons(8288);//设置接收的端口为8288 http://www.paper51.com addr_in.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//监听所有的本地IP地址 http://www.paper51.com //对rawsock绑定本机IP和端口,当系统收到目标的返回信息时,便可以通过rawsock传到应用程序当中。 copyright paper51.com intret=bind(rawsock, (struct sockaddr *)&addr_in, sizeof(addr_in)); 内容来自论文无忧网 www.paper51.com
if(ret==SOCKET_ERROR)AfxMessageBox("bind false"); copyright paper51.com 程序使用两次判断来过滤IP包。 paper51.com 首先判断IP头部,要求目的地址是本机、协议号是TCP协议。然后再判断TCP头部,要求目的端口等于选用端口号,控制标志位为SYN|ACK或者RST。因为监听套接字会接收到所有的IP包,要保证能尽快处理分组,如图4所示。 http://www.paper51.com copyright paper51.com 图4 返回IP包的接收及过滤 paper51.com
设置SIO_RCVALL,包括延时和数据大小等信息,以接收所有的数据包。在收到返回信息的时候接受并分析数据包是否为应用程序返回的信息。 http://www.paper51.com
setsockopt(rawsock,SOL_SOCKET,SO_RCVTIMEO,(char *)&settimeout, sizeof(int)); paper51.com DWORDlpvBuffer = 1; http://www.paper51.com DWORDlpcbBytesReturned = 0; paper51.com
//设置一个套接口的模式,接受所有数据 http://www.paper51.com WSAIoctl(rawsock,SIO_RCVALL, &lpvBuffer, sizeof(lpvBuffer), NULL, 内容来自论文无忧网 www.paper51.com 0, &lpcbBytesReturned, NULL,NULL); 内容来自www.paper51.com ******省略部分代码****** copyright paper51.com charRecvBuf[256]={0}; 内容来自www.paper51.com //接收数据包 paper51.com
ret=recvfrom(rawsock,RecvBuf,sizeof(RecvBuf),0,(structsockaddr*)&from,&size); 内容来自论文无忧网 www.paper51.com
if(ret!=SOCKET_ERROR) copyright paper51.com { paper51.com //分析数据包 http://www.paper51.com IPHEADER*lpIPheader; paper51.com lpIPheader=(IPHEADER*)RecvBuf; paper51.com 这里从接受到的数据中分离出IP报头lpIPheader,接着又从IP报头中继续分离出源地址sourceip,并判断源地址是否在起始IP和结束IP的范围内和是否为远程开放端口返回的数据包。 http://www.paper51.com
if(lpIPheader->proto==IPPROTO_TCP&&ntohl paper51.com (lpIPheader->sourceIP)>=StartIP&& ntohl(lpIPheader->sourceIP)<=EndIP) 内容来自论文无忧网 www.paper51.com { copyright paper51.com
char*sourceip=inet_ntoa(* (struct in_addr *)&from.sin_addr); 内容来自论文无忧网 www.paper51.com TCPHEADER*lpTCPheader=(TCPHEADER*)(RecvBuf copyright paper51.com +sizeof(IPHEADER)); 内容来自论文无忧网 www.paper51.com //判断是不是远程开放端口返回的数据包 内容来自论文无忧网 www.paper51.com if(lpTCPheader->th_seq != 0 && lpTCPheader->th_flag==0x12) paper51.com
{ 内容来自www.paper51.com CStringStrIP = sourceip; http://www.paper51.com
******省略部分代码****** paper51.com InsertToTree(hTree,StrIP,CSPort); 内容来自论文无忧网 www.paper51.com
} 内容来自论文无忧网 www.paper51.com } 内容来自www.paper51.com } 内容来自论文无忧网 www.paper51.com } copyright paper51.com
(6)在扫描完成以后,使用函数InsertToTree将结果插入到结果树中hTree,并在结果树中进行排序,使得结果按照选择的方式展开或合拢。 paper51.com
void InsertToTree (CTreeCtrl* hTree,CStringCSIP,CString CSPORT) 内容来自论文无忧网 www.paper51.com
{ 内容来自论文无忧网 www.paper51.com
HTREEITEMA=hTree->InsertItem(CSIP,NULL,TVI_LAST); http://www.paper51.com hTree->InsertItem(CSPORT,A,TVI_LAST); copyright paper51.com } paper51.com 3.4 端口扫描功能模块 http://www.paper51.com
3.4.1 端口选择模块 paper51.com 选择从端口范围或默认端口列表中获取待扫描的端口,首先通过消息传递函数m_IsChecked来判断是否得到了选取端口范围的消息,如果是,则获取起始端口和结束端口的数据并判断起始端口是否不大于结束端口;如果没有传来消息,则尝试调用m_PortListTree.GetNextItem从自定义端口列表树中得到当前所选择的默认端口并从端口列表树中继续获得下一个端口。 paper51.com
copyright paper51.com BOOL CLScanPortDlg::ReadPortToPortList() copyright paper51.com { 内容来自www.paper51.com
UpdateData(); 内容来自www.paper51.com 这里通过m_IsChecked获得选取端口范围的消息,然后就判断端口范围是否符合规则,即起始端口不应该大于结束端口。 copyright paper51.com if( m_IsChecked ) http://www.paper51.com { paper51.com if( m_PortFrom > m_PortTo ) paper51.com { paper51.com AfxMessageBox("起始端口 不应该大于 结束端口!"); 内容来自www.paper51.com returnFALSE; 内容来自www.paper51.com } paper51.com while( m_PortFrom <= m_PortTo ) 内容来自www.paper51.com { paper51.com
PortList.Add(m_PortFrom); 内容来自论文无忧网 www.paper51.com m_PortFrom++; copyright paper51.com } paper51.com
} http://www.paper51.com
该系统不仅可以提供端口范围选择,还可以让用户自定义端口列表,所以当用户选择自定义端口列表来扫描的时候,程序就通过一个循环从自定义端口列表树中获得用户勾选的端口等待扫描。 内容来自论文无忧网 www.paper51.com else 内容来自www.paper51.com { paper51.com HTREEITEMA = m_PortListTree.GetRootItem(); paper51.com if( A == NULL) paper51.com { 内容来自www.paper51.com AfxMessageBox("端口列表 不能为空!"); paper51.com returnFALSE; http://www.paper51.com } copyright paper51.com
while( A != NULL ) 内容来自论文无忧网 www.paper51.com { copyright paper51.com 这里通过一个if循环来获得自定义端口列表中选取的端口。首先将m_PortListTree中的端口信息传入到一个字符串CString str中,并读取端口列表地址。如果没有选择端口列表,则返回错误信息。 http://www.paper51.com 3.4.2 目标IP选取模块 paper51.com 选择IP范围以确定扫描的目标。读取起始ip到m_StartIP,结束ip到m_EndIP中,并判断起始IP是否不大于结束IP,如果成功就返回true,否则返回false。 copyright paper51.com BOOL CLScanPortDlg::InitIP() http://www.paper51.com { copyright paper51.com CIPAddressCtrl* pIP = (CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESSA); http://www.paper51.com
if( pIP->IsBlank() ) copyright paper51.com
{ paper51.com AfxMessageBox("IP地址不能为空!"); http://www.paper51.com Return FALSE; copyright paper51.com } 内容来自www.paper51.com
******省略部分代码****** 内容来自论文无忧网 www.paper51.com { 内容来自www.paper51.com
AfxMessageBox("IP地址不能为空!"); paper51.com Return FALSE; 内容来自论文无忧网 www.paper51.com
} paper51.com
pIP->GetAddress(m_EndIP); paper51.com
http://www.paper51.com
最后使用if循环来判断m_StartIP和m_EndIP,当m_StartIP大于m_EndIP的时候,返回提示信息"起始IP必须<=结束IP!";如果起始IP小于结束IP,则返回一个TRUE。 内容来自论文无忧网 www.paper51.com
3.4.3 终止扫描 copyright paper51.com 在扫描完成后选择“停止扫描”按钮,扫描器会终止扫描并将相关的资源释放掉以结束对系统资源的占用。首先判断有没有得到m_IsGo传来的扫描开始的消息,如果有则在获得终止扫描消息后延时1秒,并通过获得&m_ListTreeResult(扫描结果树的地址)的消息来得到当前的扫描结果树。接着释放hListenDlg(网卡进程)和m_pLocalIPList(本地IP地址列表),并设置((CWnd*)&m_OK) ->EnableWindow(TRUE),以使界面上的按钮有效,可以重新开始扫描。 copyright paper51.com 3.4.4 扫描结果存储模块 paper51.com
通过使用OnButtonSaveResult函数,在得到保存结果的消息后首先判断结果地址树是否为空,如果有扫描结果则创建一个标准文件对话框以准备存储扫描结果。在创建成功以后将扫描结果列表树上的数据写入到文本框中以存储本次扫描的结果。 paper51.com
如果程序仍然处于扫描状态中,将不能保存结果。通过全局变量判断程序是否处于扫描状态,如果没有则创建一个命为“Result.txt”的文本文件来保存扫描结果。 内容来自www.paper51.com { http://www.paper51.com if( ::OK == TRUE ) paper51.com { paper51.com
AfxMessageBox("失败,还在扫描,请等待停止后再保存!"); copyright paper51.com
return; 内容来自论文无忧网 www.paper51.com } 内容来自论文无忧网 www.paper51.com } paper51.com TCHARpR[MAX_PATH]={0}; paper51.com GetModuleFileName(NULL,pR,MAX_PATH); copyright paper51.com
memset(pR+strlen(pR)-4,0,4); http://www.paper51.com strcat(pR,"Result.txt"); paper51.com
//创建标准文件对话框,用Fdlg.DoModal()来显示创建的对话框 http://www.paper51.com 当打开文件的时候属性设置为写入,并将得到的扫描结果保存到创建的文本文件当中。 内容来自论文无忧网 www.paper51.com FILE*fp = fopen(Fname,"w"); copyright paper51.com if( fp == NULL ) copyright paper51.com { 内容来自www.paper51.com AfxMessageBox("写入失败!"); copyright paper51.com return; 内容来自www.paper51.com } copyright paper51.com
fprintf(fp,"PortScanner扫描结果如下:\n"); 内容来自www.paper51.com 定义两个结构体A和B,A表示结果树中的IP地址,B表示每个IP下面扫描出来的端口信息。在对扫描结果进行保存的时候,首先用A通过m_ListTreeResult.GetItemText()得到一个扫描的IP,然后将所有扫描这个IP得到的端口子属性m_ListTreeResult.GetNextSiblingItem()写到A的下面。如此循环便可以将所有的IP和扫描出来的端口保存到创建的文本文件中。 http://www.paper51.com
******省略部分代码****** paper51.com fclose (fp); 内容来自论文无忧网 www.paper51.com AfxMessageBox("成功写入!"); http://www.paper51.com
} 内容来自www.paper51.com //创建标准文件对话框失败 内容来自论文无忧网 www.paper51.com elseif (nResponse == IDCANCEL) paper51.com { 内容来自www.paper51.com return; copyright paper51.com } paper51.com } paper51.com |