C# 多线程与线程扫描器

多线程扫描器是一种并发执行的网络安全工具,用于扫描目标网络上的主机和端口,以发现可能存在的漏洞或弱点。扫描器利用多线程并发地扫描目标主机和端口,通过对网络通信的分析和响应处理,发现潜在的安全问题。它能够提高扫描效率和准确性,缩短扫描时间,并帮助管理员或安全专家识别和修复可能存在的漏洞。

其原理基于以下几个关键步骤:

  1. 目标选择:确定要扫描的目标网络或主机。这可以是单个IP地址、IP地址范围或域名。

  2. 端口扫描:使用多线程技术并发地扫描目标主机的端口。常见的端口扫描方法包括TCP连接扫描、SYN扫描、UDP扫描等。每个线程负责扫描一个或多个端口,并记录响应结果。

  3. 并发处理:为了提高扫描速度,多线程扫描器同时执行多个扫描任务。每个线程负责处理一个目标主机或一个端口范围。通过合理的线程管理和调度策略,可以有效地利用计算资源。

  4. 响应处理:根据端口扫描的结果,对每个目标主机或端口进行相应的处理。这可能包括判断端口是否开放、识别服务和应用程序、检测漏洞等。具体的响应处理方式取决于扫描器的设计和目的。

  5. 结果报告:将扫描结果整理并生成报告。报告可以包括目标主机列表、开放的端口列表、发现的漏洞或弱点等信息。通常,报告可以以文本、HTML或其他格式输出,以便用户进行进一步分析和处理。

获取本机IP地址

这段代码是一个简单的示例,代码的作用是获取本机的IPv4和IPv6地址,并将其输出到控制台。

  1. GetLocalAddress 方法是用来获取本机的IP地址列表。它接收一个参数 netType,用于指定要获取的地址类型,可以是 "InterNetwork"(IPv4)或 "InterNetworkV6"(IPv6)。方法内部使用 Dns.GetHostName() 获取主机名,然后使用 Dns.GetHostAddresses() 获取该主机名对应的IP地址数组。根据 netType 的值,筛选出符合条件的IP地址并添加到 IpList 列表中,最后返回该列表。

  2. Main 方法中,首先调用 GetLocalAddress 方法获取本机的IPv4地址列表,并使用 foreach 循环遍历输出每个地址。

  3. 接下来,调用 GetLocalAddress 方法获取本机的IPv6地址列表,并同样使用 foreach 循环输出每个地址。

  4. 最后,使用 Console.ReadKey() 方法等待用户按下任意键后程序结束。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        public static List<string> GetLocalAddress(string netType)
        {
            string HostName = Dns.GetHostName();
            IPAddress[] address = Dns.GetHostAddresses(HostName);
            List<string> IpList = new List<string>();

            if(netType == string.Empty)
            {
                for (int i = 0; i < address.Length; i++)
                {
                    IpList.Add(address[i].ToString());
                }
            }
            else
            {
                for (int i = 0; i < address.Length; i++)
                {
                    if (address[i].AddressFamily.ToString() == netType)
                    {
                        IpList.Add(address[i].ToString());
                    }
                }
            }
            return IpList;
        }

        static void Main(string[] args)
        {
            // 获取IPV4地址
            List<string> ipv4 = GetLocalAddress("InterNetwork");
            foreach (string each in ipv4)
                Console.WriteLine(each);

            // 获取IPV6地址
            List<string> ipv6 = GetLocalAddress("InterNetworkV6");
            foreach (string each in ipv6)
                Console.WriteLine(each);

            Console.ReadKey();
        }
    }
}

线程操作基础

这段代码是一个简单的示例,代码的作用是创建一个新的线程,并获取和显示线程的一些基本信息,然后等待子线程执行完毕。同时,在子线程函数中输出一条信息。

  1. 首先,在 My_Thread 方法中定义了一个无参的线程函数,它会在执行时输出一条信息。

  2. Main 方法中,创建了一个 ThreadStart 委托对象 childref,该委托用于指定线程要执行的方法。然后使用 childref 初始化一个新的线程 thread

  3. 调用 thread.Start() 方法启动线程。

  4. 使用一些属性和方法来获取和显示线程的信息:

    • thread.ManagedThreadId 返回线程的唯一标识符。
    • thread.Name 返回线程的名称。
    • thread.ThreadState 返回线程的状态,以字符串形式表示。
    • thread.Priority 返回线程的优先级。
    • thread.IsBackground 表示线程是否为后台线程。
  5. 使用 Thread.Sleep(1000) 让主线程暂停一秒,让子线程有足够的时间运行。

  6. 使用 thread.Join() 方法等待子线程执行完毕。

  7. 最后,使用 Console.ReadKey() 方法等待用户按下任意键后程序结束。

