C++ Boost 实现异步端口扫描器

端口扫描是一种用于识别目标系统上哪些网络端口处于开放、关闭或监听状态的网络活动。在计算机网络中,端口是一个虚拟的通信端点,用于在计算机之间传输数据。每个端口都关联着特定类型的网络服务或应用程序。端口扫描通常是网络管理员、安全专业人员用来评估网络安全的一种方法。通过扫描目标系统的端口,可以了解系统上哪些服务在运行、哪些端口是开放的,从而评估系统的安全性。

常见的端口扫描技术包括:

  • TCP端口扫描: 通过发送TCP连接请求来确定目标系统上的端口是否开放。常见的TCP扫描包括全连接扫描(Connect Scan)、半开放扫描(SYN Scan)等。
  • UDP端口扫描: 通过向目标系统发送UDP数据包,观察是否收到相应来判断UDP端口是否开放。UDP扫描较为复杂,因为UDP是一种无连接的协议,难以确定是否因为端口关闭而未响应。
  • NULL、FIN和Xmas Tree扫描: 这些扫描技术利用TCP协议的特殊性质,尝试向目标系统发送非法或异常的TCP数据包,观察目标系统的响应。
  • IDLE扫描: 利用一个第三方系统(通常是僵尸主机)发送探测包,通过观察目标系统的响应来判断端口状态。这种扫描方法更难被目标系统检测到。

本章我们将运用Boost框架实现一个基于TCP的扫描工具,TCP端口扫描是一种常见的网络扫描技术,通过发送TCP连接请求来确定目标系统上的端口是否开放,其本质上是通过调用Socket套接字中的connect()尝试连接对应的端口,如果该端口开放则连接将被建立,由此我们就可以得出该端口是存活的,利用这一特性我们就可以实现批量的端口探测功能。

生成C段地址

C段地址通常指的是IPv4地址中的子网地址,其中C表示了地址的网络前缀的类别。IPv4地址按照其前缀的长度被分为A、B、C、D和E五个类别,每个类别用于不同规模的网络。

在IPv4地址中,每个地址由32位二进制数字组成,通常以点分十进制(Dotted-Decimal Notation)的形式表示,例如,192.168.0.1。IPv4地址的前面的一部分被分配给网络,而后面的部分则分配给主机。

  • A类地址: 以0开头,用于大型网络,例如1.0.0.0到126.0.0.0。
  • B类地址: 以10开头,用于中型网络,例如128.0.0.0到191.255.0.0。
  • C类地址: 以110开头,用于小型网络,例如192.0.0.0到223.255.255.0。

因此,当我们说一个IPv4地址属于C段地址时,通常指的是这个地址的前缀是C类地址的范围,即以192.x.x.x223.x.x.x的范围。例如,192.168.1.1是一个C段地址,因为它的前缀是192。在这样的地址中,最后三个字节通常用于主机标识。

同样我们在实现端口扫描之前需要生成一个C段地址中所有的主机IP,这里我们可以通过Boost库中的字符串拼接功能来实现生成特定主机网段,具体实现细节如下所示;

  • 例如192.168.1.1/100则代表要枚举出这个网段中所有的地址,并将其存储到std::vector<std::string>容器中。
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <iostream>
#include <vector>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>

using namespace std;
using namespace boost;

// 传递IP地址范围,自动生成IP地址表
bool CalculationAddress(std::string address, std::vector<std::string> &ref)
{
  std::vector<std::string> vect;
  try
  {
    // 以/,两个下划线作为切割符号,切割后放入vect容器中
    boost::split(vect, address, boost::is_any_of("/") || boost::is_any_of("."), boost::token_compress_on);

    // 将开始和结束地址取出来
    int start_count = lexical_cast<int>(vect[3]);
    int end_count = lexical_cast<int>(vect[4]);

    // IP地址中的C段必须小于255
    if (end_count <= 255)
    {
      for (int x = start_count; x <= end_count; x++)
      {
        std::string this_address = boost::str(boost::format("%s.%s.%s.%s") % vect[0] % vect[1] % vect[2] % x);
        ref.push_back(this_address);
      }
    }
    else
    {
      return false;
    }
  }
  catch (...)
  {
    return false;
  }
  return true;
}

int main(int argc, char * argv[])
{
  // 生成 192.168.1.1/100 这个范围内的地址表
  std::vector<std::string> address_ref;
  bool flag = CalculationAddress("192.168.1.1/255", address_ref);

  if (flag == true)
  {
    // 输出地址表
    for (int x = 0; x < address_ref.size(); x++)
    {
      std::cout << "地址表: " << address_ref[x] << std::endl;
    }
  }

  std::system("pause");
  return 0;
}

