大作业准备写一个C++扫描器,于是学习一些winsock的编程知识。
我理解最基本的基于tcp的扫描器原理也就是与端口三次握手,connect即为开放。端口扫描器分类如下:
1.开放扫描
会产生大量的审计数据,容易被对方发现,但其可靠性高;
ex:TCP Connect扫描(基于三次握手),TCP反向ident扫描
2.隐蔽扫描
能有效的避免对方入侵检测系统和防火墙的检测,但这种扫描使用的数据包在通过网络时容易被丢弃从而产生错误的探测信息;
ex:TCP FIN扫描,TCP Xmas扫描,TCP Null扫描,TCP ftp proxy扫描,分段扫描
3.半开放扫描
隐蔽性和可靠性介于前两者之间。
ex:TCP Syn扫描,TCP 间接扫描
syn原理:实现原理:扫描器向目标主机端口发送SYN包。如果应答是RST包,那么说明端口是关闭的;如果应答中包含SYN和ACK包,说明目标端口处于监听状态,再传送一个RST包给目标机从而停止建立连接。由于在SYN扫描时,全连接尚未建立,所以这种技术通常被称为半连接扫描
优点:隐蔽性较全连接扫描好,一般系统对这种半扫描很少记录
缺点:通常构造SYN数据包需要超级用户或者授权用户访问专门的系统调用
而tcp与udp最主要区别在于:基于连接与无连接;tcp扫描正确率高,udp扫描范围小,效率高,错误率高
技术太渣,只能尝试实现connect的开放扫描。学习积累的部分winsock知识点如下:
比较全面的基础概念:
http://blog.csdn.net/shihoongbo/article/details/51489875
1.Winsock五种类型的套接字I/O模型:select(选择)、WSAAsyncSelect(异步选择)、WSAEventSelect(事件选择)、overlapped(重叠)、以及completion port(完成端口)。
winsock五种基本套接字I/O(好吧实在繁琐,我也没怎么看,只看了看五个概念)
http://blog.csdn.net/windows_nt/article/details/39456323
2.select实现超时检测。
通俗点讲,select作用就是,防止在在阻塞模式的套接字里被锁死,避免在非阻塞套接字里重复检查
select详解,重点:五个参数作用
blog.csdn.net/inspiron_110/article/details/4764847
3.FD_SET作用:主要为存储socket句柄,用来在select中检测connect连接的可写性。
www.xuebuyuan.com/1206173.html
4.Sockaddr_in部分参数说明
https://baike.baidu.com/item/sockaddr_in/3917215
sockaddr_in常用转换函数说明
blog.csdn.net/joeblackzqq/article/details/8258693
5.开始时,WSAStartup函数加载套接字库结束时,调用WSACleanup解除与库的连接 WSA前缀部分函数使用
blog.csdn.net/clemontine/article/details/53141041
6.#pragma comment使用
blog.csdn.net/njuitjf/article/details/43235859
本地codeblocks报错,百度发现是缺少lib库,明明#pragma comment(lib,"ws2_32.lib")了,还是不行。最后编译设置里手工加上了。此处求大佬解答!
7.实现源码:(寥寥100行,就不上github了的)
#include
#include
#include
#include
#include
#include
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函数的最后一个参数
WSAStartup(MAKEWORD(2, 2), &wsa);
TimeOut.tv_sec = 0;
TimeOut.tv_usec = 50; //超时为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); //设置为非阻塞模式
server.sin_port = htons(CurrPort);
connect(s, (struct sockaddr *)&server, sizeof(server));
ret = select(0, NULL, &mask, NULL, &TimeOut); //查询可写入状态
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;
}