マルチスレッドポートスキャンツール技術を使用して作成した文書の内容を、組み合わせてください。(前回のブログのネットワークセキュリティ12に基づきます)
知識:
ポートは、スキャンの背景と意義を
ネットワークは、各コンピュータは外に完全に開いているそのうちのいくつかの城、城、、一部が閉じられたドアのあるようなものです。で侵入者を見つけ、それらのゲートを開く方法?どこでこれらのゲートは、何につながりますか?ネットワークでは、コンピュータのこれらの城「ゲートは」「ポート」と呼ば ポートスキャンは、情報の検索、いくつかの一般的な方法の侵入者の一つであり、それはまた、侵入者の身元や意図を公開する可能性が最も高い方法です。、どのようなサービスを決定するために、ターゲットホストオペレーティングシステム上で開いているかを決定するために、ターゲットホスト侵入者がどのようなオペレーティングシステムが稼動しているサービス、ターゲットホストが開いてマスターした場合、彼らが達成するための適切な手段を使用することができます:一般的には、スキャンするポートは、以下の目的を持っています侵攻。管理者が最初にこれらのポートおよびサービスのセキュリティの脆弱性を習得している場合、我々は対応侵入を防止するための効果的なセキュリティ対策を取ることができるようになります。
ステータスポートスキャン
情報化時代のプロセスを加速するが、ソーシャルネットワークの程度の増加に伴い、コンピュータネットワークへの依存度も高まっている、ネットワークセキュリティの問題コンピュータ情報ネットワークの開発もますます明らかにされています。ポートスキャン技術は、安全性の問題の検出の重要な手段です。ポートは、潜在的な通信チャネルであるチャネルの侵略です。ポートは、多くの有用な情報を取得し、ターゲットコンピュータ上でスキャンします。異なるポートにスキャナオプションのリモートTCP / IPサービスを、ターゲット与えられた答えを記録し、この方法は、ターゲット・マシンのいくつかの固有の弱点を発見したターゲットホスト、に関する有用なさまざまな情報をたくさん集めることができます。
ポートスキャンツール(ポートスキャナ)は、検出を意味するサーバまたはホストオープンポートツールケース。多くの場合、コンピュータの管理者がセキュリティポリシーを確認するため、およびターゲットホストのネットワークサービスを特定の操作に攻撃者によって使用することができます。
ポートスキャンは、として定義されているクライアントは、対応するサーバポートの範囲要求を送信し、ポートは、これを確認するために使用することができます。それ自体悪意のあるネットワーク活動であるが、しかしまた、ネットワーク攻撃は、サービスの既知の脆弱性の重要な手段を活用するためにホストサービスをターゲット検出します。リモートマシンの可用性を確認するためのポートスキャンの主な目的は、まだ単なるサービスです。
特定のポートに対して複数のホストをスキャンが呼び出されたポートクリーニング特定のサービスを得るために、(Portsweep)。たとえば、に基づいて、SQLのサービスワームは、ポート1433上の多数のホストを確立するために、同じポートを掃引しますTCPの接続を。[1]
TCPスキャン
最も単純なポートスキャンツールを使用するには、オペレーティング・システム固有のネットワーク機能を、しばしばとして使用されたSYNスキャンする選択肢。nmapのような走査モードは同様のため、接続と呼ばれるUnixの接続システム()コマンド。ポートが開いている場合は、オペレーティングシステムが完成することができるようになりますTCP 3ウェイハンドシェイクを、ポートスキャンツールはすぐにあなただけのを防止するために作成した接続を閉じますサービス拒否攻撃を。このスキャンモードの利点は、特別な権限を持たないユーザーです。スキャンは人気がないように、しかし、ネイティブのオペレーティングシステム基盤となるネットワーク制御機能を使用して、達成することはできません。そして、TCPスキャンが簡単に特にポートを清掃する手段として、見つけることができます。これらのサービスは、送信者の記録されますのIPアドレスを、侵入検知システムは、アラームをトリガすることができます。[1]
SYNスキャン
TCP SYNスキャンは、別のスキャンです。ポートスキャンツールは、IPの送信、ネイティブネットワークのオペレーティングシステムの機能ではなく、自己生成を使用していないパケットを、その応答を監視します。それは完全なTCP接続を確立することはありませんので、このパターンは、「セミオープンスキャン」と呼ばれています。宛先ポートが開いている場合、ポートスキャンツールは、SYNパケットを生成し、それはSYN-ACKパケットを返します。スキャン応答RSTパケットの終了、その後、ハンドシェイクが完了する前に、接続を閉じます。ポートが閉じているが、フィルタを使用しなかった場合、宛先ポートは、持続可能なリターンRSTパケットでなければなりません。
この粗いネットワークの使用は、いくつかの利点があります。制御パケットが送信され、応答は、応答のより詳細な分析を可能にすること、スキャンツールに長いフルパワーを待ちます。これは、いくつかの論争のより侵襲的な存在感を持っていないターゲットホスト上のモードをスキャンしますが、利点は、SYNスキャンがより完全な接続を確立していないということです。しかし、RSTパケットは、プリンタなどの特に単純なネットワークデバイスをネットワークの輻輳を引き起こす可能性があります。[1]
UDPスキャン
いくつかの技術的な課題があるものの、UDPスキャンは、も可能です。UDPはコネクションレスプロトコルであるため、TCP SYNパケットに相当するものはありません。送信ポートにUDPパケットが開いていない場合は、ターゲットは、ICMPポート到達不能メッセージに応答します。ほとんどのUDPポートスキャナは、このスキャン方法を使用して、ポートが開いている推測するために、応答の欠如を使用します。ポートがファイアウォールによってブロックされている場合は、この方法は間違ったポートが開いていることを報告します。ポート到達不能メッセージがブロックされている場合は、すべてのポートが開いているように表示されます。この方法は、ICMPレート制限の影響を受けています。
別の方法は、アプリケーション固有のUDPパケットを送信することであり、アプリケーション層応答を生成することが望ましいです。DNSサーバが存在する場合、例えば、ポート53は、応答してDNSクエリ結果を伝達されます。この方法は、開いているポートを特定するという点で、より信頼性が高いです。しかし、それは特定のプローブが使用可能なポートスキャンアプリケーションに制限されています。(たとえば、NMAPのための)いくつかのツールは、通常は70限り多くがあるプローブの20個の未満のUDPサービスがあり、(例えば、NESUS)商用ツールの数。いくつかのケースでは、サービスは、ポート上で聴くことができますが、特定のプローブに応答しないように設定されています。
-------------------------------------------------- ---------------------------
最後のテスト手順によって主に最後に見つけることができる3つの短所:
①直接ドメイン名を入力してスキャンをサポートしていません:IPアドレスが特に良い思い出ではない、我々は通常、覚えて、このURLのドメインであるかの順序でのping cmdでIPアドレスを取得する必要性を照会することによって、非常に不便です。
②connect()関数は、デフォルトでブロックされ、ポートスキャンは、スキャンのホストのために開いているポートではなく、オンライン、いくつかの時間を特にないがかかります無意味になり、ホストを決定するためにスキャンする前に、それはまた、多くの時間を要し回避することができ、いくつかの有用な作業を行うためのオンラインプログラムです。
③開いているポートに接続したときに時間を要し、接続ポートスキャンを活用する大きな予定で約0.05sではなく、開いているポートは、21Sを消費している、ほとんど立ち往生したときに開いているポートではありませんスキャンが21秒。スキャン速度を向上させ、時間を節約するために、複数の再送信を避けるために、デフォルトのタイムアウトを設定するには()関数を接続するには
ポートスキャンツールを最適化するために次のことを知ることができます。
ポイント1:IPアドレス機能へのドメイン名
ポイント2:ホストの生存テスト
つまり、テストはpingを実行できるかどうか、ホストがオンラインであるかどうかを判断することである生存テストをホストします。
ポイント3:遅延スキャンノンブロッキング
実験は、ここで見つけることができる2つの関数の構造に関する:
① FD_SET:
これは、配列マクロ定義は、実際には、ある長型の配列であり、各アレイ要素は、ファイルハンドル(ソケット、ファイル、パイプ、設備、など)コンタクトを確立すると開くことができるプログラマによって行わ作動接点を確立するために、 )(セレクト呼び出すとき、読み取り可能なハンドルを選択し()プロセスの実装を通知することは、カーネルによって状態に応じてIO FD_SETの内容を変更します。
主にオペレーティングシステムが機能を提供します。
② int型のioctlsocket(int型の、長いCMD、u_longの* argpは)。:
S:インタフェース記述子のセットを識別する。
CMD:Sの動作コマンドソケット。
argpは:指し示すポインタに、cmdコマンドパラメータをもたらしました。
③は(FD_SET FAR、int型nfds個* readfds、FD_SET * writefds、FD_SET * exceptfds、constのいるstruct timeval *タイムアウト)選択をint型。:
nfds個:範囲内の整数値は、すべてのファイルディスクリプタ、すなわち、最大のすべてのファイル記述子の値プラス1のセットですされ、パラメータの値は、あなたが正しく設定することができ、Windowsの問題ではありません。
readfds :(ソケットの読みやすさをチェックするために待機しているセットへのオプション)のポインタ。
writefds :(書き込みチェック待っているソケットのセットへのオプション)のポインタ。
エラーチェックソケットの待機グループにexceptfds :(オプション)のポインタ。
タイムアウト:ブロッキング操作にほとんどの時間を待つために()を選択するには、NULLです。
注:使用に注意する非ブロック接続の問題があります:
すぐに1がこのような状況に対処しなければならない、接続(同じマシン上で、たとえば、クライアントおよびサーバ)を確立する接続を呼び出す可能性があります。
2. POSIXでは、関連する2を定義し、非ブロック接続条項を選択します:
A. 接続が正常に確立され、ソケット記述子が書き込み可能になりました。(接続が確立されると、ライトバッファが空いている、書き込むことができます)
B. 接続に失敗し、ソケットディスクリプタは読み出し可能と書き込み可能の両方です。(エラーが保留されているので、そう可読および書き込み可能)
マルチスレッド
・ 条件:ホストポートスキャン、40秒のスキャン時間の変わり目に、2000件のスレッドを開きました。
・ ボトルネック:5000以上を開くかどうか、かなりのスキャン時間を短縮することはできません。
・ ボトルネックソリューション:あなたが開いている1000個のポートがリストをスキャンし、オンライン、社会学+プログラミングがなければならない最も頻繁に使用することができます。
* 注:ソケットは、貴重なシステムリソースは、シャットダウンする必要はありませんで、クリティカル領域でのマルチスレッドのリソースをロックします。
参考:https://www.cnblogs.com/woniu-felix/p/10826157.html
// PortScanf.cpp : 定义控制台应用程序的入口点。
//
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#include <cstdio>
#include <iostream>
#include <ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32")
#pragma comment(lib, "Ws2_32.lib")
using namespace std;
//获取超时时间
unsigned long nTimeout;
//#include <winsock2.h>
//#pragma comment(lib, "WS2_32")
//线程个数
#define THREADCOUNT 2000
DWORD WINAPI ThreadProc(LPVOID lpParameter);
char IP[32] = "";
//端口号
int PortNum = 0;
//临界区变量
CRITICAL_SECTION cs;
//线程函数
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
//创建套接字
//SOCKET TryConnect;
SOCKET s;
WSADATA wsa;
//SOCKET s;
struct sockaddr_in server;
int CurrPort; //当前端口
//int ret;
WSAStartup(MAKEWORD(2, 2), &wsa); //使用winsock函数之前,必须用WSAStartup函数来装入并初始化动态连接库
server.sin_family = AF_INET; //指定地址格式,在winsock中只能使用AF_INET
server.sin_addr.s_addr = inet_addr(IP); //指定被扫描的IP地址
while (1)
{
if (PortNum > 65535)
{
break;
}
//进入临界区
EnterCriticalSection(&cs);
int tmpport = PortNum;
PortNum++;
//DWORD threadID=GetCurrentThreadId();
//printf("线程%d正在检测端口%d\n",threadID,PortNum);//所有使用临界区资源的代码都要加锁
//离开临界区
LeaveCriticalSection(&cs);
WSADATA wsa;
//SOCKET s;
struct sockaddr_in server;
//int CurrPort; //当前端口
//int ret;
WSAStartup(MAKEWORD(2, 2), &wsa); //使用winsock函数之前,必须用WSAStartup函数来装入并初始化动态连接库
server.sin_family = AF_INET; //指定地址格式,在winsock中只能使用AF_INET
server.sin_addr.s_addr = inet_addr(IP); //指定被扫描的IP地址
SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
server.sin_port = htons(tmpport); //指定被扫描IP地址的端口号
TIMEVAL TimeOut;
FD_SET mask;
unsigned long mode = 1; //ipctlsocket函数的最后一个参数
//设置超时毫秒数
TimeOut.tv_sec = 0;
TimeOut.tv_usec = nTimeout;
FD_ZERO(&mask);
FD_SET(s, &mask);
//设置为非阻塞模式
ioctlsocket(s, FIONBIO, &mode);
connect(s, (struct sockaddr *)&server, sizeof(server)); //连接
int ret = select(0, NULL, &mask, NULL, &TimeOut);
if (ret != 0 && ret != -1) //判断连接是否成功
{
printf("%s:%d Success O(∩_∩)O~~\n", IP, tmpport);
closesocket(s);
}
else {
//printf("%s:%d Failed\n", Ip, CurrPort);
}
closesocket(s);//防止开启太多socket连接,导致后面socket分配无效
}
return 0;
}
typedef struct _IPHeader
{
unsigned char iphVerLen;
unsigned char ipTOS;
unsigned short ipLength;
unsigned short ipID;
unsigned short ipFlags;
unsigned char ipTTL;
unsigned char ipProtocol;
USHORT ipChecksum;
ULONG ipSource;
ULONG ipDestination;
} IPHeader, *PIPHeader;
typedef struct icmp_hdr
{
unsigned char icmp_type;
unsigned char icmp_code;
unsigned short icmp_checksum;
unsigned short icmp_id;
unsigned short icmp_sequence;
unsigned long icmp_timestamp;
} ICMP_HDR, *PICMP_HDR;
typedef struct _EchoRequest {
ICMP_HDR icmphdr;
char cData[32];
}ECHOREQUEST, *PECHOREQUEST;
#define REQ_DATASIZE 32
typedef struct _EchoReply {
IPHeader iphdr;
ECHOREQUEST echoRequest;
}ECHOREPLAY, *PECHOREPLAY;
USHORT checksum(USHORT* buff, int size)
{
u_long cksum = 0;
while (size > 1)
{
cksum = cksum + *buff;
buff = buff + 1;
size = size - sizeof(USHORT);
}
if (size == 1)
{
USHORT u = 0;
u = (USHORT)(*(UCHAR*)buff);
cksum = cksum + u;
}
cksum = (cksum >> 16) + (cksum & 0x0000ffff);
cksum = cksum + (cksum >> 16);
u_short answer = (u_short)(~cksum);
return (answer);
}
//我的ping程序
BOOL MyPing(char *szDestIp)
{
WSADATA wsaData;
WORD version = MAKEWORD(2, 2);
int ret = WSAStartup(version, &wsaData);
if (ret != 0) {
printf(" 加载Winsock库错误! \n");
return 0;
}
/*char szDestIp[100];
printf("输入所要连接的外网地址:\n");
scanf("%s", szDestIp);*/
SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
int nTimeOut = 1000;
// 设置接收超时
setsockopt(sRaw, SOL_SOCKET, SO_RCVTIMEO, (char const*)&nTimeOut, sizeof(nTimeOut));
SOCKADDR_IN dest;
dest.sin_family = AF_INET;
dest.sin_port = htons(0);
dest.sin_addr.S_un.S_addr = inet_addr(szDestIp);
ECHOREQUEST echoReq;
echoReq.icmphdr.icmp_type = 8;
echoReq.icmphdr.icmp_code = 0;
echoReq.icmphdr.icmp_id = (USHORT)GetCurrentProcessId();
echoReq.icmphdr.icmp_checksum = 0;
echoReq.icmphdr.icmp_sequence = 0;
memset(&echoReq.cData, 'E', 32);
USHORT nSeq = 0; SOCKADDR_IN from;
int nLen = sizeof(from);
int fail = 0;
int success = 0;
int i = 0;
int a[4];
int isFail = 0;
int timeQ;
while (TRUE) {
printf("正在循环\n");
static int nCount = 0; int nRet;
if (nCount++ == 4) break;
echoReq.icmphdr.icmp_checksum = 0;
echoReq.icmphdr.icmp_timestamp = GetTickCount();
echoReq.icmphdr.icmp_sequence = nSeq++;
echoReq.icmphdr.icmp_checksum = checksum((USHORT*)&echoReq, sizeof(echoReq));
nRet = sendto(sRaw, (char*)&echoReq, sizeof(echoReq), 0, (SOCKADDR *)&dest, sizeof(dest));
if (nRet == SOCKET_ERROR) {
printf(" sendto() failed: %d \n", WSAGetLastError());
//system("pause");
return false;
}
ECHOREPLAY echoReply;
nRet = recvfrom(sRaw, (char*)&echoReply, sizeof(ECHOREPLAY), 0, (sockaddr*)&from, &nLen);
if (nRet == SOCKET_ERROR) {
if (WSAGetLastError() == WSAETIMEDOUT) {
printf(" timed out\n");
printf("时间超时\n");
fail++;
continue;
}
printf(" recvfrom() failed: %d\n", WSAGetLastError());
isFail = 1;
printf("来自172.16.4.42的回复:无法访问目标主机\n");
success++;
continue;
}
if (nRet < sizeof(ECHOREPLAY)) {
printf(" Too few bytes from %s \n", inet_ntoa(from.sin_addr));
return false;
}
if (echoReply.echoRequest.icmphdr.icmp_type != 0) {
printf(" nonecho type %d recvd \n", echoReply.echoRequest.icmphdr.icmp_type);
//system("pause");
return false;
}
if (echoReply.echoRequest.icmphdr.icmp_id != GetCurrentProcessId()) {
printf(" someone else's packet! \n");
//system("pause");
return false;
}
printf(" %d bytes Reply from %s: \n", nRet, inet_ntoa(from.sin_addr));
printf(" icmp_seq = %d. ", echoReply.echoRequest.icmphdr.icmp_sequence);
int nTick = GetTickCount();
success++;
printf(" time: %d ms", nTick - echoReply.echoRequest.icmphdr.icmp_timestamp);
a[i] = nTick - echoReply.echoRequest.icmphdr.icmp_timestamp;
i++;
printf(" TTL= %d ", echoReply.iphdr.ipTTL);
//printf(echoReply.echoRequest.cData);
printf(" \n");
Sleep(1000);
}
printf("%s 的ping的统计信息:\n", szDestIp);
printf("数据包:已发送 = %d,已接收 = %d,丢失 = %d\n", success, success, fail);
if (isFail != 1) {
printf("往返程的估计时间:(以毫秒记)\n");
int timeC = a[0];
int timeD = a[0];
int timeA = a[0];
int j;
for (j = 1; j < 4; j++) {
if (timeC < a[j]) {
timeC = a[j];
}
if (timeD > a[j]) {
timeD = a[j];
}
timeA = timeA + a[j];
}
timeA = timeA / 4;
printf("最短 = %d 最长 = %d 平均 = %d\n", timeD, timeC, timeA);
}
else {
}
printf("跳出循环!\n");
if (fail == 4)
{
return false;
}
closesocket(sRaw);
WSACleanup();
//system("pause");
return true;
}
//扫描端口
int scant(char *Ip, int StartPort, int EndPort)
{
WSADATA wsa;
//SOCKET s;
struct sockaddr_in server;
int CurrPort; //当前端口
//int ret;
WSAStartup(MAKEWORD(2, 2), &wsa); //使用winsock函数之前,必须用WSAStartup函数来装入并初始化动态连接库
server.sin_family = AF_INET; //指定地址格式,在winsock中只能使用AF_INET
server.sin_addr.s_addr = inet_addr(Ip); //指定被扫描的IP地址
cout << "设置超时时间:" << endl;
cout << ">>";
//获取超时时间
unsigned long nTimeout;
cin >> nTimeout;
//逐个连接从开始端口到结束端口
for (CurrPort = StartPort; CurrPort <= EndPort; CurrPort++)
{
SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
server.sin_port = htons(CurrPort); //指定被扫描IP地址的端口号
TIMEVAL TimeOut;
FD_SET mask;
unsigned long mode = 1; //ipctlsocket函数的最后一个参数
//设置超时毫秒数
TimeOut.tv_sec = 0;
TimeOut.tv_usec = nTimeout;
FD_ZERO(&mask);
FD_SET(s, &mask);
//设置为非阻塞模式
ioctlsocket(s, FIONBIO, &mode);
connect(s, (struct sockaddr *)&server, sizeof(server)); //连接
int ret = select(0, NULL, &mask, NULL, &TimeOut);
if (ret != 0 && ret != -1) //判断连接是否成功
{
printf("%s:%d Success O(∩_∩)O~~\n", Ip, CurrPort);
closesocket(s);
}
else {
//printf("%s:%d Failed\n", Ip, CurrPort);
}
}
//printf("Cost time:%f second\n", CostTime); //输出扫描过程中耗费的时间
//closesocket(server);
WSACleanup(); //释放动态连接库并释放被创建的套接字
return 1;
}
//扫描端口
int scant2(char *Ip, int StartPort, int EndPort)
{
WSADATA wsa;
//SOCKET s;
struct sockaddr_in server;
int CurrPort; //当前端口
//int ret;
WSAStartup(MAKEWORD(2, 2), &wsa); //使用winsock函数之前,必须用WSAStartup函数来装入并初始化动态连接库
server.sin_family = AF_INET; //指定地址格式,在winsock中只能使用AF_INET
server.sin_addr.s_addr = inet_addr(Ip); //指定被扫描的IP地址
cout << "设置超时时间:" << endl;
cout << ">>";
//获取超时时间
unsigned long nTimeout;
cin >> nTimeout;
//逐个连接从开始端口到结束端口
for (CurrPort = StartPort; CurrPort <= EndPort; CurrPort++)
{
SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
server.sin_port = htons(CurrPort); //指定被扫描IP地址的端口号
TIMEVAL TimeOut;
FD_SET mask;
unsigned long mode = 1; //ipctlsocket函数的最后一个参数
//设置超时毫秒数
TimeOut.tv_sec = 0;
TimeOut.tv_usec = nTimeout;
FD_ZERO(&mask);
FD_SET(s, &mask);
//设置为非阻塞模式
ioctlsocket(s, FIONBIO, &mode);
connect(s, (struct sockaddr *)&server, sizeof(server)); //连接
int ret = select(0, NULL, &mask, NULL, &TimeOut);
if (ret != 0 && ret != -1) //判断连接是否成功
{
printf("%s:%d Success O(∩_∩)O~~\n", Ip, CurrPort);
closesocket(s);
}
else {
//printf("%s:%d Failed\n", Ip, CurrPort);
}
}
//printf("Cost time:%f second\n", CostTime); //输出扫描过程中耗费的时间
//closesocket(server);
WSACleanup(); //释放动态连接库并释放被创建的套接字
return 1;
}
//发送控制器
void sendController(char ip[])
{
if (MyPing(ip) == false) //ping失败
{
cout << "ping失败!" << endl;
return;
}
else
{
cout << "ping成功!" << endl;
}
cout << "选择:(1.单线程扫描指定端口范围 2.多线程扫描全部端口)" << endl;
cout << ">>";
int option;
cin >> option;
if (option == 1)
{
cout << "输入你要查询的起始端口:" << endl;
cout << ">>";
int startPort;
cin >> startPort;
cout << "输入你要查询的结束端口:" << endl;
cout << ">>";
int endPort;
cin >> endPort;
cout << "设置超时时间:" << endl;
cout << ">>";
cin >> nTimeout;
scant(ip, startPort, endPort);
}
else if (option == 2)
{
cout << "设置超时时间:" << endl;
cout << ">>";
cin >> nTimeout;
char tempIp[32];
strcpy(IP, ip); //OK
//初始化套接字
WSADATA ws;
::WSAStartup(MAKEWORD(2, 0), &ws);
DWORD start = GetTickCount();
//初始化临界区
InitializeCriticalSection(&cs);
//多线程扫描
HANDLE hThread[THREADCOUNT];
for (int i = 0; i < THREADCOUNT; i++)
{
hThread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, (LPVOID)0, 0, NULL);
}
//当thread数量超过64的处理
int tempNumThreads = THREADCOUNT;
int tempMax = 0;
while (tempNumThreads >= MAXIMUM_WAIT_OBJECTS)
{
tempNumThreads -= MAXIMUM_WAIT_OBJECTS;
WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, &hThread[tempMax], false, INFINITE);
tempMax += MAXIMUM_WAIT_OBJECTS;
}
WaitForMultipleObjects(tempNumThreads, &hThread[tempMax], false, INFINITE);
//删除临界区
DeleteCriticalSection(&cs);
DWORD end = GetTickCount();
printf("use time(s):%f\n", (end - start) / 1000.0);
}
}
//域名装换ip函数
int hostnameToIp()
{
//使用Ws2_32.dll的初始化
WORD wVersionRequested = 0;
WSADATA wsaData = {};
int err = 0;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
{
return -1;
}
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 )
{
WSACleanup( );
return -1;
}
//////////////////////////
char** pptr = NULL;
char szHostName[256] = {};
cout << "--------------------------------------" << endl;
cout << "输入域名:";
//while( cin.getline( szHostName, sizeof(szHostName) ) )
//{
cin.getline(szHostName, sizeof(szHostName));
HOSTENT* pHostEntry = gethostbyname( szHostName );
if( NULL != pHostEntry && szHostName[0] != '\0' )
{
//将主机的规范名输出
cout << "主机规范名:" << pHostEntry->h_name << endl;
//主机别名。可含多个
int i = 0;
for ( i = 1, pptr = pHostEntry->h_aliases; *pptr != NULL; ++pptr )
{
cout << "主机别名" << i++ << ":" << *pptr << endl;
}
//将主机地址列表输出,可含多个
char szIpBuff[32] = {0};
for ( i = 1, pptr = pHostEntry->h_addr_list; *pptr != NULL; ++pptr )
{
cout << "A" << endl;
if (i == 1) //只使用一个ip
{
memset(szIpBuff, 0, sizeof(szIpBuff));
//inet_ntop的返回值为NULL,则表示失败。否则返回对应的IP地址(此时szIpRet指向的是szIpBuff)
const char* szIpRet = inet_ntop(pHostEntry->h_addrtype, *pptr, szIpBuff, sizeof(szIpBuff));
if (szIpBuff != NULL)
{
cout << "解析IP地址" << i++ << ":" << szIpRet << endl;
char *buf = new char[strlen(szIpRet) + 1];
strcpy(buf, szIpRet);
sendController(buf);
}
}
else
{
break;
}
}
}
else
{
cout << "解析失败。" << endl;
}
cout << "hostnameToip结束" << endl;
memset( szHostName, 0, sizeof(szHostName) );
cout << "--------------------------------------" << endl;
//cout << "输入域名:";
WSACleanup();
return 0;
}
int main()
{
hostnameToIp();
//cout << "请输入你要扫描的ip:" << endl;
//cout << ">>";
//char * ip = new char[50];
//cin >> ip;
//char szIpBuff[32] = { 0 };
//cout << "域名转ip:" << szIpBuff << endl;
//cout << "输入你要查询的起始端口:" << endl;
//cout << ">>";
//int startPort;
//cin >> startPort;
//cout << "输入你要查询的结束端口:" << endl;
//cout << ">>";
//int endPort;
//cin >> endPort;
//scant(ip, startPort, endPort);
system("pause");
return 0;
}
この実験的研究を通じて、我々はポートスキャンツールの最適化を完了しました。IPアドレスにドメイン名、ホスト生存試験及び遅延スキャン機能、マルチスレッド走査:これは、4つの部分を含みます。最初のマルチユース、マルチスレッドスキャンと比較して、あなたのポートスキャンをスピードアップすることができます。
マルチスレッドの実装:
スレッド関数を設計します
//スレッド関数
DWORD WINAPI ThreadProc(LPVOID lpParameter )
絶えず上昇して、ポートの数、0〜65535のポート番号を設定するスレッド機能は、重要な領域の使用は、複数のスレッドを使用する際に何の繰り返しは、ポートを訪れていないことを確認します。
//クリティカルセクションを入力します。
EnterCriticalSection(&CS);
int型 tmpport = PortNumを。
PortNumを++;
// DWORDスレッドID = GetCurrentThreadId()。
//のprintf(「%d個のスレッドは、ポート%dは\ nを検出している」、スレッドID、PortNumを); //すべてのコードリソースの使用クリティカルセクションはロックされます
//クリティカル領域を残します
LeaveCriticalSection(&CS);
使用多线程扫描临界区,当线程数量超过64时,可以使用WaitForMultipleObjects函数处理,这个函数其实作用其实就是可以不让在一瞬间创建一大堆线程,而是以64个线程为一个单位,当其中某个线程结束时,再触发下一个单位的线程,放缓线程的创建速度。
//初始化临界区
InitializeCriticalSection(&cs);
//多线程扫描
HANDLE hThread[THREADCOUNT];
for (int i = 0; i < THREADCOUNT; i++)
{
hThread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, (LPVOID)0, 0, NULL);
}
//当thread数量超过64的处理
int tempNumThreads = THREADCOUNT;
int tempMax = 0;
while (tempNumThreads >= MAXIMUM_WAIT_OBJECTS)
{
tempNumThreads -= MAXIMUM_WAIT_OBJECTS;
WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, &hThread[tempMax], false, INFINITE);
tempMax += MAXIMUM_WAIT_OBJECTS;
}
WaitForMultipleObjects(tempNumThreads, &hThread[tempMax], false, INFINITE);
//删除临界区
DeleteCriticalSection(&cs);
(2)域名转换ip地址使用gethostbyname这个函数得到域名的相关信息,然后使用inet_ntop解析IP地址
const char* szIpRet = inet_ntop(pHostEntry->h_addrtype, *pptr, szIpBuff, sizeof(szIpBuff));
(3)存活测试适应ping程序看是否ping通,但是在此期间我遇到了一个问题,就是发送的数据包时间过长,没有接到回复,所以要设置超时时间。
// 设置接收超时
setsockopt(sRaw, SOL_SOCKET, SO_RCVTIMEO, (char const*)&nTimeOut, sizeof(nTimeOut));
(4)非阻塞与延时扫描使用
TIMEVAL TimeOut;
FD_SET mask;
unsigned long mode = 1; //ipctlsocket函数的最后一个参数
//设置超时毫秒数
TimeOut.tv_sec = 0;
TimeOut.tv_usec = nTimeout;
FD_ZERO(&mask);
FD_SET(s, &mask);
//设置为非阻塞模式
ioctlsocket(s, FIONBIO, &mode);
connect(s, (struct sockaddr *)&server, sizeof(server)); //连接
int ret = select(0, NULL, &mask, NULL, &TimeOut);