using System;
using System.Collections;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        // 定义一个无参线程函数
        public static void My_Thread()
        {
            Console.WriteLine("线程函数已运行");
        }

        static void Main(string[] args)
        {
            string strinfo = string.Empty;

            ThreadStart childref = new ThreadStart(My_Thread);
            Thread thread = new Thread(childref);
            thread.Start();

            Console.WriteLine("线程唯一标识符: " + thread.ManagedThreadId);
            Console.WriteLine("线程名称: " + thread.Name);
            Console.WriteLine("线程状态: " + thread.ThreadState.ToString());
            Console.WriteLine("线程优先级: " + thread.Priority.ToString());
            Console.WriteLine("是否为后台线程: " + thread.IsBackground);

            Thread.Sleep(1000);
            thread.Join();

            Console.ReadKey();
        }
    }
}

线程传递参数

这段代码是一个多线程示例,代码的作用是创建了200个线程,每个线程输出一个包含姓名和年龄信息的结构体对象的内容,并在输出后休眠3秒钟。这样可以模拟多个线程同时执行,并展示多线程的并发特性。

  1. 首先,在 ThreadObj 结构体中定义了两个字段 nameage,用于存储姓名和年龄的信息。

  2. My_Thread 方法中,通过将 obj 强制转换为 ThreadObj 结构体类型,获取传递给线程的姓名和年龄信息,并输出到控制台。然后通过 Thread.Sleep(3000) 让线程休眠3秒钟。

  3. Main 方法中,使用 for 循环创建200个线程。在每次循环中,创建一个新的 ThreadObj 对象,并将姓名设为 "admin",年龄设为循环变量 x 的值。然后创建一个新的线程 thread,将 My_Thread 方法作为线程函数,并将 obj 作为参数传递给线程。最后,将线程的 IsBackground 属性设置为 true,以确保在主线程结束时,后台线程也会自动结束。

  4. 执行完循环后,通过 Console.ReadKey() 方法等待用户按下任意键后程序结束。

using System;
using System.Collections;
using System.Threading;

namespace ConsoleApplication1
{
    public struct ThreadObj
    {
        public string name;
        public int age;

        public ThreadObj(string _name, int _age)
        {
            this.name = _name;
            this.age = _age;
        }
    }

    class Program
    {
        // 定义一个无参线程函数
        public static void My_Thread(object obj)
        {
            ThreadObj thread_path = (ThreadObj)obj;
            Console.WriteLine("姓名: {0} 年纪: {1}", thread_path.name, thread_path.age);
            Thread.Sleep(3000);
        }

        static void Main(string[] args)
        {
            for(int x=0;x<200;x++)
            {
                ThreadObj obj = new ThreadObj("admin", x);
                Thread thread = new Thread(My_Thread);
                thread.IsBackground = true;

                thread.Start(obj);
            }
            Console.ReadKey();
        }
    }
}

实现端口扫描

这段代码是一个简单的端口扫描程序,代码通过循环尝试连接指定 IP 地址上的各个端口,并输出每个端口的开放状态。它可以用于快速扫描指定 IP 地址上的常见端口,以便进行网络安全评估或服务探测。请注意,这只是一个简单的示例,并不能完整地表示端口扫描的所有细节和技术。在实际应用中,需要考虑更多的因素,例如扫描范围、扫描速度和权限等。

  1. 首先定义了一个整型数组 Port,其中包含了要扫描的端口号。

  2. foreach 循环中,对于每个端口号,创建一个新的 Socket 对象 sock,指定了地址族为 InterNetwork,套接字类型为 Stream,协议类型为 IP

  3. 使用 sock.Connect("192.168.1.10", each) 尝试连接到指定的 IP 地址和端口。如果连接成功,则表示该端口开放,输出 "端口开启:"加上端口号。

  4. 如果连接失败,捕获异常并输出 "端口关闭:"加上端口号,然后关闭套接字。

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            // FTP, SSH, Telnet, SMTP, HTTP, POP3, RPC, SMB, SMTP, IMAP, POP3
            int[] Port = new int[] { 21, 22, 23, 25, 80, 110, 135, 445, 587, 993, 995 };

            foreach(int each in Port)
            {
                Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
                try
                {
                    sock.Connect("192.168.1.10",each);
                    if(sock.Connected)
                    {
                        Console.WriteLine("端口开启:" + each);
                    }
                }
                catch
                {
                    Console.WriteLine("端口关闭:" + each);
                    sock.Close();
                }
            }
        }
    }
}