上述函数CalculationAddress通过传入范围192.168.1.1/100即可实现生成1-100以内的所有IP地址字符串,并将其存储到address_ref容器内,输出效果如下图所示;

端口字符串提取

接着我们还需要实现一个提取端口字符串的功能,例如当使用者传入22,23,135,139时,我们将其解析成独立的整数类型,并将其存储到std::vector<int>容器内保存,该功能的实现只需要使用boost::split函数切割并循环将数据放入到整数容器内即可,如下所示;

#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <iostream>
#include <vector>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>

using namespace std;
using namespace boost;

// 传递端口字符串,解析为vector容器
bool CalculationPort(std::string port_string, std::vector<int> &ref)
{
  std::vector<std::string> vect;
  try
  {
    boost::split(vect, port_string, boost::is_any_of(","), boost::token_compress_on);

    for (int x = 0; x < vect.size(); x++)
    {
      ref.push_back(lexical_cast<int>(vect[x]));
    }
    return true;
  }
  catch (...)
  {
    return false;
  }
  return true;
}

int main(int argc, char * argv[])
{
  // 传入字符串端口,自动解析为vector容器
  std::vector<int> port_ref;
  bool flag = CalculationPort("22,23,55,135", port_ref);

  if (flag == true)
  {
    // 输出地址表
    for (int x = 0; x < port_ref.size(); x++)
    {
      std::cout << "端口表: " << port_ref[x] << std::endl;
    }
  }

  std::system("pause");
  return 0;
}

通过boost中的函数可以很容易实现字符串的切割,运行后可看到字符串被解析成了独立的整数,如下图所示;

异步端口探测

Boost.Asio是一个强大的C++库,提供了异步I/O和网络编程的支持。本文将介绍如何使用Boost.Asio实现异步连接,以及如何设置超时机制,确保连接在规定的时间内建立。Asio是Boost库中的一个模块,用于异步I/O和网络编程。它提供了一种灵活的方式来处理异步操作,使得程序能够更高效地利用系统资源。Boost.Asio支持TCP、UDP、SSL等协议,使得开发者能够轻松实现异步网络通信。

异步连接实现

在本文的代码示例中,我们使用Boost.Asio创建了一个AsyncConnect类,用于执行异步连接。这个类包含了异步连接的主要逻辑,其中使用了tcp::socketdeadline_timer来处理异步操作和超时。

#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <iostream>
#include <string>
#include <boost/asio.hpp> 
#include <boost/bind.hpp>  
#include <boost/date_time/posix_time/posix_time_types.hpp>  

using namespace std;
using boost::asio::ip::tcp;

// 异步连接地址与端口
class AsyncConnect
{
public:
  AsyncConnect(boost::asio::io_service& ios, tcp::socket &s)
    :io_service_(ios), timer_(ios), socket_(s) {}

  // 异步连接
  bool aysnc_connect(const tcp::endpoint &ep, int million_seconds)
  {
    bool connect_success = false;

    // 异步连接,当连接成功后将触发 connect_handle 函数
    socket_.async_connect(ep, boost::bind(&AsyncConnect::connect_handle, this, _1, boost::ref(connect_success)));

    // 设置一个定时器  million_seconds 
    timer_.expires_from_now(boost::posix_time::milliseconds(million_seconds));
    bool timeout = false;

    // 异步等待 如果超时则执行 timer_handle
    timer_.async_wait(boost::bind(&AsyncConnect::timer_handle, this, _1, boost::ref(timeout)));
    do
    {
      // 等待异步操作完成
      io_service_.run_one();
      // 判断如果timeout没超时,或者是连接建立了,则不再等待
    } while (!timeout && !connect_success);
    timer_.cancel();
    return connect_success;
  }

private:
  // 如果连接成功了,则 connect_success = true
  void connect_handle(boost::system::error_code ec, bool &connect_success)
  {
    if (!ec)
    {
      connect_success = true;
    }
  }

  // 定时器超时timeout = true
  void timer_handle(boost::system::error_code ec, bool &timeout)
  {
    if (!ec)
    {
      socket_.close();
      timeout = true;
    }
  }
  boost::asio::io_service &io_service_;
  boost::asio::deadline_timer timer_;
  tcp::socket &socket_;
};
探测主函数

在主函数中,我们创建了一个AsyncConnect对象,并使用它进行异步连接。这个例子中,我们尝试连接到IP地址为"202.89.233.101",端口号为80的服务器,并设置了连接超时时间为300毫秒。

