// PortScan.cpp : Defines the entry point for the console application. // ///============================================================================= /// PortScan - 端口扫描程序 /// /// 2005-7-8 16:49:52 ///============================================================================= #include <winsock2.h> #include <stdio.h> //printf函数要用的头文件 #pragma comment(lib,"ws2_32.lib") void Help(); DWORD WINAPI ScanThread(LPVOID lp); void ReportAPIError(); //保存扫描的主机IP和端口的结构 typedef struct{ char HostIp[17]; int ScanPort; }HostStruct; long lPortOpen = 0; // 统计开放端口数 int main(int argc, char* argv[]) { WORD wVersion = MAKEWORD(2,0); //socket的版本 WSADATA wsaData; int iFromPort; //开始端口 int iToPort; //结束端口 int iNowPort; //正在扫描的端口 int iPortCount; //端口总数 //如果命令行下参数不是4个(包括portscan.exe本身),提示正确的用法 if(argc != 4) { Help(); return -1; } //保存用户输入的要扫描的起始端口和结束端口,由于用户输入的是char型,所以要先转成int型 iFromPort = atoi(argv[2]); iToPort = atoi(argv[3]); //对用户输入的端口进行判断 if(iFromPort > iToPort || iFromPort < 0 || iFromPort >65535 || iToPort <0 || iToPort >65535) { printf("起始端口不能大于结束端口,且范围为:1-65535!\n"); return 0; } if (WSAStartup(wVersion , &wsaData)) { printf("初始化失败!"); return -1; } //要扫描的端口总数 iPortCount = iToPort - iFromPort + 1; printf("端口范围: %d -> %d,共%d个.\n", iFromPort,iToPort , iPortCount); printf("\n======= 开始扫描 =======\n"); // 根据端口数创建线程句柄数 HANDLE *hThreads = new HANDLE[iPortCount]; ZeroMemory(hThreads,sizeof(HANDLE)*iPortCount); // // 根据端口数创建线程参数结构指针,使用它只是为了记录结构指针,用于主线程释放动态内存 // HostStruct** pScanHosts = new HostStruct*[iPortCount]; ZeroMemory(pScanHosts,sizeof(HostStruct*)*iPortCount); //循环连接端口,以判断端口是否开放 int iThreadCount = 0; // 成功创建的线程数目计数 int iParamCount = 0; // 线程句柄数组索引 for(iParamCount = 0, iNowPort = iFromPort; iNowPort <= iToPort; iParamCount++,iNowPort++) { // 为单独的线程提供单独的线程参数,此参数不能在局部栈上分配 pScanHosts[iParamCount] = new HostStruct; strcpy( pScanHosts[iParamCount]->HostIp,argv[1]); pScanHosts[iParamCount]->ScanPort = iNowPort; HANDLE hThread; hThread = CreateThread(NULL,NULL,ScanThread,pScanHosts[iParamCount],NULL,NULL); if(hThread == NULL) { ReportAPIError(); continue; } else hThreads[iThreadCount++] = hThread;//只统计正常运行的线程 } printf("线程创建完毕!\n"); // // 等待线程执行完毕,这一步是必须的,否则上面分配的动态内存会过早释放,线程执行时参数数据将出现异常 // // WaitForMultipleObjects 所能等待的对象最大不能超过MAXIMUM_WAIT_OBJECTS (64)个,如果超过,进行分组等待 // for(int iGroup = 0; iThreadCount>0; iGroup ++, iThreadCount -= MAXIMUM_WAIT_OBJECTS) { DWORD res = WaitForMultipleObjects( iThreadCount>MAXIMUM_WAIT_OBJECTS ? MAXIMUM_WAIT_OBJECTS : iThreadCount, hThreads+iGroup*MAXIMUM_WAIT_OBJECTS, TRUE, INFINITE); if(res == WAIT_FAILED) { ReportAPIError(); continue; } } printf("扫描完毕!\n"); printf("共开放端口: %ld 个 \n",lPortOpen); // 释放所有动态分配的内存 delete[iPortCount] hThreads; for(int ii=0; ii < iPortCount; ii ++ ) { delete pScanHosts[ii]; } delete[iPortCount] pScanHosts; WSACleanup(); return 0; } //============================================================================== // 线程函数 // 2005-7-8 16:52:41 //============================================================================== DWORD WINAPI ScanThread(LPVOID lp) { struct sockaddr_in sin; //sockaddr_in结构 SOCKET s; //保存创建socket时的返回值 //将参数传化成HostStruct结构指针 HostStruct *lpScanHost=(HostStruct*)lp; s = socket(AF_INET,SOCK_STREAM,0); if(s == INVALID_SOCKET) { printf("创建socket()失败!\n"); // WSACleanup();//这不是你应该在这里做的 } //给结构成员赋值 sin.sin_family = AF_INET; sin.sin_port = htons(lpScanHost->ScanPort); sin.sin_addr.S_un.S_addr = inet_addr(lpScanHost->HostIp); //建立连接 if(connect(s,(struct sockaddr*)&sin,sizeof(sin)) == SOCKET_ERROR) { printf("%s -> %d:未开放\n",lpScanHost->HostIp,lpScanHost->ScanPort); // closesocket(s);//not necessary! } else { printf("%s -> %d:开放\n",lpScanHost->HostIp,lpScanHost->ScanPort); //iPortOpen ++; InterlockedIncrement(&lPortOpen); closesocket(s); } return 0; } //以下为帮助函数内容 void Help() { printf("\nPortScan V1.0 by:∮明天去要饭\n"); printf("\nPortScan V1.1 by:meteor135 smith_135@163.com\n"); printf("Usage:\n"); printf(" PortScan.exe <TargetIP> <BeginPort> <EndPort>\n"); printf("Example:\n"); printf(" PortScan.exe 127.0.0.1 1 445\n"); } //============================================================================== // 报告API错误 // 2005-7-8 16:52:19 //============================================================================== void ReportAPIError() { LPVOID lpMsgBuf; if (!FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL )) { // Handle the error. return ; } // Display the string. printf("%s\n",lpMsgBuf); // Free the buffer. LocalFree( lpMsgBuf ); }
特此感谢 meteor135(流星雨) 对我的程序进行的改进。现在这个多线程的扫描器,速度是挺快,不过还是有些小问题,以后如果有更好的版本,我会发出来给大家研究的。
|