C++实现端口扫描器

单个端口信息抓取

通过判断连接返回的套接字信息来判断端口是否开放,然后抓取端口对应的信息。

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

void port_open(char *, int);

int main(int argc, char *argv[])
{
    port_open("192.168.3.132", atoi(argv[1]));
    return 0;
}

void port_open(char * addr, int port){
    
    int socketClient;
    socketClient = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in addrSrv;
    memset(&addrSrv, 0 , sizeof(addrSrv));
    addrSrv.sin_family = AF_INET;
    addrSrv.sin_addr.s_addr = inet_addr(addr);
    addrSrv.sin_port = htons(port);

    cout << "-----scaning---port: " << port << endl;
    if(connect(socketClient, (struct sockaddr*) & addrSrv, sizeof(addrSrv)) == -1){
        cout << "[-] " << port << " closed!" << endl;
    }
    else{
        cout << "[+] " << port << " open!" << endl;
        int end_index;
        char message[65536];
        
        end_index = recv(socketClient, message, 65536, 0);
        cout << end_index << endl;
        if(end_index == -1)
            cout << "read failed!" << endl;
        else{
            message[end_index] = '\0';
            cout << message << endl;
        }
    }
    close(socketClient);
}

多个端口单线程扫描

  • 通过getopt和switch来解析命令行参数,此处提供了三个参数,分别时主机地址、开始端口、结束端口。开始端口和结束端口都有对应的默认值。
  • 考虑了一下异常的影响。
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

char addr[30];

void port_scan(int);
void order_port_scan(int, int);

int main(int argc, char **argv){
    int start_port=1, end_port=1000;
    int opt;
    const char *optstring = "a:s:e:";

    while((opt = getopt(argc, argv, optstring)) != -1){
        switch(opt){
            case 'a':
                strcpy(addr, argv[optind-1]);
                break;
            case 's':
                start_port = atoi(argv[optind-1]);
                break;
            case 'e':
                end_port = atoi(argv[optind-1]);
                break;
            default:
                cout << "parameter error" << endl;
                exit(0);
        }
    }

    if(addr == nullptr)
        cout << "address is not supplyed!" << endl;
    cout << "*********** Scanning " << addr << " from port " << start_port << " to port " << end_port << " *************************"<<endl;
    order_port_scan(start_port, end_port);
    return 0;
}


void order_port_scan(int start_port, int end_port){ 
    for(int port=start_port; port <= end_port; port++)
        port_scan(port);
}
void port_scan(int port){

    int socketClient;
    struct sockaddr_in addrSrv;
    try{
        socketClient = socket(AF_INET, SOCK_STREAM, 0);
        memset(&addrSrv, 0, sizeof(addrSrv));
        addrSrv.sin_family = AF_INET;
        addrSrv.sin_addr.s_addr = inet_addr(addr);
        addrSrv.sin_port = htons(port);
        if(connect(socketClient, (struct sockaddr*) &addrSrv, sizeof(addrSrv)) >= 0){
            cout << "[+] " << port << " open! " << endl; 
        }else{
            cout << "[-] " << port << " closed! " << endl; 
        }
    }catch(exception e){
        cout << "error!" << endl;
    }
    close(socketClient);
}

多端口多线程实现

  • 多线程中加入静态互斥锁,可以通过-p参数指定线程数,但是建议的线程数不要太大,不能超过100,因为此处定义的线程数组大小为100。
  • linux下sleep函数的单位时是秒,可以通过usleep来指定更短的时间。
  • 在编程实现的过程中考虑线程数的多少,而不是一共有多少个要扫描的端口。
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

pthread_mutex_t mutex_x=PTHREAD_MUTEX_INITIALIZER;
char addr[30];
struct threadPort{
    int thread_port;
};

void * port_scan(void *threadarg);


int main(int argc, char **argv){
    int start_port=1, end_port=1000;
    int thread_num = 5;
    int opt;
    const char *optstring = "a:s:e:p:";

    struct threadPort tp[100];
    int time_thread = 10000;
    pthread_t threads[100];
    int thread_id;
    int id = 0;
    int rc;

    while((opt = getopt(argc, argv, optstring)) != -1){
        switch(opt){
            case 'a':
                strcpy(addr, argv[optind-1]);
                break;
            case 's':
                start_port = atoi(argv[optind-1]);
                break;
            case 'e':
                end_port = atoi(argv[optind-1]);
                break;
            case 'p':
                thread_num = atoi(argv[optind-1]);
                break;
            default:
                cout << "parameter error" << endl;
                exit(0);
        }
    }

    if(addr == nullptr)
        cout << "address is not supplyed!" << endl;
    cout << thread_num << endl;
    cout << "*********** Scanning " << addr << " from port " << start_port << " to port " << end_port << " *************************"<<endl;
    for(int port=start_port; port <= end_port; port++, id++){
        thread_id = id % thread_num;
        tp[thread_id].thread_port = port;
        rc = pthread_create(&threads[thread_id], NULL, port_scan, &tp[thread_id]);
        if(rc){
            cout << "Error, return code from pthread_create() is "<< rc << endl;
            exit(-1);
        }
        usleep(time_thread);
    }
    pthread_exit(NULL);
    return 0;
}

void * port_scan(void *threadarg){ // 注意函数的原型要这么定义
    pthread_mutex_lock(&mutex_x);
    struct threadPort * data = (struct threadPort *) threadarg;
    int port = data->thread_port;
    int socketClient;
    struct sockaddr_in addrSrv;
    try{
        socketClient = socket(AF_INET, SOCK_STREAM, 0);
        memset(&addrSrv, 0, sizeof(addrSrv));
        addrSrv.sin_family = AF_INET;
        addrSrv.sin_addr.s_addr = inet_addr(addr);
        addrSrv.sin_port = htons(port);
        if(connect(socketClient, (struct sockaddr*) &addrSrv, sizeof(addrSrv)) >= 0){
            cout << "[+] " << port << " open! " << endl; 
        }else{
            cout << "[-] " << port << " closed! " << endl; 
        }
    }catch(exception e){
        cout << "error!" << endl;
    }
    close(socketClient);
    pthread_mutex_unlock(&mutex_x);
    pthread_exit(NULL);
    return NULL;
} 
#编译命令
g++ simple_pthread_port_scan.cpp -o simple_pthread_port_scan -lpthread
#执行命令
./simple_pthread_port_scan -a 192.168.3.132 -p 20 -s 20 -e 100    

你可能感兴趣的:(渗透测试,linux,c++,网络安全)