使用Java开发多线程端口扫描工具(二)

一 介绍

这一篇文章是紧接着上一篇文章(http://www.zifangsky.cn/2015/12/使用java开发多线程端口扫描工具/)写的,端口扫描的原理不用多少,我在上一篇文章中已经说过了,至于目的大家都懂得。在这一篇文章里,我主要是对端口扫描工具的继续完善,以及写出一个比较直观的图形界面出来,以方便我们测试使用。界面如下:

这个工具主要是实现了以下几点功能:(1)两种扫描方式,一种是只扫描常见端口,另一种是设置一个起始和结束端口,依次探测。当然,原理很简单,用for循环就可以了;(2)输入一个域名或者IP后,可以自定义扫描线程,这一点是非常有用的,因为有的服务器是装了360,云锁或者安全狗的,扫描线程过大或许会被封IP。

注:文末我会给出简易的可执行jar文件的下载链接

二 代码实现

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class PortScan extends JFrame implements ActionListener {
	private static final long serialVersionUID = 1L;
	private GridBagLayout gridbag;
	private GridBagConstraints constraints;
	private JPanel mainJPanel,panel1,panel1_1,panel1_2,panel2,panel2_2,panel3,panel4,panel5;
	private ButtonGroup buttonGroup;  //扫描方式组
	private JRadioButton scanType1,scanType2;  //扫描方式1,扫描方式2
	private JLabel startJLabel,endJLabel,threadNum;  //起始端口和结束端口 线程数
	private JLabel progressJLabel,resultJLabel;  //进度和结果
	private JTextField customPorts,startPort,endPort,customDomain,customThreadNum;  //常见端口,起始和结束端口;自定义域名,自定义线程数
	private JButton beginJButton;  //开始扫描
	private JScrollPane progressPane,resultPane;  //进度面板和结果面板
	private JTextArea progressJtJTextArea,resultJTextArea;  //同上

	private JMenuBar jMenuBar;
	private JMenu help;
	private JMenuItem author,contact,version,readme;

	private Font menuFont = new Font("宋体", Font.LAYOUT_NO_LIMIT_CONTEXT, 14);  //菜单字体
	private Font contentFont = new Font("宋体", Font.LAYOUT_NO_LIMIT_CONTEXT, 16);  //正文字体

	public PortScan(){
		super("多线程端口扫描工具");
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		setPreferredSize(new Dimension(900, 600));
		int frameWidth = this.getPreferredSize().width;  //界面宽度
		int frameHeight = this.getPreferredSize().height;  //界面高度
		setSize(frameWidth,frameHeight);
		setLocation((screenSize.width - frameWidth) / 2,(screenSize.height - frameHeight) / 2);

		//初始化
		mainJPanel = new JPanel();
		panel1 = new JPanel();
		panel1_1 = new JPanel();
		panel1_2 = new JPanel();
		panel2 = new JPanel();
		panel2_2 = new JPanel();
		panel3 = new JPanel();
		panel4 = new JPanel();
		panel5 = new JPanel();
		buttonGroup = new ButtonGroup();
		scanType1 = new JRadioButton("扫描常见端口:");
		scanType2 = new JRadioButton("扫描一个连续段的端口:");
		startJLabel = new JLabel("起始端口:");
		endJLabel = new JLabel("结束端口:");
		threadNum = new JLabel("线程:");
		progressJLabel = new JLabel("扫描进度");
		resultJLabel = new JLabel("扫描结果");
		customPorts = new JTextField("21,22,23,25,26,69,80,110," +
				"143,443,465,1080,1158,1433,1521,2100,3306," +
				"3389,7001,8080,8081,8888,9080,9090,43958");
		startPort = new JTextField("20", 10);
		endPort = new JTextField("9000", 10);
		customDomain = new JTextField("www.zifangsky.cn", 25);
		customThreadNum = new JTextField("5", 5);
		beginJButton = new JButton("开始扫描");
		progressPane = new JScrollPane();
		resultPane = new JScrollPane();
		progressJtJTextArea = new JTextArea(18, 20);
		resultJTextArea = new JTextArea(18, 20);

		//布局
		buttonGroup.add(scanType1);
		buttonGroup.add(scanType2);
		scanType1.setSelected(true);

		gridbag = new GridBagLayout();
		constraints = new GridBagConstraints();
		constraints.fill = GridBagConstraints.BOTH;
		mainJPanel.setLayout(gridbag);

		constraints.gridwidth = 0; 
		constraints.gridheight = 1;
		constraints.weightx = 1;  
		constraints.weighty = 0;  
		gridbag.setConstraints(scanType1, constraints);
		scanType1.setFont(contentFont);
		mainJPanel.add(scanType1);

		gridbag.setConstraints(customPorts, constraints);
		customPorts.setFont(contentFont);
		mainJPanel.add(customPorts);

		gridbag.setConstraints(scanType2, constraints);
		scanType2.setFont(contentFont);
		mainJPanel.add(scanType2);

		gridbag.setConstraints(panel1, constraints);
		mainJPanel.add(panel1);

		gridbag.setConstraints(panel2, constraints);
		mainJPanel.add(panel2);

		constraints.weighty = 1;
		gridbag.setConstraints(panel3, constraints);
		mainJPanel.add(panel3);

		panel1.setLayout(new FlowLayout(FlowLayout.LEFT,30,5));
		panel1.add(panel1_1);
		panel1.add(panel1_2);
		panel1_1.setLayout(new FlowLayout(FlowLayout.CENTER,0,5));
		startJLabel.setFont(contentFont);
		panel1_1.add(startJLabel);
		startPort.setFont(contentFont);
		panel1_1.add(startPort);
		panel1_2.setLayout(new FlowLayout(FlowLayout.CENTER,0,5));
		endJLabel.setFont(contentFont);
		panel1_2.add(endJLabel);
		endPort.setFont(contentFont);
		panel1_2.add(endPort);

		panel2.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 5));
		customDomain.setFont(contentFont);
		panel2.add(customDomain);
		panel2.add(panel2_2);
		panel2_2.setLayout(new FlowLayout());
		threadNum.setFont(contentFont);
		panel2_2.add(threadNum);
		customThreadNum.setFont(contentFont);
		panel2_2.add(customThreadNum);
		beginJButton.setFont(contentFont);
		panel2.add(beginJButton);

		panel3.setLayout(new GridLayout(1, 2));
		panel3.add(panel4);
		panel3.add(panel5);
		panel4.setLayout(new BorderLayout());
		progressJLabel.setFont(contentFont);
		progressJLabel.setHorizontalAlignment(JLabel.CENTER);
		panel4.add(progressJLabel,BorderLayout.NORTH);
		panel4.add(progressPane,BorderLayout.CENTER);
		progressJtJTextArea.setFont(contentFont);
		progressPane.setViewportView(progressJtJTextArea);
		progressJtJTextArea.setEditable(false);
		progressJtJTextArea.setLineWrap(true);
		progressJtJTextArea.setWrapStyleWord(true);
		panel5.setLayout(new BorderLayout());
		resultJLabel.setFont(contentFont);
		resultJLabel.setHorizontalAlignment(JLabel.CENTER);
		panel5.add(resultJLabel,BorderLayout.NORTH);
		panel5.add(resultPane,BorderLayout.CENTER);
		resultJTextArea.setFont(contentFont);
		resultPane.setViewportView(resultJTextArea);
		resultJTextArea.setEditable(false);
		resultJTextArea.setLineWrap(true);
		resultJTextArea.setWrapStyleWord(true);

		//菜单
		jMenuBar = new JMenuBar();
		help = new JMenu("帮助");
		author = new JMenuItem("作者");
		contact = new JMenuItem("联系方式");
		version = new JMenuItem("版本号");
		readme = new JMenuItem("说明");
		help.setFont(menuFont);
		jMenuBar.add(help);
		author.setFont(menuFont);
		help.add(author);
		contact.setFont(menuFont);
		help.add(contact);
		version.setFont(menuFont);
		help.add(version);
		readme.setFont(menuFont);
		help.add(readme);

		add(mainJPanel);
		setJMenuBar(jMenuBar);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		beginJButton.addActionListener(this);
		author.addActionListener(this);
		contact.addActionListener(this);
		version.addActionListener(this);
		readme.addActionListener(this);
	}	

	/**
	 * 点击事件,根据选择的不同扫描方式,开启不同的线程开始扫描
	 * */
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == beginJButton){
			progressJtJTextArea.setText("");
			resultJTextArea.setText("");
			String domain = getDomainString(customDomain.getText().trim());
			int threadNumber = Integer.parseInt(customThreadNum.getText().trim());
			if(domain == null)
				return ;
			if(scanType1.isSelected()){
				String[] portsString = customPorts.getText().split(",");
				//端口转化为int型
				int[] ports = new int[portsString.length];
				for(int i=0;i<portsString.length;i++)
					ports[i] = Integer.parseInt(portsString[i].trim());
				//线程池
				ExecutorService threadPool = Executors.newCachedThreadPool();
				for (int i = 0; i < threadNumber; i++) {
					ScanThread1 scanThread1 = new ScanThread1(domain, ports,
							threadNumber, i, 800);
					threadPool.execute(scanThread1);
				}
				threadPool.shutdown();
			}
			else if(scanType2.isSelected()){
				int startPortInt = Integer.parseInt(startPort.getText().trim());
				int endPortInt = Integer.parseInt(endPort.getText().trim());

				ExecutorService threadPool = Executors.newCachedThreadPool();
				for (int i = 0; i < threadNumber; i++) {
					ScanThread2 scanThread2 = new ScanThread2(domain, startPortInt,endPortInt,
							threadNumber, i, 800);
					threadPool.execute(scanThread2);
				}
				threadPool.shutdown();
			}
		}
		else if(e.getSource() == author){
			JOptionPane.showMessageDialog(this, "zifangsky","作者:",JOptionPane.INFORMATION_MESSAGE);
		}
		else if(e.getSource() == contact){
			JOptionPane.showMessageDialog(this, "邮箱:[email protected]\n" +
					"博客:http://www.zifangsky.cn","联系方式:",JOptionPane.INFORMATION_MESSAGE);
		}
		else if(e.getSource() == version){
			JOptionPane.showMessageDialog(this, "v1.0.0","版本号:",JOptionPane.INFORMATION_MESSAGE);
		}
		else if(e.getSource() == readme){
			JOptionPane.showMessageDialog(this, "多线程端口扫描工具,两个扫描方式任你选择,你值得拥有!!!","说明:",JOptionPane.INFORMATION_MESSAGE);
		}

	}

	class ScanThread1 implements Runnable{
		private String domain;
		private int[] ports; // 待扫描的端口的Set集合
		private int threadNumber, serial, timeout; // 线程数,这是第几个线程,超时时间

		public ScanThread1(String domain,int[] ports, int threadNumber, int serial,
				int timeout) {
			this.domain = domain;
			this.ports = ports;
			this.threadNumber = threadNumber;
			this.serial = serial;
			this.timeout = timeout;
		}

		public void run() {
			int port = 0;
			try {
				InetAddress address = InetAddress.getByName(domain);
				Socket socket;
				SocketAddress socketAddress;
				if (ports.length < 1)
					return;
				for (port = 0 + serial; port <= ports.length - 1; port += threadNumber) {
					SwingUtilities.invokeLater(new ProgressRunnable( ports[port]));  //更新界面

					socket = new Socket();
					socketAddress = new InetSocketAddress(address, ports[port]);
					try {
						socket.connect(socketAddress, timeout);
						socket.close();
						SwingUtilities.invokeLater(new ResultRunnable( ports[port]));  //更新界面
					} catch (IOException e) {

					}
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			} catch (UnknownHostException e) {
				e.printStackTrace();
			}

		}

	}
	class ScanThread2 implements Runnable{
		private String domain;
		private int startPort = 20,endPort = 100; // 待扫描的端口的Set集合
		private int threadNumber, serial, timeout; // 线程数,这是第几个线程,超时时间

		public ScanThread2(String domain, int startPort, int endPort,
				int threadNumber, int serial, int timeout) {
			this.domain = domain;
			this.startPort = startPort;
			this.endPort = endPort;
			this.threadNumber = threadNumber;
			this.serial = serial;
			this.timeout = timeout;
		}

		public void run() {
			int port = 0;
			try {
				InetAddress address = InetAddress.getByName(domain);
				Socket socket;
				SocketAddress socketAddress;
				for (port = startPort + serial; port <= endPort; port += threadNumber) {
					SwingUtilities.invokeLater(new ProgressRunnable(port));  //更新界面

					socket = new Socket();
					socketAddress = new InetSocketAddress(address, port);
					try {
						socket.connect(socketAddress, timeout); // 超时时间
						socket.close();
						SwingUtilities.invokeLater(new ResultRunnable(port));  //更新界面
					} catch (IOException e) {

					}
				}
			} catch (UnknownHostException e) {
				e.printStackTrace();
			}

		}

	}

	/**
	 * 由EDT调用来更新界面的线程
	 * */
	class ProgressRunnable implements Runnable{
		private int currentPort = 0; 

		public ProgressRunnable(int currentPort) {
			this.currentPort = currentPort;
		}

		public void run() {
			progressJtJTextArea.setEditable(true);
			progressJtJTextArea.append("正在扫描端口:" + currentPort + "\n");
			progressJtJTextArea.setEditable(false);
			//设置显示最新内容
			progressJtJTextArea.selectAll();
			progressJtJTextArea.setCaretPosition(progressJtJTextArea.getSelectionEnd());
		}

	}
	/**
	 * 同上
	 * */
	class ResultRunnable implements Runnable{
		private int currentPort = 0; 

		public ResultRunnable(int currentPort) {
			this.currentPort = currentPort;
		}
		public void run() {
			resultJTextArea.setEditable(true);
			resultJTextArea.append("端口:" + currentPort + "    开放\n");
			resultJTextArea.setEditable(false);
			resultJTextArea.selectAll();
			resultJTextArea.setCaretPosition(resultJTextArea.getSelectionEnd());
		}
	}

	/**
	 * 根据输入的字符串提取出其中的域名字符串或者IP字符串,如:www.zifangsky.cn
	 * 
	 * @param str 输入的包含域名的字符串
	 * @return 域名或IP字符串
	 * */
	public static String getDomainString(String str){
		String reg = "[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+";
		Pattern pattern = Pattern.compile(reg);
		Matcher matcher = pattern.matcher(str);
		if(matcher.find()){
			return matcher.group();
		}
		return "";
	}

	public static void main(String[] args){
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				new PortScan();
			}
		});
	}
}

