C++网络安全工具编程(一)connect端口扫描器
端口扫描的种类有很多,其中最简单的即为基于TCP三次握手协议的connect扫描器。其原理为与服务端口建立一个socket连接,当连接上时即可判断端口打开,之后断开连接,进行下一端口的试探。首先来看一个最简的c++客户端与目标服务器建立socket连接的基础代码
#include "stdafx.h" #include <string.h> #include <WinSock.h> #include <iostream> #pragma comment(lib,"ws2_32.lib") using namespace std; int _tmain(int argc, _TCHAR* argv[]) { //初始化Windows Sockets 动态库 WSADATA wsaData; if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0) { cout<<"找不到可使用的WinSock dll!"<<endl; return 1; } //创建套接字 SOCKET sClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(sClient==INVALID_SOCKET) { cout<<"创建客户端socket失败!"<<endl; return 1; } //连接服务器 SOCKADDR_IN addrServ; addrServ.sin_family=AF_INET; addrServ.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); addrServ.sin_port=htons(10046); if(connect(sClient,(sockaddr *)&addrServ,sizeof(sockaddr))==SOCKET_ERROR) { cout<<"连接服务器失败!"<<endl; closesocket(sClient); return 1; } else cout<<"连接服务器成功!"<<endl; //关闭套接字,释放资源 closesocket(sClient); WSACleanup(); return 0;
这里注意一下,如遇到 error LNK2019: 无法解析的外部符号 _WSACleanup@0,该符号在函数 _wmain 此类错误,如上代码添加#pragma comment(lib,”ws2_32.lib”)即可。
由于功能需求的关系,这里就不讲解发送与接收消息的方法了,后续会陆续开篇。
在window下建立socket连接,通常需要使用winSock这个库,初始化动态库并创建套接字后,使用connect方法对目标IP(127.0.0.1)及端口(10046)尝试连接。
以上即为一个标准的windows平台下C++使用socket连接目标服务器的过程。
利用上面的代码,我们即可开始自己的端口扫描器的制作,原理非常简单,即将单一的对目标服务器端口的连接尝试,放置到一个for循环中批量操作,并根据结果显示不同的打印内容。
代码如下:
#include "stdafx.h" #include <string.h> #include <WinSock.h> #include <iostream> #pragma comment(lib,"ws2_32.lib") using namespace std; int _tmain(int argc, _TCHAR* argv[]) { //初始化Windows Sockets 动态库 WSADATA wsaData; if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0) { cout<<"找不到可使用的WinSock dll!"<<endl; return 1; } SOCKET sClient = NULL; SOCKADDR_IN addrServ; addrServ.sin_family=AF_INET; addrServ.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); for (int _port = 0;_port<100;_port++){ if (sClient == NULL) { //创建套接字 sClient=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(sClient==INVALID_SOCKET) { cout<<"创建客户端socket失败!"<<endl; return 1; } } addrServ.sin_port=htons(_port); //连接服务器 if(connect(sClient,(sockaddr *)&addrServ,sizeof(sockaddr))==SOCKET_ERROR) { cout<<"port "<<_port<<" is not open!"<<endl; //closesocket(sClient); //return 1; } else{ cout<<"port "<<_port<<" open on host!!!!!!!!!!!!"<<endl; closesocket(sClient); sClient = NULL; } } //关闭套接字,释放资源 getchar(); WSACleanup(); return 0;
以上代码即可简单的实现0-100号端口的tcp扫描。不过运行速度较慢,连接超时的时限也没有加入。但对于入门学习来说已经基本满足了初学者对概念的熟悉。后续我们将针对此扫描做更多的拓展,例如,多线程端口扫描等等。
同时,需要注意的是,基于connect的端口扫描,是不隐蔽扫描,通过tcp服务器与目标端口建立3次握手的过程会被服务器记录下来,因此,只需要在服务器上稍加防护即可屏蔽此类扫描。
后续我将介绍其他类型的扫描方式。
最后发个运行效果:
补充:综合编程 , 安全编程 ,