int main(int argc, char * argv[])
{
  try
  {
    boost::asio::io_service io;
    tcp::socket socket(io);
    AsyncConnect hander(io, socket);
    tcp::endpoint ep(boost::asio::ip::address::from_string("8.141.58.64"), 80);

    // 传递扫描ep地址结构,以及超时时间
    if (hander.aysnc_connect(ep, 300))
    {
      std::cout << "连通了" << std::endl;
      io.run();
    }
    else
    {
      std::cout << "连接失败" << std::endl;
    }

  }
  catch (...)
  {
    return false;
  }

  std::system("pause");
  return 0;
}

通过本文的示例,我们展示了如何使用Boost.Asio创建异步连接,并设置连接超时。异步连接的实现可以提高程序的性能和效率,特别适用于需要处理大量并发连接的网络应用场景。Boost.Asio的灵活性使得开发者能够更方便地处理异步I/O操作,提高程序的健壮性和可维护性。

当代码被运行时,则自动探测特定地址的特定端口是否开放,如果开放则返回如下图所示;

端口扫描封装

实现端口扫描

首先增加PortScan函数该函数传入地址端口号以及超时时间,自动扫描端口开放状态,这里我们就以扫描192.168.1.1端口从78-100扫描后将结果输出到屏幕上。

// 封装端口扫描函数
bool PortScan(std::string address, int port, int timeout)
{
  try
  {
    boost::asio::io_service io;
    tcp::socket socket(io);
    AsyncConnect hander(io, socket);
    tcp::endpoint ep(boost::asio::ip::address::from_string(address), port);

    // 传递扫描ep地址结构,以及超时时间
    if (hander.aysnc_connect(ep, timeout))
    {
      io.run();
      return true;
    }
    else
    {
      return false;
    }

  }
  catch (...)
  {
    return false;
  }
}

int main(int argc, char * argv[])
{
  for (int x = 78; x < 100; x++)
  {
    bool is_open = PortScan("192.168.1.1", x, 1000);
    std::cout << "扫描端口: " << x << " 状态: " << is_open << std::endl;
  }

  std::system("pause");
  return 0;
}

运行上述代码即可扫描特定的端口是否开放,输出效果如下图所示;

实现特定端口扫描

实现CalculationPort函数,用户传入一串字符串自动解析为端口号,并调用扫描功能对特定端口进行扫描。

#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <iostream>
#include <string>
#include <boost/asio.hpp> 
#include <boost/bind.hpp>  
#include <boost/date_time/posix_time/posix_time_types.hpp>

#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>

using namespace std;
using namespace boost;
using boost::asio::ip::tcp;

// 传递端口字符串,解析为vector容器
bool CalculationPort(std::string port_string, std::vector<int> &ref)
{
	std::vector<std::string> vect;
	try
	{
		boost::split(vect, port_string, boost::is_any_of(","), boost::token_compress_on);

		for (int x = 0; x < vect.size(); x++)
		{
			ref.push_back(lexical_cast<int>(vect[x]));
		}
		return true;
	}
	catch (...)
	{
		return false;
	}
	return true;
}

int main(int argc, char * argv[])
{
	std::string scan_address = "192.168.1.1";
	std::vector<int> scan_port_list;

	bool scan_ref = CalculationPort("80,443,445,135,139", scan_port_list);
	if (scan_ref == true)
	{
		// 循环取出需要扫描的端口对目标进行扫描
		for (int x = 0; x < scan_port_list.size(); x++)
		{
			bool is_open = PortScan(scan_address, scan_port_list[x], 1000);
			if (is_open == true)
			{
				std::cout << "扫描地址: " << scan_address << " 扫描端口: " << scan_port_list[x] << " 扫描状态: 端口开放" << std::endl;
			}
			else
			{
				std::cout << "扫描地址: " << scan_address << " 扫描端口: " << scan_port_list[x] << " 扫描状态: 端口关闭" << std::endl;
			}
		}
	}
	std::system("pause");
	return 0;
}

运行上述代码即可扫描地址192.168.1.1下的80,443,445,135,139端口开放状态,如下图所示;

增加参数解析

Boost Program Options 是Boost库中的一个模块,用于处理程序的命令行选项。它提供了一个灵活的框架,使得开发者能够轻松地解析和处理命令行参数。

#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <iostream>
#include <string>
#include <boost/asio.hpp> 
#include <boost/bind.hpp>  
#include <boost/date_time/posix_time/posix_time_types.hpp>

#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>

#include <boost/program_options.hpp>

using namespace std;
using namespace boost;
using boost::asio::ip::tcp;
namespace opt = boost::program_options;

