回憶.初學C語言時編寫的第一個程序.TCP端口掃描器

//////////////////////////////////////////////////////////
//PortScan.cpp

#include < winsock2.h >
#include < windows.h >
#include < stdio.h >
#include < stdlib.h >
#include < string.h >

#pragma comment( lib, "WS2_32.lib" )

//-----------------by Chrython Chou 200532530012 ----------------------

//////////////////////////////////////////////////////////
//函數原型


//歡迎界面
void psTitle( char * );

//默認掃描方式
void ps1( char *, char * );

//自定義掃描方式
void ps2( char *, char *, char *, char * );

//獲得主機信息
void GetLocalDate( void );

//線程函數
DWORD WINAPI psProc(
  LPVOID lpParameter   // thread data
);


//////////////////////////////////////////////////////////
//全局變量


//目標地址和目標端口
char g_szTargetIP[20];
int g_nTargetPort;

//默認常用探測端口
int g_nPorts[23] = {
  21,22,23,25,53,79,80,110,111,119,135,139,143,
  443,445,512,554,1080,1433,1521,2401,3306,3389
};

//端口開放數量
int g_nOpenPorts;

//////////////////////////////////////////////////////////
//類

//載入和釋放Winsock2庫的類
class CInitSock
{
public:

 CInitSock( BYTE minorVer = 2, BYTE majorVer = 2)
 {
  WORD wVersionRequested;
  WSADATA wsaData;
  int err;

  wVersionRequested = MAKEWORD( minorVer, majorVer );

  err = ::WSAStartup( wVersionRequested, &wsaData );
  if( err != 0 )
  {
   return;
  }
  if ( LOBYTE( wsaData.wVersion ) != minorVer || HIBYTE( wsaData.wVersion ) != majorVer )
  {
   ::WSACleanup();
   return;
  }
 }

 ~CInitSock()
 {
  ::WSACleanup();
 }
};

//參數輸入錯誤類
class CGetError
{
public:

 void PortError( int nStartPort, int nEndPort )
 {
  if ( nStartPort < 0 || nStartPort > 65535 || nEndPort < 0 || nEndPort > 65535 )
  {
   printf("錯誤: 端口輸入/n");
   exit(1);
  }
  if ( nStartPort >= nEndPort )
  {
   printf("錯誤: 端口輸入/n");
   exit(1);
  }
 }
 
 void IPError( void )
 {
  DWORD IPmax = inet_addr( "255.255.255.255" );
  DWORD IPmin = inet_addr( "0.0.0.0" );
  DWORD nowIP = inet_addr( g_szTargetIP );

  if ( nowIP >= IPmax || nowIP <= IPmin )
  {
   printf("錯誤: IP地址輸入/n");
   exit(1);
  }
 }

 void DelayTimeError( int nDelayTime )
 {
  if ( nDelayTime < 0 || nDelayTime > 65535 )
  {
   printf("錯誤: 等待時間輸入/n");
   exit(1);
  }
 }

};


//////////////////////////////////////////////////////////
//主函數用於命令行參數輸入

void main(int argc,char *argv[])
{
 if( argc == 1 )
 {
  psTitle( argv[0] );
  exit( 1 );
 }
 
 else if(argc == 3)
 {
  ps1( argv[1] , argv[2] );
 }
 else if( argc == 5 )
 {
  ps2( argv[1], argv[2], argv[3], argv[4] );
 }
 
 else
 {
  printf( "錯誤: 參數輸入/n" );
  exit( 1 );
 }
}

//歡迎界面
void psTitle(char *help)
{
 printf ("--------------------------------------------------------------------/n");
 printf ("Portscan端口掃描器/n");
 printf ("------------------------------本機信息------------------------------/n");
 GetLocalDate();
 printf ("------------------------------功能說明------------------------------/n");
 printf ("常用端口掃描:/n");
 printf ("/tPortscan <目標IP> [等待時間(毫秒)]/n");
 printf ("自定義端口掃描:/n");
 printf ("/tPortscan <目標IP> [開始端口] [結束端口] [等待時間(毫秒)]/n");
 printf ("舉例:/n");
 printf ("/tPortscan 127.0.0.1 1/n");
 printf ("/tPortscan 127.0.0.1 0 65535 1/n");
 printf ("--------------------------------------------------------------------/n");
}