三 测试效果

随便找了一个网站进行测试,效果如下:

附:打包好的可执行jar包:链接:http://down.51cto.com/data/2147925

特别申明:给出测试软件以及源代码仅仅只是为了技术交流,请勿用作非法用途,否则后果自负!

(PS:如果没有下载豆的话,可以看我个人博客上的这篇文章,文末有百度云的下载链接,传送门:http://www.zifangsky.cn/2016/01/使用java开发多线程端口扫描工具(二)/

时间: 2024-10-06 15:13:02

使用Java开发多线程端口扫描工具(二)的相关文章

使用Java开发多线程端口扫描工具

前言:这里只给出命令行版的扫描工具,后续可能是写一个独立的界面,或者是集成到其他工具上去. 一 扫描原理 其实原理非常简单,就是使用Socket去连接目标IP或者域名的指定端口,如果能够连上则说明该端口是打开的.反之,要是在连接超时之前都没有连上,则将该端口判断为关闭状态.下面我将分别说明两种基本的扫描方式:(1)扫描一个连续的端口段:(2)仅扫描一个指定的端口集合 二 使用多线程扫描目标主机一个段的端口开放情况 /**  * 多线程扫描目标主机一个段的端口开放情况  *   * @param 

端口扫描工具

简单的多线程端口扫描工具 可以接收IP地址作为参数,如果不接参数,则默认扫描本机的端口 1 #!/usr/bin/python 2 3 import socket 4 import time 5 import argparse 6 import threading 7 8 def arg_process(): 9 argparser=argparse.ArgumentParser(description="Port Scaner") 10 argparser.add_argument(

告别脚本小子【编写端口扫描工具】

前言Windows系统默认开放了很多端口,通常这些端口意味着该主机运行着大家都知道的服务,比如TCP端口21-FTP服务,TCP端口80-HTTP服务,有些服务就有可能存在公开的漏洞,因此可以说主机上每一个开放的端口都可能成为一条入侵的捷径.当然,网上存在很多端口扫描工具,但是我们总不能只知道使用别人的工具,一是这些工具别人编写的时候有没有加入后门,二是如果只会用别人的工具,最终也只能是一个脚本小子,所以我们自己来编写一款实用的端口扫描工具. 一.基础知识 1.1.线程 线程,有时被称为轻量级进

五款优秀的端口扫描工具

在使用阿里云服务器,搭建阿里云VPC专有网络之后,关闭不必要的端口,并进行验证. 端口摘要: 端口扫描器是一种检测服务器或主机虚拟端口是开启或关闭的工具.端口允许同一台计算机上的不同应用程序同时共享网络资源.连接本地局域网或互联网的计算机运行着许多不同服务,它们监听着常用或不常用的端口.端口数的范围从0到65535,0到1023的端口数最常用,它们中有许多是为FTP.SSH.HTTP.telnet.DNS和NNTP等服务保留的,1024到49151端口是注册端口,49152到65535则分配给动

纯 Java 开发 WebService 调用测试工具(wsCaller.jar)

注:本文来自hacpai.com:Tanken的<纯 Java 开发 WebService 调用测试工具(wsCaller.jar)>的文章 基于 Java 开发的 WebService 测试工具,不像上文的 iWallpaper.jar 只能实现在 Windows 系统下的功能,此工具发挥了 Java 跨平台的优势,亲测可在 Windows.Mac OS 及 Linux 下运行及使用.简单易用的专门用于测试 WebService 的小工具,在 2003 版 wsCaller.jar 的基础上

『安全工具』Nmap 强悍的端口扫描工具

作为时下流行的端口扫描工具,Nmap有因其扫描的隐密性有“端口扫描之王”之称 上图是黑客帝国(The Matrix)中崔妮蒂用Nmap等工具入侵发电站的能源管理系统 0x 01 Nmap介绍 Nmap是一款用于网络发现和安全审计的安全工具,常用于端口扫描. 用法: nmap [扫描类型] [参数] 目标IP 1. 扫描类型 -sT TCP 连接扫描,会在目标主机中记录大量的链接请求和错误信息 -sS SYN扫描,只完成三次握手前两次,很少有系统记入日志,默认使用,需要root(admin)权限

&#8203;【安全牛学习笔记】端口扫描(二)

端口扫描(二) ╋━━━━━━━━━━━━━━━━━╋ ┃端口扫描                          ┃ ┃隐蔽扫描-----syn                  ┃ ┃  不建立完整链接                  ┃ ┃  应用日志不记录扫描行为-----隐蔽 ┃ ┃僵尸扫描                          ┃ ┃  极度隐蔽                        ┃ ┃  实施条件苛刻                    ┃ ┃  可伪

Windows多线程端口扫描

还不是很了解多线程,先简单运用下. 1 /* 2 2015.5 HT 3 多线程端口扫描 4 5 netstat -an 6 7 */ 8 9 #include <iostream> 10 #include <process.h> 11 #include <winsock2.h> 12 #pragma comment(lib,"ws2_32.lib") 13 using namespace std; 14 15 // 线程传递的端口参数 16 typ

端口扫描工具nmap

nmap 使用介绍 nmap是目前为止最广为使用的国外端口扫描工具之一.我们可以从[url]http://www.insecure.org/[/url]进行下载,可以很容易的安装到Windows和unix操作系统中,包括mac os x(通过configure.make .make install等命令)也可以直接从http://www.insecure.org/下载windows二进制(包括所需要的winpcap)也可以从http://www.nmapwin.org/获得nmap的图形wind