int main(int argc, char * argv[])
{
  opt::options_description des_cmd("\n Usage: LyShark 端口扫描器 Ver:1.0 \n\n Options");
  des_cmd.add_options()
    ("address,a", opt::value<std::string>()->default_value("127.0.0.1"), "指定扫描地址")
    ("set_port,s", opt::value<std::string>()->default_value("none"), "设置扫描端口")
    ("help,h", "帮助菜单");

  opt::variables_map virtual_map;
  try
  {
    opt::store(opt::parse_command_line(argc, argv, des_cmd), virtual_map);
  }
  catch (...){ return 0; }

  // 定义消息
  opt::notify(virtual_map);

  // 无参数直接返回
  if (virtual_map.empty())
  {
    return 0;
  }
  else if (virtual_map.count("help") || virtual_map.count("h"))
  {
    std::cout << des_cmd << std::endl;
    return 0;
  }
  else if (virtual_map.count("address") && virtual_map.count("set_port"))
  {
    std::string address = virtual_map["address"].as<std::string>();
    std::string set_port = virtual_map["set_port"].as<std::string>();

    // 判断是不是默认参数
    if (address == "127.0.0.1" || set_port == "none")
    {
      std::cout << des_cmd << std::endl;
    }
    else
    {
      // 执行扫描流程
      std::vector<int> scan_port_list;

      bool scan_ref = CalculationPort(set_port, scan_port_list);
      if (scan_ref == true)
      {
        // 循环取出需要扫描的端口对目标进行扫描
        for (int x = 0; x < scan_port_list.size(); x++)
        {
          bool is_open = PortScan(address, scan_port_list[x], 1000);
          if (is_open == true)
          {
            std::cout << "扫描地址: " << address << " 扫描端口: " << scan_port_list[x] << " 扫描状态: 端口开放" << std::endl;
          }
          else
          {
            std::cout << "扫描地址: " << address << " 扫描端口: " << scan_port_list[x] << " 扫描状态: 端口关闭" << std::endl;
          }
        }
      }
    }
  }
  else
  {
    std::cout << "参数错误" << std::endl;
  }
  return 0;

  std::system("pause");
  return 0;
}

当有了命令解析功能,我们就可以向程序内传入参数,如下所示;

多线程扫描
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <iostream>
#include <string>
#include <boost/asio.hpp> 
#include <boost/bind.hpp>  
#include <boost/date_time/posix_time/posix_time_types.hpp>

#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>

#include <boost/program_options.hpp>

#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/function.hpp>
#include <boost/thread/thread_guard.hpp>

using namespace std;
using namespace boost;
using boost::asio::ip::tcp;
namespace opt = boost::program_options;

boost::mutex io_mutex;

// 实现多线程扫描
void MyThread(std::string address, int port)
{
  bool is_open = PortScan(address, port, 1000);
  // boost::mutex::scoped_lock lock(io_mutex);

  boost::lock_guard<boost::mutex> global_mutex(io_mutex);
  if (is_open == true)
  {
    std::cout << "扫描地址: " << address << " 扫描端口: " << port << " 扫描状态: 开放" << std::endl;
  }
  else
  {
    std::cout << "扫描地址: " << address << " 扫描端口: " << port << " 扫描状态: 关闭" << std::endl;
  }
}

int main(int argc, char * argv[])
{
  opt::options_description des_cmd("\n Usage: LyShark 端口扫描器 Ver:1.0 \n\n Options");
  des_cmd.add_options()
    ("address,a", opt::value<std::string>()->default_value("127.0.0.1"), "指定扫描地址")
    ("set_port,s", opt::value<std::string>()->default_value("none"), "设置扫描端口")
    ("help,h", "帮助菜单");

  opt::variables_map virtual_map;
  try
  {
    opt::store(opt::parse_command_line(argc, argv, des_cmd), virtual_map);
  }
  catch (...){ return 0; }

  // 定义消息
  opt::notify(virtual_map);

  // 无参数直接返回
  if (virtual_map.empty())
  {
    return 0;
  }
  else if (virtual_map.count("help") || virtual_map.count("h"))
  {
    std::cout << des_cmd << std::endl;
    return 0;
  }
  else if (virtual_map.count("address") && virtual_map.count("set_port"))
  {
    std::string address = virtual_map["address"].as<std::string>();
    std::string set_port = virtual_map["set_port"].as<std::string>();

    // 判断是不是默认参数
    if (address == "127.0.0.1" || set_port == "none")
    {
      std::cout << des_cmd << std::endl;
    }
    else
    {
      // 执行扫描流程
      std::vector<int> scan_port_list;

      bool scan_ref = CalculationPort(set_port, scan_port_list);
      if (scan_ref == true)
      {
        boost::thread_group group;
        // 循环取出需要扫描的端口对目标进行扫描
        for (int x = 0; x < scan_port_list.size(); x++)
        {
          group.create_thread(boost::bind(MyThread, address, scan_port_list[x]));
        }
        group.join_all();
      }
    }
  }
  else
  {
    std::cout << "参数错误" << std::endl;
  }
  return 0;

  std::system("pause");
  return 0;
}