//默認掃描方式
void ps1( char *target, char *delay )
{
 //初始化CGetError
 CGetError psError;
 int nDelayTime = atoi( delay );

 

 //初始化Winsock庫
 CInitSock initSock;

 HANDLE hThread1;

 strcpy( g_szTargetIP , target );

 //輸入錯誤處理
 psError.IPError();
 psError.DelayTimeError( nDelayTime );
 
 printf ("/n--------------------------------------------------------------------/n");
 printf( "目標地址: ");
 puts( target );
 printf( "目標端口: 默認常用端口" );
 printf("/n------------------------------掃描報告------------------------------");

 for ( int i = 0; i < 23; i++ )
 { 
  g_nTargetPort = g_nPorts[i];

  //NULL 使用缺省的安全性
  //0 採用調用線程一樣的大小
  //psProc 指定線程入口函數的地址
  //NULL 傳遞給線程的一個參數
  //0 創建的標記爲0 一旦創建立即運行
  //NULL 線程的ID 不需要使用
  hThread1 = CreateThread( NULL, 0, psProc, NULL, NULL, NULL );
 
  CloseHandle( hThread1 );

  Sleep( nDelayTime );
 }
 printf( "/n/n共掃描到%d個端口開放" , g_nOpenPorts );
 printf ("/n--------------------------------------------------------------------/n");
 printf( "/n/n端口掃描完畢/n" );
}

//自定義掃描方式
void ps2( char *target, char *start, char *end, char *delay )

 //初始化CGetError
 CGetError psError;

 int nStartPort = atoi( start );
 int nEndPort = atoi( end );
 int nDelayTime = atol( delay );

 //初始化Winsock庫
 CInitSock initSock;

 HANDLE hThread2;

 strcpy( g_szTargetIP , target );
 
 
 //輸入錯誤處理
 psError.PortError( nStartPort, nEndPort );
 psError.IPError();
 psError.DelayTimeError( nDelayTime );

 printf ("/n--------------------------------------------------------------------/n");
 printf( "目標地址: ");
 puts( target );
 printf( "目標端口: %d -- %d:", nStartPort, nEndPort );
 printf ("/n------------------------------掃描報告------------------------------");

 for ( int port = nStartPort; port <= nEndPort; port++ )
 { 
  g_nTargetPort = port;

  //NULL 使用缺省的安全性
  //0 採用調用線程一樣的大小
  //psProc 指定線程入口函數的地址
  //NULL 傳遞給線程的一個參數
  //0 創建的標記爲0 一旦創建立即運行
  //NULL 線程的ID 不需要使用
  hThread2 = CreateThread( NULL, 0, psProc, NULL, NULL, NULL );
 
  CloseHandle( hThread2 );

  Sleep( nDelayTime );
 }
 printf( "/n/n共掃描到%d個端口開放" , g_nOpenPorts );
 printf ("/n--------------------------------------------------------------------/n");
 printf( "/n/n端口掃描完畢/n" );
}

//獲得主機信息
void GetLocalDate( void )
{
 //初始化Winsock庫
 CInitSock initSock;

 char szHost[256];
//獲取本地主機名
 ::gethostname( szHost, 256 );
//通過主機名獲取主機信息
 hostent *pHost = ::gethostbyname( szHost );
//打印出所有IP
 in_addr addr;

 for( int i = 0;; i++ )
 {
  char *p;
  char *szlp;

  p = pHost->h_addr_list[i];
  
  if ( p == NULL )
   break;
  memcpy( &addr.S_un.S_addr, p, pHost->h_length );

  szlp = ::inet_ntoa( addr );

  printf("本地主機名: %s /n", szHost);
  printf("本地主機IP: %s /n", szlp);
 }
}

//調用輔線程來循環掃描每個端口
DWORD WINAPI psProc(
 LPVOID lpParameter   // thread data
)
{
 //創建套接字
 SOCKET psSock = ::socket ( AF_INET, SOCK_STREAM, 0 );
 
 //sockaddr_in結構
 struct sockaddr_in psAddr;

 if( psSock == INVALID_SOCKET )
 {
  printf( "Error: socket /n" );
  exit(1);
 }

 //將psAddr中的前sizeof( psAddr )個字符都替換成0
 memset( &psAddr, 0, sizeof( psAddr ) );

 //填充sockaddr結構
 psAddr.sin_family = AF_INET;
 psAddr.sin_addr.S_un.S_addr = inet_addr( g_szTargetIP );
 psAddr.sin_port = htons( g_nTargetPort );

 if( ::connect( psSock, ( sockaddr* )&psAddr, sizeof( psAddr ) ) != SOCKET_ERROR )
 {
  printf( "/n端口 %d 開放", ntohs( psAddr.sin_port) );
  g_nOpenPorts++;
  
 }

 //關閉監聽套接字
 ::closesocket( psSock );

 return 0;
}

發佈了7 篇原創文章 · 獲贊 1 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章