大作業(yè)準(zhǔn)備寫一個(gè)C++掃描器,于是學(xué)習(xí)一些winsock的編程知識(shí)。
我理解最基本的基于tcp的掃描器原理也就是與端口三次握手,connect即為開放。端口掃描器分類如下:
1.開放掃描
會(huì)產(chǎn)生大量的審計(jì)數(shù)據(jù),容易被對(duì)方發(fā)現(xiàn),但其可靠性高;
ex:TCP Connect掃描(基于三次握手),TCP反向ident掃描
2.隱蔽掃描
能有效的避免對(duì)方入侵檢測(cè)系統(tǒng)和防火墻的檢測(cè),但這種掃描使用的數(shù)據(jù)包在通過網(wǎng)絡(luò)時(shí)容易被丟棄從而產(chǎn)生錯(cuò)誤的探測(cè)信息;
ex:TCP FIN掃描,TCP Xmas掃描,TCP Null掃描,TCP ftp proxy掃描,分段掃描
3.半開放掃描
隱蔽性和可靠性介于前兩者之間。
ex:TCP Syn掃描,TCP 間接掃描
syn原理:實(shí)現(xiàn)原理:掃描器向目標(biāo)主機(jī)端口發(fā)送SYN包。如果應(yīng)答是RST包,那么說明端口是關(guān)閉的;如果應(yīng)答中包含SYN和ACK包,說明目標(biāo)端口處于監(jiān)聽狀態(tài),再傳送一個(gè)RST包給目標(biāo)機(jī)從而停止建立連接。由于在SYN掃描時(shí),全連接尚未建立,所以這種技術(shù)通常被稱為半連接掃描
優(yōu)點(diǎn):隱蔽性較全連接掃描好,一般系統(tǒng)對(duì)這種半掃描很少記錄
缺點(diǎn):通常構(gòu)造SYN數(shù)據(jù)包需要超級(jí)用戶或者授權(quán)用戶訪問專門的系統(tǒng)調(diào)用
而tcp與udp最主要區(qū)別在于:基于連接與無連接;tcp掃描正確率高,udp掃描范圍小,效率高,錯(cuò)誤率高
技術(shù)太渣,只能嘗試實(shí)現(xiàn)connect的開放掃描。學(xué)習(xí)積累的部分winsock知識(shí)點(diǎn)如下:
比較全面的基礎(chǔ)概念:
1.Winsock五種類型的套接字I/O模型:select(選擇)、WSAAsyncSelect(異步選擇)、WSAEventSelect(事件選擇)、overlapped(重疊)、以及completion port(完成端口)。
winsock五種基本套接字I/O(好吧實(shí)在繁瑣,我也沒怎么看,只看了看五個(gè)概念)
2.select實(shí)現(xiàn)超時(shí)檢測(cè)。
通俗點(diǎn)講,select作用就是,防止在在阻塞模式的套接字里被鎖死,避免在非阻塞套接字里重復(fù)檢查
select詳解,重點(diǎn):五個(gè)參數(shù)作用
3.FD_SET作用:主要為存儲(chǔ)socket句柄,用來在select中檢測(cè)connect連接的可寫性。
4.Sockaddr_in部分參數(shù)說明
sockaddr_in常用轉(zhuǎn)換函數(shù)說明
5.開始時(shí),WSAStartup函數(shù)加載套接字庫(kù)結(jié)束時(shí),調(diào)用WSACleanup解除與庫(kù)的連接 WSA前綴部分函數(shù)使用
6.#pragma comment使用
blog.csdn.net/njuitjf/article/details/43235859
本地codeblocks報(bào)錯(cuò),百度發(fā)現(xiàn)是缺少lib庫(kù),明明#pragma comment(lib,"ws2_32.lib")了,還是不行。最后編譯設(shè)置里手工加上了。此處求大佬解答!
7.實(shí)現(xiàn)源碼:(寥寥100行,就不上github了的)
#include <winsock2.h>
#include <winsock.h>
#include <iostream>
#include <stdio.h>
#include <sstream>
#include <time.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"ws2_32")
int scan(char *Ip, int StartPort, int EndPort);
int main(int argc, char **argv)
{
int ret;
if (argc != 4)
{
printf("Usage: %s \n", argv[0]);
exit(1);
}
ret = scan(argv[1], atoi(argv[2]), atoi(argv[3]));
if (ret)
printf("Scan OK\n");
return 0;
}
int scan(char *Ip, int StartPort, int EndPort)
{
clock_t StartTime, EndTime;
float CostTime;
TIMEVAL TimeOut;
FD_SET mask;
WSADATA wsa;
SOCKET s;
struct sockaddr_in server;
int CurrPort;
int ret;
unsigned long mode = 1; //ioctlsocket函數(shù)的最后一個(gè)參數(shù)
WSAStartup(MAKEWORD(2, 2), &wsa);
TimeOut.tv_sec = 0;
TimeOut.tv_usec = 50; //超時(shí)為50ms
FD_ZERO(&mask);
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(Ip);
StartTime = clock();
for (CurrPort = StartPort; CurrPort <= EndPort; CurrPort++)
{
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
FD_SET(s, &mask);
ioctlsocket(s, FIONBIO, &mode); //設(shè)置為非阻塞模式
server.sin_port = htons(CurrPort);
connect(s, (struct sockaddr *)&server, sizeof(server));
ret = select(0, NULL, &mask, NULL, &TimeOut); //查詢可寫入狀態(tài)
if (0 == ret || -1 == ret)
{
closesocket(s);
}
else
{
printf("%s:%d\n", Ip, CurrPort);
closesocket(s);
}
}
EndTime = clock();
CostTime = (float)(EndTime - StartTime) / CLOCKS_PER_SEC;
printf("Cost time:%f second\n", CostTime);
WSACleanup();
return 1;
}