运行效果如下图所示,通过使用多线程可提高程序的扫描效率。

完整扫描器代码
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <iostream>
#include <string>
#include <boost/asio.hpp> 
#include <boost/bind.hpp>  
#include <boost/date_time/posix_time/posix_time_types.hpp>

#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>

#include <boost/program_options.hpp>

#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/function.hpp>
#include <boost/thread/thread_guard.hpp>

using namespace std;
using namespace boost;
using boost::asio::ip::tcp;
namespace opt = boost::program_options;

boost::mutex io_mutex;

void ShowOpt()
{
  fprintf(stderr,
    "#                       #                          #       \n"
    "#                       #                          #       \n"
    "#     #    #    #####   ######    ######   # ###   #   ##  \n"
    "#     #    #   #        #     #  #     #   ##      #  #    \n"
    "#     #    #    ####    #     #  #     #   #       ###     \n"
    "#      #####        #   #     #  #    ##   #       #  #    \n"
    "#####      #   #####    #     #   #### #   #       #   ##  \n\n"
    );
}

// 异步连接地址与端口
class AsyncConnect
{
public:
  AsyncConnect(boost::asio::io_service& ios, tcp::socket &s)
    :io_service_(ios), timer_(ios), socket_(s) {}

  // 异步连接
  bool aysnc_connect(const tcp::endpoint &ep, int million_seconds)
  {
    bool connect_success = false;

    // 异步连接,当连接成功后将触发 connect_handle 函数
    socket_.async_connect(ep, boost::bind(&AsyncConnect::connect_handle, this, _1, boost::ref(connect_success)));

    // 设置一个定时器  million_seconds 
    timer_.expires_from_now(boost::posix_time::milliseconds(million_seconds));
    bool timeout = false;

    // 异步等待 如果超时则执行 timer_handle
    timer_.async_wait(boost::bind(&AsyncConnect::timer_handle, this, _1, boost::ref(timeout)));
    do
    {
      // 等待异步操作完成
      io_service_.run_one();
      // 判断如果timeout没超时,或者是连接建立了,则不再等待
    } while (!timeout && !connect_success);
    timer_.cancel();
    return connect_success;
  }

private:
  // 如果连接成功了,则 connect_success = true
  void connect_handle(boost::system::error_code ec, bool &connect_success)
  {
    if (!ec)
    {
      connect_success = true;
    }
  }

  // 定时器超时timeout = true
  void timer_handle(boost::system::error_code ec, bool &timeout)
  {
    if (!ec)
    {
      socket_.close();
      timeout = true;
    }
  }
  boost::asio::io_service &io_service_;
  boost::asio::deadline_timer timer_;
  tcp::socket &socket_;
};

// 封装端口扫描函数
bool PortScan(std::string address, int port, int timeout)
{
  try
  {
    boost::asio::io_service io;
    tcp::socket socket(io);
    AsyncConnect acHandler(io, socket);
    tcp::endpoint ep(boost::asio::ip::address::from_string(address), port);

    // 传递扫描ep地址结构,以及超时时间
    if (acHandler.aysnc_connect(ep, timeout))
    {
      io.run();
      return true;
    }
    else
    {
      return false;
    }

  }
  catch (...)
  {
    return false;
  }
}

// 传递IP地址范围,自动生成IP地址表
bool CalculationAddress(std::string address, std::vector<std::string> &ref)
{
  std::vector<std::string> vect;
  try
  {
    // 以/,两个下划线作为切割符号,切割后放入vect容器中
    boost::split(vect, address, boost::is_any_of("/") || boost::is_any_of("."), boost::token_compress_on);

    // 将开始和结束地址取出来
    int start_count = lexical_cast<int>(vect[3]);
    int end_count = lexical_cast<int>(vect[4]);

    // IP地址中的C段必须小于255
    if (end_count <= 255)
    {
      for (int x = start_count; x <= end_count; x++)
      {
        std::string this_address = boost::str(boost::format("%s.%s.%s.%s") % vect[0] % vect[1] % vect[2] % x);
        ref.push_back(this_address);
      }
    }
    else
    {
      return false;
    }
  }
  catch (...)
  {
    return false;
  }
  return true;
}