多线程端口扫描

这段代码实现了一个具有超时功能的端口扫描程序。这段代码可以用于快速扫描指定 IP 地址范围内的多个端口,并输出每个端口的开放状态。它利用了异步连接操作和超时机制,可以提高扫描效率,并避免长时间等待连接的情况。请注意,在实际使用中,应该遵守法律和道德规范,并遵循适当的授权和使用方式。

主要代码解析如下:

  1. 定义了一个私有字段 ip,用于存储目标 IP 地址,以及一个整型数组 ports,包含要扫描的端口号列表。

  2. Connect 方法接受一个 IPEndPoint 对象和超时时间(以毫秒为单位),并返回一个布尔值表示连接是否成功。在方法中,创建一个 Socket 对象 scanSocket,指定地址族为 InterNetwork,套接字类型为 Stream,协议类型为 IP

  3. 调用 scanSocket.BeginConnect 方法发起异步连接操作,使用 result.AsyncWaitHandle.WaitOne 等待连接操作完成,超时时间由 TimeSpan.FromMilliseconds(timeoutMSec) 指定。如果连接操作完成且成功建立连接,则返回 true,否则返回 false

  4. Main 方法中,创建 TimeoutPortScan 对象 ps,然后遍历指定的 IP 地址范围(从1到255),构建目标 IP 地址。

  5. 对于每个 IP 地址,遍历 ports 数组,调用 ps.Connect 方法尝试与目标主机的每个端口建立连接,超时时间设置为100毫秒。

  6. 如果连接成功,则输出 "IP: {0} --> 端口: {1} --> 状态: Open",其中 {0}{1} 分别代表目标 IP 地址和端口号。

using System;
using System.Net;
using System.Net.Sockets;

namespace TimeoutPortScan
{
    class TimeoutPortScan
    {
        private IPAddress ip;
        private readonly int[] ports = new int[] { 21, 22, 23, 25, 53, 80, 110, 118, 135, 143, 156, 161, 
            443, 445, 465, 587, 666, 990, 991, 993, 995, 1080, 1433, 1434, 1984, 2049, 2483, 2484, 3128, 
            3306, 3389, 4662, 4672, 5222, 5223, 5269, 5432, 5500, 5800, 5900, 8000, 8008, 8080 };

        public bool Connect(IPEndPoint remoteEndPoint, int timeoutMSec)
        {
            Socket scanSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
            try
            {
                IAsyncResult result = scanSocket.BeginConnect(remoteEndPoint, null, null);
                bool success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromMilliseconds(timeoutMSec), false);
                if (result.IsCompleted && scanSocket.Connected)
                {
                    scanSocket.EndConnect(result);
                    return true;
                }
                else
                    return false;
            }
            finally
            {
                scanSocket.Close();
            }
        }

        static void Main(string[] args)
        {
            TimeoutPortScan ps = new TimeoutPortScan();

            for (int x = 1; x < 255;x++ )
            {
                string addr = string.Format("192.168.1.{0}", x);
                IPAddress.TryParse(addr, out ps.ip);

                for (int num = 0; num < ps.ports.Length; num++)
                {
                    if (ps.Connect(new IPEndPoint(ps.ip, ps.ports[num]), 100))
                        Console.WriteLine("IP:{0} --> 端口: {1} --> 状态: Open", addr,ps.ports[num]);
                }
            }
        }
    }
}

异步端口扫描

