|
- // PortScan.cpp
- //
- //=============================================================================
- // PortScan - 端口扫描程序
- //
- // XXXXXXXXXXXXXXX
- //
- // XXXXXXXXXXXXXXX
- //=============================================================================
- #include <winsock2.h>
- #include <stdio.h>
- #pragma comment(lib,"ws2_32.lib")
- DWORD WINAPI ScanThread(LPVOID lp);
- //保存扫描的主机IP和端口的结构
- typedef struct{
- char HostIp[17];
- int ScanPort;
- }HostStruct;
- long lPortOpen = 0; // 统计开放端口数
- //帮助
- void Help(char *argv0)
- {
- printf("\nPortScan.exe");
- printf("\nUsage:");
- printf("\n\t%s 127.0.0.1 1 3389\n",argv0);
- exit(0);
- }
- //==============================================================================
- // 线程函数
- //==============================================================================
- DWORD WINAPI ScanThread(LPVOID lp)
- {
- struct sockaddr_in sin; // sockaddr_in结构
- HostStruct *lpScanHost=(HostStruct*)lp; // 将参数传化成HostStruct结构指针
- SOCKET s = socket(AF_INET,SOCK_STREAM,0);
- // 给结构成员赋值
- 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("\n%s:%d\tOPEN",lpScanHost->HostIp,lpScanHost->ScanPort);
- InterlockedIncrement(&lPortOpen); // 原子性++ 相对 InterlockedDecrement 原子性--
- }
- closesocket(s); // 无论连接是否成功都需要关闭socket
- return 0;
- }
- int main(int argc, char* argv[])
- {
- WORD wVersion = MAKEWORD(2,0); //socket的版本
- WSADATA wsaData;
- int iFromPort; //开始端口
- int iToPort; //结束端口
- int iNowPort; //正在扫描的端口
- int iPortCount; //端口总数
- int badCount=0; //线程失败数,有时候失败是因为目标设置了最大连接数
- //如果命令行下参数不是4个,提示正确的用法
- if(argc != 4)
- Help(argv[0]);
- //保存用户输入的要扫描的起始端口和结束端口,由于用户输入的是char型,所以要先转成int型
- iFromPort = atoi(argv[2]);
- iToPort = atoi(argv[3]);
- //对用户输入的端口进行判断
- if(iFromPort > iToPort || iToPort >65535 || iFromPort < 0)
- return -1;
- if (WSAStartup(wVersion , &wsaData))
- return -1;
- //要扫描的端口总数
- iPortCount = iToPort - iFromPort + 1;
- // 根据端口数创建线程句柄数
- HANDLE *hThreads = new HANDLE[iPortCount];
- ZeroMemory(hThreads,sizeof(HANDLE)*iPortCount);
- //
- // 根据端口数创建线程参数结构指针,使用它只是为了记录结构指针,用于主线程释放动态内存
- //
- HostStruct** pScanHosts = new HostStruct*[iPortCount];
- ZeroMemory(pScanHosts,sizeof(HostStruct*)*iPortCount);
- printf("\n====== Scanning ======\n");
- //循环连接端口,以判断端口是否开放
- 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 = CreateThread(NULL,NULL,ScanThread,pScanHosts[iParamCount],NULL,NULL);
- if(hThread != NULL){
- hThreads[iThreadCount++] = hThread;//只统计正常运行的线程
- if(iThreadCount%64==0) Sleep(200); // 每成功创建64个线程,停顿200毫秒(多次测试后的合理取值),降低CPU
- }
- else
- badCount++;
- }
- // 等待线程执行完毕,这一步是必须的,否则上面分配的动态内存会过早释放,线程执行时参数数据将出现异常
- // WaitForMultipleObjects 所能等待的对象最大不能超过MAXIMUM_WAIT_OBJECTS (64)个,如果超过,进行分组等待
- //
- for(int iGroup = 0; iThreadCount>0; iGroup ++, iThreadCount -= MAXIMUM_WAIT_OBJECTS)
- {
- WaitForMultipleObjects(
- iThreadCount>MAXIMUM_WAIT_OBJECTS ? MAXIMUM_WAIT_OBJECTS : iThreadCount,
- hThreads+iGroup*MAXIMUM_WAIT_OBJECTS,
- TRUE,
- 256); // 此参数单位为毫秒,若为INFINITE则代表一直等待,直到线程返回
- }
- printf("\n\n====== OK ======");
- printf("\n\tBad threads %d : %d",iPortCount,badCount);
- printf("\n\tDetected open ports %ld\n",lPortOpen);
- // 释放所有动态分配的内存
- delete[iPortCount] hThreads;
- for(int ii=0; ii < iPortCount; ii ++ )
- delete pScanHosts[ii];
- delete[iPortCount] pScanHosts;
- WSACleanup();
- return 0;
- }
复制代码 |
|