// 传递端口字符串,解析为vector容器
bool CalculationPort(std::string port_string, std::vector<int> &ref)
{
  std::vector<std::string> vect;
  try
  {
    boost::split(vect, port_string, boost::is_any_of(","), boost::token_compress_on);

    for (int x = 0; x < vect.size(); x++)
    {
      ref.push_back(lexical_cast<int>(vect[x]));
    }
    return true;
  }
  catch (...)
  {
    return false;
  }
  return true;
}

// 实现多线程扫描
void MyThread(std::string address, int port)
{
  bool is_open = PortScan(address, port, 1000);
  // boost::mutex::scoped_lock lock(io_mutex);

  boost::lock_guard<boost::mutex> global_mutex(io_mutex);
  if (is_open == true)
  {
    std::cout << "扫描地址: " << address << " 扫描端口: " << port << " 扫描状态: 开放" << std::endl;
  }
  else
  {
    std::cout << "扫描地址: " << address << " 扫描端口: " << port << " 扫描状态: 关闭" << std::endl;
  }
}

// 实现全端口线程扫描
void MyThreadB(std::string address, int port)
{
  bool is_open = PortScan(address, port, 1000);
  // boost::mutex::scoped_lock lock(io_mutex);

  boost::lock_guard<boost::mutex> global_mutex(io_mutex);
  if (is_open == true)
  {
    std::cout << "扫描地址: " << address << " 扫描端口: " << port << " 扫描状态: 开放" << std::endl;
  }
}

int main(int argc, char * argv[])
{
  opt::options_description des_cmd("\n Usage: LyShark 端口扫描器 Ver:1.1 \n\n Options");
  des_cmd.add_options()
    ("address,a", opt::value<std::string>(), "指定扫描地址 192.168.1.1")
    ("c_address,c", opt::value<std::string>(), "设置扫描C地址段 192.168.1.1/24")
    ("set_port,s", opt::value<std::string>(), "设置扫描端口 80,443,135,139")
    ("type,t", opt::value<std::string>(), "对特定主机 扫描 1-65535 全端口")
    ("help,h", "帮助菜单");

  opt::variables_map virtual_map;
  try
  {
    opt::store(opt::parse_command_line(argc, argv, des_cmd), virtual_map);
  }
  catch (...){ return 0; }

  // 定义消息
  opt::notify(virtual_map);

  // 无参数直接返回
  if (virtual_map.empty())
  {
    ShowOpt();
    std::cout << des_cmd << std::endl;
    return 0;
  }
  else if (virtual_map.count("help") || virtual_map.count("h"))
  {
    ShowOpt();
    std::cout << des_cmd << std::endl;
    return 0;
  }
  // 扫描全端口
  else if (virtual_map.count("address") && virtual_map.count("type"))
  {
    std::string address = virtual_map["address"].as<std::string>();
    std::string type = virtual_map["type"].as<std::string>();

    if (address.length() != 0 && type == "all")
    {
      // 执行全端口扫描
      boost::thread_group group;
      for (int x = 0; x < 65534; x++)
      {
        group.create_thread(boost::bind(MyThreadB, address, x));
        _sleep(50);
      }
      group.join_all();
    }
  }

  // 扫描特定端口
  else if (virtual_map.count("address") && virtual_map.count("set_port"))
  {
    std::string address = virtual_map["address"].as<std::string>();
    std::string set_port = virtual_map["set_port"].as<std::string>();

    // 执行特定端口扫描
    std::vector<int> scan_port_list;

    bool scan_ref = CalculationPort(set_port, scan_port_list);
    if (scan_ref == true)
    {
      boost::thread_group group;
      // 循环取出需要扫描的端口对目标进行扫描
      for (int x = 0; x < scan_port_list.size(); x++)
      {
        group.create_thread(boost::bind(MyThread, address, scan_port_list[x]));
      }
      group.join_all();
    }
  }

  // 扫描特定地址段中的特定端口
  else if (virtual_map.count("c_address") && virtual_map.count("set_port"))
  {
    std::string c_address = virtual_map["c_address"].as < std::string >();
    std::string set_port = virtual_map["set_port"].as<std::string>();

    // 计算出需要扫描的端口
    std::vector<int> scan_port_list;
    bool scan_port_ref = CalculationPort(set_port, scan_port_list);

    // 计算出需要扫描的地址段
    std::vector < std::string > scan_address_list;

    bool scan_address_ref = CalculationAddress(c_address, scan_address_list);

    if (scan_port_ref == true && scan_address_ref == true)
    {
      // 分别取出每一个IP地址
      for (int x = 0; x < scan_address_list.size(); x++)
      {
        boost::thread_group group;
        // 对每一个IP地址中的端口段进行扫描
        for (int y = 0; y < scan_port_list.size(); y++)
        {
          group.create_thread(boost::bind(MyThreadB, scan_address_list[x], scan_port_list[y]));
        }
        group.join_all();
      }
    }
  }
  else
  {
    std::cout << "参数错误" << std::endl;
  }
  return 0;
}