这段代码实现了一个异步端口扫描程序。它从命令行参数中提取目标 IP 地址、起始端口和结束端口,然后使用异步连接方式扫描指定范围内的端口,并输出开放的端口号。它利用异步连接操作和回调函数来实现非阻塞的扫描过程,提高了扫描效率。注意,在实际使用中,请遵守法律和道德规范,并遵循适当的授权和使用方式。

主要代码解析如下:

  1. Main 方法获取命令行参数,并调用 GetPortRange 方法解析目标 IP 地址、起始端口和结束端口。如果解析成功,则调用 Scan 方法进行端口扫描。

  2. GetPortRange 方法用于从命令行参数中提取目标 IP 地址、起始端口和结束端口。如果命令行参数符合要求,则将提取的值赋给相应的变量,并返回 true;否则,返回 false。如果命令行参数为 /?/h/help,则输出帮助信息。

  3. Scan 方法用于进行端口扫描。它使用一个 Socket 对象 scanSocket,指定地址族为 InterNetwork,套接字类型为 Stream,协议类型为 IP。然后,循环遍历指定的端口范围,在每次循环中创建一个新的随机端口进行绑定,以避免与已有的端口冲突。

  4. 在每次循环中,使用 scanSocket.BeginConnect 方法发起异步连接操作,指定目标 IP 地址和端口号,并提供一个回调函数 ScanCallBack。回调函数的第一个参数是 IAsyncResult 对象,用于获取异步连接的结果。回调函数的第二个参数是一个 ArrayList 对象,包含了需要在回调函数中使用的额外参数(scanSocketport)。

  5. 在回调函数 ScanCallBack 中,首先解析回调函数的输入参数,并判断端口是否连接成功。如果连接成功,则输出 "端口: {0,5} 状态: Open",其中 {0,5} 代表端口号,并关闭 scanSocket

using System;
using System.Net;
using System.Net.Sockets;
using System.Collections;

namespace AsyncPortScan
{
    class AsyncPortScan
    {
        static void Main(string[] args)
        {
            IPAddress ip;
            int startPort, endPort;
            if (GetPortRange(args, out ip, out startPort, out endPort) == true)  // 提取命令行参数
                Scan(ip, startPort, endPort);   // 端口扫描
        }

        /// 从命令行参数中提取端口
        private static bool GetPortRange(string[] args, out IPAddress ip, out int startPort, out int endPort)
        {
            ip = null;
            startPort = endPort = 0;
            // 帮助命令
            if (args.Length != 0 && (args[0] == "/?" || args[0] == "/h" || args[0] == "/help"))
            {
                Console.WriteLine("scan 192.168.1.10 100 2000");
                return false;
            }

            if (args.Length == 3)
            {
                // 解析端口号成功
                if (IPAddress.TryParse(args[0], out ip) && int.TryParse(args[1], out startPort) && int.TryParse(args[2], out endPort))
                    return true;
                else
                    return false;
            }
            else
            {
                return false;
            }
        }
        /// 端口 扫描
        static void Scan(IPAddress ip, int startPort, int endPort)
        {
            Random rand = new Random((int)DateTime.Now.Ticks);
            for (int port = startPort; port < endPort; port++)
            {
                Socket scanSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
                //寻找一个未使用的端口进行绑定
                do
                {
                    try
                    {
                        scanSocket.Bind(new IPEndPoint(IPAddress.Any, rand.Next(65535)));
                        break;
                    }
                    catch
                    {
                        //绑定失败
                    }
                } while (true);

                try
                {
                    scanSocket.BeginConnect(new IPEndPoint(ip, port), ScanCallBack, new ArrayList() { scanSocket, port });
                }
                catch
                {
                    continue;
                }
            }
        }

        /// BeginConnect的回调函数 异步Connect的结果
        static void ScanCallBack(IAsyncResult result)
        {
            // 解析 回调函数输入 参数
            ArrayList arrList = (ArrayList)result.AsyncState;
            Socket scanSocket = (Socket)arrList[0];
            int port = (int)arrList[1];
            // 判断端口是否开放
            if (result.IsCompleted && scanSocket.Connected)
            {
                Console.WriteLine("端口: {0,5} 状态: Open", port);
            }
            scanSocket.Close();
        }
    }
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

微软技术分享

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值