至此,一个基于ASIO异步模型的,多线程端口扫描器就这么完成了,总结帮助手册。

  • 扫描全端口: lyscanner.exe --address 192.168.1.1 --type all
  • 扫描整个C段: lyscanner.exe --c_address 192.168.1.1/10 --set_port 22,25
  • 特定端口扫描: lyscanner.exe --address 192.168.1.1 --set_port 22,25,135,139

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/175646.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PyTorch微调终极指南1:预训练模型调整

如今&#xff0c;在训练深度学习模型时&#xff0c;通过根据自己的数据微调预训练模型来进行迁移学习&#xff08;transfer learning&#xff09;已成为首选方法。 通过微调这些模型&#xff0c;我们可以利用他们的专业知识并使它们适应我们的特定任务&#xff0c;从而节省宝贵…

uniapp - 开关按钮

目录 1.运行代码如下&#xff1a; 2.运行效果 3.switch属性 1.运行代码如下&#xff1a; <template><view class"switchBox"><switch change"switchChange" color"#F21177" :checked"form.checked" /></view&…

Python简直是万能的,这5大主要用途你一定要知道!

从2015开始国内就开始慢慢接触Python了&#xff0c;从16年开始Python就已经在国内的热度更高了&#xff0c;目前也可以算的上"全民Python"了。 众所周知小学生的教材里面已经有Python了&#xff0c;国家二级计算机证也需要学习Python了&#xff01; 因为Python简单…

消息中间件——RabbitMQ(四)命令行与管控台的基本操作!

前言 在前面的文章中我们介绍过RabbitMQ的搭建&#xff1a;RabbitMQ的安装过以及各大主流消息中间件的对比&#xff1a;&#xff0c;本章就主要来介绍下我们之前安装的管控台是如何使用以及如何通过命令行进行操作。 1. 命令行操作 1.1 基础服务的命令操作 rabbitmqctl sto…

2023年中国高压驱动芯片分类、市场规模及发展趋势分析[图]

高压驱动芯片是一种能在高压环境下工作的集成电路&#xff0c;主要用于控制和驱动各种功率器件&#xff0c;如继电器、电磁阀、电机、变频器等。高压驱动芯片根据其输出电流的大小和形式可分为两类恒流型和开关型。 高压驱动芯片分类 资料来源&#xff1a;共研产业咨询&#x…

Windows系统如何安装与使用TortoiseSVN客户端,并实现在公网访问本地SVN服务器

文章目录 前言1. TortoiseSVN 客户端下载安装2. 创建检出文件夹3. 创建与提交文件4. 公网访问测试 前言 TortoiseSVN是一个开源的版本控制系统&#xff0c;它与Apache Subversion&#xff08;SVN&#xff09;集成在一起&#xff0c;提供了一个用户友好的界面&#xff0c;方便用…

深入了解ECharts

文章目录 导言一、什么是ECharts&#xff1f;二、基本概念1.ECharts实例2.数据系列&#xff08;Series&#xff09;3.坐标轴&#xff08;Axis&#xff09; 三、基本图表类型1.折线图2.柱状图3.饼图 高级功能1.题定制2.事件交互3.地图可视化 总结我是将军&#xff0c;我一直都在…

埃尔米特插值(hermite 插值) C++

埃尔米特插值 原理 #pragma once #include <vector> #include <functional> /*埃尔米特插值*/ struct InterpolationPoint {double x; // 插值点的横坐标double y; // 插值点的纵坐标double derivative; // 插值点的导数值// 默认构造函数InterpolationPoint() : x…

SpringBoot项目启动后自动停止了?

1 现象 2023-11-22T09:05:13.36108:00 DEBUG 17521 --- [ main] o.s.b.a.ApplicationAvailabilityBean : Application availability state LivenessState changed to CORRECT 2023-11-22T09:05:13.36208:00 DEBUG 17521 --- [ main] o.s.b.a.Applicat…

D-Wave推出新开源及解决无线信道解码新方案!

​&#xff08;图片来源&#xff1a;网络&#xff09; 加拿大量子计算机公司D-Wave&#xff08;纽约证券交易所股票代码&#xff1a;QBTS&#xff09;是量子计算系统、软件和服务领域的佼佼者&#xff0c;也是全球首家商业量子计算机供应商。 近期&#xff0c;该公司发布了一…

数据库实验一 数据表的创建与修改管理

数据库实验一、数据表的创建与修改管理实验 一、实验目的二、设计性实验三、观察与思考 一、实验目的 (1) 掌握表的基础知识。 (2) 掌握使用SQL语句创建表的方法。 (3) 掌握表的修改、查看、删除等基本操作方法。 (4) 掌握表中完整性约束的定义。 (5) 掌握完整性约束的作用 二…

腾讯云轻量数据库开箱测评,1核1G轻量数据库测试

腾讯云轻量数据库1核1G开箱测评&#xff0c;轻量数据库服务采用腾讯云自研的新一代云原生数据库TDSQL-C&#xff0c;轻量数据库兼100%兼容MySQL数据库&#xff0c;实现超百万级 QPS 的高吞吐&#xff0c;128TB海量分布式智能存储&#xff0c;虽然轻量数据库为单节点架构&#x…

外贸自建站的指南?新手如何玩转海洋建站?

外贸自建站工具有哪些&#xff1f;外贸新手怎么搭建独立网站&#xff1f; 拥有自己的外贸网站是提高企业国际竞争力和扩大市场份额的有效途径。然而&#xff0c;许多企业在外贸自建站的过程中感到困惑。海洋建站将为您提供一份详细的外贸自建站指南&#xff0c;助您轻松打造一…

时序预测 | MATLAB实现基于ELM-AdaBoost极限学习机结合AdaBoost时间序列预测

时序预测 | MATLAB实现基于ELM-AdaBoost极限学习机结合AdaBoost时间序列预测 目录 时序预测 | MATLAB实现基于ELM-AdaBoost极限学习机结合AdaBoost时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.Matlab实现ELM-Adaboost时间序列预测&#xff0c;极…

RFID电网资产全寿命周期管理解决方案

一、方案背景 随着电网公司对电网资产全寿命周期管理的要求日益明确&#xff0c;许多电网公司已经开始积极推进存量资产PMS、PM与AM数据的联动对应&#xff0c;并将联动成果纳入资产全寿命周期管理一体化平台进行指标考核。然而&#xff0c;由于资产变动导致数据质量下降的问题…

SpringBoot中使用注解的方式创建队列和交换机

SpringBoot中使用注解的方式创建队列和交换机 前言 最开始蘑菇博客在进行初始化配置的时候&#xff0c;需要手动的创建交换机&#xff0c;创建队列&#xff0c;然后绑定交换机&#xff0c;这个步骤是非常繁琐的&#xff0c;而且一不小心的话&#xff0c;还可能就出了错误&…

FSCTF2023-Reverse方向题解WP。学习贴

文章目录 [FSCTF 2023]signin[FSCTF 2023]MINE SWEEPER[FSCTF 2023]Xor[FSCTF 2023]EZRC4[FSCTF 2023]ez_pycxor[FSCTF 2023]Tea_apk[FSCTF 2023]ezcode[FSCTF 2023]ezbroke[FSCTF 2023]rrrrust!!![FSCTF2023]ezrev&#xff08;未解决&#xff09; [FSCTF 2023]signin UPX壳&am…

Fiddler模拟弱网环境

1.设置弱网&#xff1a;Rules-》Customize Rules 上传速度&#xff1a;1KB/300ms1KB/0.3s3.33KB/s 下载速度&#xff1a;1KB/150ms1KB/0.15s6.67KB/s 2.启动弱网&#xff1a;Rules-》Performance-》Simulate Modem Speeds 开启后&#xff0c;此项为勾选状态 3.验证弱网生效…

Activiti7工作流引擎:生成实时的流程图片

实时获取当前流程对应的流程图片&#xff0c;并对当前正在审批的节点进行高亮显示。 public class ActivitiController {Autowiredprivate ProcessEngine processEngine;Autowiredprivate RepositoryService repositoryService;Autowiredprivate RuntimeService runtimeService…

处理无线debug问题

无限debug的产生 条件说明 开发者工具是打开状态 js代码中有debugger js有定时处理 setInterval(() > {(function (a) {return (function (a) {return (Function(Function(arguments[0]" a ")()))})(a)})(bugger)(de, 0, 0, (0, 0)); }, 1000); ​ #这里就…