-
2021-11-09 08:52:48
通过Java实现一个端口扫描器
一、原理介绍
端口扫描顾名思义,就是扫描目的资源的端口,来发现目的资源是否对外开放某个端口,提供了某种网络服务。 在安全攻防领域经常通过端口扫描技术来发现关键资产对外提供服务的情况。红军为发现暴露的风险点,进行安全加固;蓝军为识别目标服务,以便识别资产的脆弱点,实施针对性网络攻击。
二、实现
功能介绍
- 对指定ip进行指定端口进行扫描,获取目的ip的端口开放情况
- 扫描模式:TCP全连接扫描、TCP半连接扫描(待实现)
- 通过发送空信息,获取开放端口对应服务的应答,获取指纹信息,从而判断服务类别
- 端口开放情况会通过日志打印出来
输入
- ip地址或ip地址组,用逗号隔开
- 待扫描的端口组:0-65535,左开右闭
输出
- 通过日志打印端口开放情况
类说明
- ScanApp 扫描器启动类
/** * 扫描器启动类 */ public class ScanApp { public static void main(String[] args) { // 待扫描的ip地址或ip地址组 String ips = null; ips = "14.29.192.196,14.116.188.121"; // 待扫描的port范围 String ports = "20-25"; Scanner.start(ips,ports); } }
- Scanner 扫描管理类
import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; /** * 端口、指纹扫描器 * 职责: * 1、解析输入的ip地址、端口 * 2、新键扫描任务ScanJob扫描引擎进行端口扫描 * 3、两种扫描方式:TCP全连接扫描、TCP半连接扫描 * */ public class Scanner { // 日志 private static Logger logger = Logger.getLogger("Scanner"); // 使用多线程扫描 private static ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10,20,1000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(5), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()); /** * 开始方法 * @param ips 输入的待扫描ip列表 * @param ports 输入的待扫描端口 */ public static void start(String ips, String ports) { // 解析端口 String[] portArray = ports.split("-"); int portStart = Integer.parseInt(portArray[0]); int portEnd = Integer.parseInt(portArray[1]); logger.info("[-] Ports: " + ports); // 解析ip地址,并扫描 if (ips.indexOf(',') != -1) { String[] ipList = ips.split(","); logger.info("[-] IP list: " + ipList.toString()); for (String ip : ipList) { scanAllPort(ip,portStart,portEnd); } }else if (ips.indexOf('/') != -1){ // TODO 支持ip地址网段的解析 String[] ipArray = ips.split("/"); String ipAddress = ipArray[0]; int mask = Integer.parseInt(ipArray[1]); String[] ipSplit = ipAddress.split("."); }else { scanAllPort(ips,portStart,portEnd); } // 扫描任务都完成后,程序停止 try{ while(true){ if(poolExecutor.getActiveCount() == 0){ logger.info("[-] Scan job all finish"); System.exit(-1); break; } Thread.sleep(1000); } }catch (Exception ex){ logger.warning("End with exeception, ex: " + ex.getMessage()); } System.exit(-1); } /** * 扫描某ip的对应端口 * @param ip ip地址 * @param portStart 开始扫描的的端口 * @param portEnd 停止扫描的端口 */ public static void scanAllPort(String ip, int portStart, int portEnd){ for (int port = portStart; port <= portEnd; port++){ scan(ip,port); } } /** * 对ip:port进行扫描 * @param ip ip地址 * @param port 端口 */ public static void scan(String ip, int port){ // 执行扫描任务 poolExecutor.execute(new ScanJob(new ScanObject(ip,port),ScanEngine.TCP_FULL_CONNECT_SCAN)); } }
- ScanEngine 扫描器引擎
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ConnectException; import java.net.Socket; import java.util.logging.Logger; /** * 扫描器引擎 * 实现具体的扫描逻辑,提供扫描能力(TCP全连接和半连接扫描) */ public class ScanEngine { private static Logger logger = Logger.getLogger("TCPFullConnectScan"); public static final String TCP_FULL_CONNECT_SCAN = "TCP_FULL_CONNECT_SCAN"; public static final String TCP_HALF_CONNECT_SCAN = "TCP_HALF_CONNECT_SCAN"; public static ScanObject scan(ScanObject object, String scanEngine){ switch (scanEngine){ case TCP_FULL_CONNECT_SCAN: return tcpFullConnectScan(object); case TCP_HALF_CONNECT_SCAN: return tcpHalfConnectScan(object); } return tcpFullConnectScan(object); } /** * tcp全连接扫描 * @param object * @return */ private static ScanObject tcpFullConnectScan(ScanObject object){ try{ // 全连接扫描,发现可用服务 Socket socket = new Socket(object.getIp(),object.getPort()); object.setOpen(true); object.setService(); // 发送招手信息 OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream()); out.write("hello"); out.flush(); // 获取服务指纹 BufferedReader re = new BufferedReader(new InputStreamReader(socket.getInputStream())); String serviceBanner = re.readLine(); object.setBanner(serviceBanner); object.setService(); logger.info("[-] Find service :"+ object); socket.close(); } catch (ConnectException e) { // 打印连接失败的端口 // logger.info("[-] Close: " + object.getIp() + ":" + object.getPort()); } catch (Exception e){ // 出现其他异常 logger.info("[-] " + object.toString() + "end with unexecepted exeception:" + e.getMessage()); } return object; } /** * TPC 半连接扫描 * @param object * @return */ private static ScanObject tcpHalfConnectScan(ScanObject object){ // TODO 待实现tcp半连接扫描 return object; } }
- ScanJob 扫描任务类
/** * 扫描任务类,执行具体的扫描任务 */ public class ScanJob implements Runnable{ // 扫描信息 private ScanObject object; // 扫描类型 private String scanType; public ScanJob(ScanObject object,String scanType) { this.object = object; this.scanType = scanType; } @Override public void run() { ScanEngine.scan(object, scanType); } }
- ScanObject 扫描结果实体类
import java.util.HashMap; import java.util.Map; /** * 扫描信息实体 */ public class ScanObject { private String ip; private int port; private String service; private Boolean isOpen; private String banner; // 存放服务指纹和服务的对应关系 banner -> service private static Map<String,String> bannerMaps = new HashMap<>(); // 存放常见端口与服务的对应关系 port -> service private static Map<Integer,String> portMaps = new HashMap<>(); static { bannerMaps.put("ssh","SSH"); portMaps.put(22,"SSH"); bannerMaps.put("ftp","FTP"); portMaps.put(21,"FTP"); portMaps.put(20,"FTP"); bannerMaps.put("smtp","SMTP"); portMaps.put(25,"SMTP"); bannerMaps.put("mysql","MySQL"); portMaps.put(3389,"MySQL"); } public ScanObject(String ip, int port) { this.ip = ip; this.port = port; } public Boolean getOpen() { return isOpen; } public void setOpen(Boolean open) { isOpen = open; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public String getService() { return service; } public void setService() { // 先根据port判断服务类型 if (portMaps.containsKey(this.port)){ this.service = portMaps.get(this.port); } if (banner != null && !banner.equals("")){ for (String key : bannerMaps.keySet()) { if (banner.toLowerCase().contains(key)) { this.service = bannerMaps.get(key); break; } } } } public String getBanner() { return banner; } public void setBanner(String banner) { this.banner = banner; } @Override public String toString() { return "ScanObject{" + "ip='" + ip + '\'' + ", port=" + port + ", service='" + service + '\'' + ", isOpen=" + isOpen + ", banner='" + banner + '\'' + '}'; } }
使用方式
- 在ScanApp中的ips字符串中加入待扫描的ip地址(逗号隔开),在ports中输入扫描的端口范围(减号隔开)
- 使用jdk8运行ScanApp
项目源码链接:
https://github.com/aa792978017/Scanner
如果这篇文章对你有帮助,欢迎点赞收藏;如果对文章有任何疑问,也欢迎留言提出,笔者会尽快回复。
更多相关内容 -
计算机网络课程设计 多线程端口扫描器(TCP/UDP端口扫描)(java实现)带GUI界面
2020-07-10 21:04:011.利用Socket通信机制实现一个多线程的端口扫描器。 2.设计要求: 2.1用户界面:用户可以输入IP地址或IP地址段;输入端口号或端口号范围;列表显示主机名、开放的端口及开放端口上相应的服务名称。 2.2端口的有效... -
专题讲座资料(2021-2022年)多线程端口扫描器Java课程设计报告源代码.doc
2021-10-13 01:35:47教育资料 -
JAVA多线程端口扫描器
2020-11-15 14:05:35本软件是用java开发的多线程端口扫描器。可以实现本地扫描和指定IP扫描。本文包含文档说明和代码,很详细。 -
多线程端口扫描器 Java课程设计报告 源代码
2009-12-31 12:16:44多线程端口扫描器是实现计算机的端口的扫描,只要在在前台设置好所要扫描的IP、起始端口、结束端口以及所要用到的线程数,点击扫描,就可以扫描到所输入IP地址主机的开放端口,并显示在主窗体中;点击退出,则可以... -
Java多线程端口扫描课设报告
2018-07-04 19:54:23Java多线程端口扫描课设任务简单报告,多线程端口扫描器是实现计算机的端口扫描,只要前台设计好了要扫描的IP或主机、起始端口、结束端口及所要用到的线程数,点击扫描,就可以扫描到相应IP或主机的端口,并显示在... -
基于多线程端口扫描器 java
2016-10-07 07:40:34点击运行可以出现扫描窗口,并且不报错,点击扫描按钮以后,窗口消失,仍然不报错,求大神指点![图片说明]... -
端口扫描器的设计与实现(Java).zip
2019-12-15 00:10:451.利用Socket通信机制实现一个多线程的端口扫描器。 2.设计要求: 2.1用户界面:用户可以输入IP地址或IP地址段;输入端口号或端口号范围;列表显示主机名、开放的端口及开放端口上相应的服务名称。 2.2端口的... -
基于java的多线程端口扫描器
2010-12-08 19:45:15基于java的多线程端口扫描器,该扫描器实现了按不同的方式进行端口扫描,同时支持端口范围和线程数的手动设定,并实现了扫描结构的保存功能 -
Java多线程编写高效端口扫描器
2017-10-12 23:22:48大二下学期学的Java,很是感兴趣,期末课程设计时想了很久也没有想到要编写个什么,刚好那段时间比特币病毒爆发,很多高校的毕业生的毕业设计,毕业论文等不幸丢失,这时很多人认识到了电脑端口的重要性,于是我也有...引言:大二下学期学的Java,很是感兴趣,期末课程设计时想了很久也没有想到要编写个什么,刚好那段时间比特币病毒爆发,很多高校的毕业生的毕业设计,毕业论文等不幸丢失,这时很多人认识到了电脑端口的重要性,于是我也有了想法,想要编写一个端口扫描器。但由于学校课程时间有限,学的内容很少,今天整理了一下才想写博客记录下第一次用Java编写的小程序。发出来希望能和诸君探讨,欢迎提出异议和意见,优化程序,提高性能;同时也希望能给以后学Java的同学一些思路,在学习的过程中多些乐趣。
这个程序的主要功能有查看本机ip地址,主机名;本机开放端口;查网站IP地址;查网站开放端口;换肤;
主界面如下图:
由于功能较少,用到的技术不多,不难,主要用到GUI组件,io流,多线程,网络编程之Socket套接字,简单的命令提示符。
分功能来讲的话,查本机ip、本机扫描、查网址ip简要思路:应用多线程,ipconfig、netstat、ping等命令获得相应信息,通过IO流获取得到的信息,输出到文本域,
扫描端口通过用Socket套接字用多线程与目标网址或ip地址的指定端口循环连接,若连接成功则说明对方机器开启了这个端口,失败则未开启。
由于为了更好的查看功能,未用背景图,功能实现如下图:
本机ip和查网址ip
本机端口扫描
目标ip端口扫描
源码如下:
import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; public class SearchPort extends JFrame implements ActionListener { private static JTextArea jta; private JScrollPane js; private JTextField jt1,jt2,jt3,jt4; private JButton jb1,jb2,jb3,jb4,jb5,jb6,jb7,jb8,jb10; String path; ImageIcon background; static double b,a;; private static InetAddress bjip, wip; private static InetAddress ip; private static String bjname; private String name; private String commandstr; private static int qishi; private int zhongzhi; Socket socket; public SearchPort() { super("端口扫描器");//名字 //设置大小 setSize(800,600); //设置位置 setLocation(0, 0); path = "background10.jpg"; //背景图片 background = new ImageIcon(path); // 把背景图片显示在一个标签里面 JLabel label = new JLabel(background); // 把标签的大小位置设置为图片刚好填充整个面板 label.setBounds(0, 0, this.getWidth(), this.getHeight()); // 把内容窗格转化为JPanel,否则不能用方法setOpaque()来使内容窗格透明 JPanel imagePanel = (JPanel) this.getContentPane(); imagePanel.setOpaque(false); // 把背景图片添加到分层窗格的最底层作为背景 this.getLayeredPane().add(label, new Integer(Integer.MIN_VALUE)); //设置为显示 setVisible(true); //创建jpanel JPanel jp=new JPanel(); JPanel jp1=new JPanel(); JPanel jp2=new JPanel(); JPanel jp3=new JPanel(); JPanel jp4=new JPanel(); JPanel jp5=new JPanel(); JPanel jp6=new JPanel(); JPanel jp7=new JPanel(); JPanel jp8=new JPanel(); JPanel jp9=new JPanel(); JPanel jp10=new JPanel(); JPanel jp11=new JPanel(); JPanel jp12=new JPanel(); JPanel jp13=new JPanel(); JPanel jp14=new JPanel(); JPanel jp15=new JPanel(); JPanel jp16=new JPanel(); JPanel jp17=new JPanel(); JPanel jp18=new JPanel(); //需要透明的组件全设置为透明 jp.setOpaque(false); jp1.setOpaque(false); jp2.setOpaque(false); jp3.setOpaque(false); jp4.setOpaque(false); jp5.setOpaque(false); jp6.setOpaque(false); jp7.setOpaque(false); jp8.setOpaque(false); jp9.setOpaque(false); jp10.setOpaque(false); jp11.setOpaque(false); jp12.setOpaque(false); jp13.setOpaque(false); jp14.setOpaque(false); jp15.setOpaque(false); jp16.setOpaque(false); jp17.setOpaque(false); jp18.setOpaque(false); //按钮的设置 jb1=new JButton("复制"); jb2=new JButton("剪切"); jb3=new JButton("清空"); jb4=new JButton("本机IP"); jb5=new JButton("查网址IP"); jb6=new JButton("扫描"); jb8=new JButton("换肤"); jb10=new JButton("本机扫描"); //按钮添加监听事件 jb1.setOpaque(false); jb1.addActionListener(this); jb2.addActionListener(this); jb3.addActionListener(this); jb4.addActionListener(this); jb5.addActionListener(this); jb6.addActionListener(this); jb8.addActionListener(this); jb10.addActionListener(this); //建立滚动窗格,把文本域添加进去 jta=new JTextArea(" 结果 ",27,36); js=new JScrollPane(jta); //滚动窗格及文本域设置透明 jta.setOpaque(false); js.setOpaque(false); //文本行的设置 jt1=new JTextField("192.168.38.12",12); jt2=new JTextField("www.baidu.com",12); jt3=new JTextField("起始端口",12); jt4=new JTextField("终止端口",12); //文本行设置透明 jt1.setOpaque(false); jt2.setOpaque(false); jt3.setOpaque(false); jt4.setOpaque(false); //添加JPanel this.add(jp); //jp设置一行两列 jp.setLayout(new GridLayout(1,2)); //jp添加jp1,jp2 jp.add(jp1); jp.add(jp2); //jp1设置边界 jp1.setBorder(BorderFactory.createTitledBorder("扫描结果")); //jp1设置边布局 jp1.setLayout(new BorderLayout()); //jp1添加Jp3到上方 jp1.add(jp3,"North"); //滚动窗格设置透明 js.setOpaque(false); js.getViewport().setOpaque(false); //把js添加到jp3 jp3.add(js); //jp4添加到jp1下方 jp1.add(jp4,"South"); // jp4添加四个按钮 jp4.add(jb1); jp4.add(jb2); jp4.add(jb3); jp4.add(jb8); //jp3设置大小 jp3.setPreferredSize(new Dimension(400,600)); //jp2设置边布局 jp2.setLayout(new BorderLayout()); //jp5添加到jp2 上方 jp2.add(jp5,"North"); //JP5设置大小 jp5.setPreferredSize(new Dimension(400,500)); //jp5设置边界 jp5.setBorder(BorderFactory.createTitledBorder("设扫描地址")); //把jp6添加到jp2的中间 jp2.add(jp6,"Center"); //jp6设置边界 jp6.setBorder(BorderFactory.createTitledBorder("扫描")); //jp6设置网格布局4行1列 jp5.setLayout(new GridLayout(4,1)); //把Jp7 jp8 jp9 jp10插入到jp5 jp5.add(jp7); jp5.add(jp8); jp5.add(jp9); jp5.add(jp10); //jp7设置1行2列 jp7.setLayout(new GridLayout(1,2)); //jp8设置1行2列 jp8.setLayout(new GridLayout(1,2)); //jp9设置1行2列 jp9.setLayout(new GridLayout(1,2)); //jp10设置1行2列 jp10.setLayout(new GridLayout(1,2)); //把jp11jp15添加到Jp7 jp7.add(jp11); jp7.add(jp15); //jp15设置边界 jp15.setBorder(BorderFactory.createTitledBorder("IP地址")); //把文本行添加到Jp15 jp15.add(jt1); //把jp12jp16添加到Jp8 jp8.add(jp12); jp8.add(jp16); //jp16设置边界 jp16.setBorder(BorderFactory.createTitledBorder("网址")); //把文本行添加到Jp15 jp16.add(jt2); //把jp13jp17添加到Jp9 jp9.add(jp13); jp9.add(jp17); //jp17设置边界 jp17.setBorder(BorderFactory.createTitledBorder("起始端口")); //把文本行添加到Jp17 jp17.add(jt3); //把jp14jp18添加到Jp10 jp10.add(jp14); jp10.add(jp18); //jp18设置边界 jp18.setBorder(BorderFactory.createTitledBorder("终止端口")); //把文本行添加到Jp18 jp18.add(jt4); //把按钮添加到jp6 jp6.add(jb4); jp6.add(jb10); jp6.add(jb5); jp6.add(jb6); } //动作响应事件 public void actionPerformed(ActionEvent e) { if(e.getSource()==jb1)//如果jb1被按下 { jta.copy();//复制 } if(e.getSource()==jb2) { jta.cut();//剪切 } if(e.getSource()==jb3) { jta.setText(" 结果 ");//清空 } if(e.getSource()==jb4)//获取本机ip { try { bjip=InetAddress.getLocalHost(); //获得本机ip bjname=InetAddress.getLocalHost().getHostName();//获得本机名 } catch (UnknownHostException e1) { e1.printStackTrace(); } jta.setText(jta.getText()+"\n"+" 本机IP:"+bjip+"\n"+" 本机名字"+bjname); //输出 } if(e.getSource()==jb5) //查本机端口 { search s=new search(); Thread t1=new Thread(s); Thread t2=new Thread(s); t1.start(); t2.start(); } if(e.getSource()==jb6)//扫描端口 { qishi=Integer.parseInt(jt3.getText());//jt3的输入转数字 zhongzhi =Integer.parseInt(jt4.getText()); InetAddress ip = null; if (qishi!=0&&zhongzhi!=0) //判断起始终止端口是否为空 { if(qishi>0&&zhongzhi<65535)//判断端口是否正确 { if(qishi<zhongzhi) //判断是否起始端口小于终止端口 { if ((zhongzhi-qishi)<1000) //判断要扫描的端口数是否小于1000 { try { wip = InetAddress.getByName(jt1.getText()); //获取ip } catch (UnknownHostException e1) { JOptionPane.showMessageDialog(rootPane, "请输入正确的ip地址!"); } for (int port = qishi; port <=zhongzhi; port++) //端口循环 { searchport s = new searchport(wip,port); Thread t = new Thread(s); t.start(); if (port==zhongzhi) { jta.setText(jta.getText()+"\n"+" 扫描完毕"); //判断是否扫锚完毕 } } } else { JOptionPane.showMessageDialog(rootPane, "扫描端口数过多!");//扫描太多 } } else { JOptionPane.showMessageDialog(rootPane, "起始端口必须小于终止端口"); } } else { JOptionPane.showMessageDialog(rootPane, "请输入正确的端口!"); } } else { JOptionPane.showMessageDialog(rootPane, "请输入端口!"); } } if(e.getSource()==jb10) //获取本机开放端口 { new Thread(new Runnable(){ public void run() { BufferedReader br = null; try { String commands="nslookup"; String www=commands+" "+jt2.getText(); commandstr=www; //命令 Process p = Runtime.getRuntime().exec("Netstat -an"); //调用系统控制命令符 br = new BufferedReader(new InputStreamReader(p.getInputStream())); //截取命令符的返回代码 String line = null; StringBuilder sb = new StringBuilder(); //字符串变量非线程 while ((line = br.readLine()) != null) { sb.append(line + "\n"); // 如果返回值为空,连接一个字符串到末尾 } jta.setText(jta.getText()+"\n"+sb.toString()); 把截取的字符串输出到文本域 } catch (Exception ev) { ev.printStackTrace(); } finally { if (br != null) //如果返回值不为空则关闭br { try { br.close(); } catch (Exception ev) { ev.printStackTrace(); } } } } }).start(); } } public static void main(String[] args) { new SearchPort(); } class search implements Runnable { public void run() { BufferedReader br = null; try { String commands="nslookup -an"; String www=commands+" "+jt2.getText(); commandstr=www; //需要调用系统命令符的命令 Process p = Runtime.getRuntime().exec(commandstr); //调用系统命令符 br = new BufferedReader(new InputStreamReader(p.getInputStream())); //截取命令符返回的信息 String line = null; StringBuilder sb = new StringBuilder(); //字符串变量非线程 while ((line = br.readLine()) != null) { sb.append(line + "\n"); //如果返回值为空,连接一个字符串到末尾 } jta.setText(jta.getText()+"\n"+" "+sb.toString()); //把截取的返回值输出到文本域 } catch (Exception ev) { ev.printStackTrace(); } finally { if (br != null) //如果返回值不为空则关闭br { try { br.close(); } catch (Exception ev) { ev.printStackTrace(); } } } } } class searchport implements Runnable { private InetAddress wip; private int port; searchport(InetAddress wip,int port) { this.wip=wip; this.port=port; } @Override public void run() { try { Socket socket=new Socket(wip,port); //与目标ip的端口建立连接 jta.setText(jta.getText()+"\n"+" "+port +"开启"); //成功则输出到文本域 socket.close(); //连接关闭 } catch (Exception ev) { jta.setText(jta.getText()+"\n"+" "+port +"关闭");//连接失败则输出到文本域 } } }
-
Java网络编程实现的简单端口扫描器示例
2020-08-27 16:08:46主要介绍了Java网络编程实现的简单端口扫描器,涉及Java网络编程Socket组建、swing组建及多线程相关操作技巧,需要的朋友可以参考下 -
使用Java开发多线程端口扫描工具
2017-11-27 14:59:00一 扫描原理 其实原理非常简单,就是使用Socket去连接目标IP或者域名的指定端口,如果能够连上则说明该端口是打开的。反之,要是在连接超时之前都...二 使用多线程扫描目标主机一个段的端口开放情况 1 2 3 4 5 6...一 扫描原理
其实原理非常简单,就是使用Socket去连接目标IP或者域名的指定端口,如果能够连上则说明该端口是打开的。反之,要是在连接超时之前都没有连上,则将该端口判断为关闭状态。下面我将分别说明两种基本的扫描方式:(1)扫描一个连续的端口段;(2)仅扫描一个指定的端口集合
二 使用多线程扫描目标主机一个段的端口开放情况
123456789101112131415161718192021222324252627282930313233343536/**
* 多线程扫描目标主机一个段的端口开放情况
*
* @param ip
* 待扫描IP或域名,eg:180.97.161.184 www.zifangsky.cn
* @param startPort
* 起始端口
* @param endPort
* 结束端口
* @param threadNumber
* 线程数
* @param timeout
* 连接超时时间
* */
public
void
scanLargePorts(String ip,
int
startPort,
int
endPort,
int
threadNumber,
int
timeout) {
ExecutorService threadPool = Executors.newCachedThreadPool();
for
(
int
i =
0
; i < threadNumber; i++) {
ScanMethod1 scanMethod1 =
new
ScanMethod1(ip, startPort, endPort,
threadNumber, i, timeout);
threadPool.execute(scanMethod1);
}
threadPool.shutdown();
// 每秒中查看一次是否已经扫描结束
while
(
true
) {
if
(threadPool.isTerminated()) {
System.out.println(
"扫描结束"
);
break
;
}
try
{
Thread.sleep(
1000
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
然后是一个内部类ScanMethod1实现了Runnable接口:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657/**
* 扫描方式一:针对起始结束端口,进行逐个扫描
*
* */
class
ScanMethod1
implements
Runnable {
private
String ip;
// 目标IP
private
int
startPort, endPort, threadNumber, serial, timeout;
// 起始和结束端口,线程数,这是第几个线程,超时时间
/**
* 初始化
*
* @param ip
* 待扫描IP或域名
* @param startPort
* 起始端口
* @param endPort
* 结束端口
* @param threadNumber
* 线程数
* @param serial
* 标记是第几个线程
* @param timeout
* 连接超时时间
* */
public
ScanMethod1(String ip,
int
startPort,
int
endPort,
int
threadNumber,
int
serial,
int
timeout) {
this
.ip = ip;
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(ip);
Socket socket;
SocketAddress socketAddress;
for
(port = startPort + serial; port <= endPort; port += threadNumber) {
socket =
new
Socket();
socketAddress =
new
InetSocketAddress(address, port);
try
{
socket.connect(socketAddress, timeout);
// 超时时间
socket.close();
System.out.println(
"端口 "
+ port +
" :开放"
);
}
catch
(IOException e) {
// System.out.println("端口 " + port + " :关闭");
}
}
}
catch
(UnknownHostException e) {
e.printStackTrace();
}
}
}
三 使用多线程扫描目标主机指定Set端口集合的开放情况
123456789101112131415161718192021222324252627282930313233/**
* 多线程扫描目标主机指定Set端口集合的开放情况
*
* @param ip
* 待扫描IP或域名,eg:180.97.161.184 www.zifangsky.cn
* @param portSet
* 待扫描的端口的Set集合
* @param threadNumber
* 线程数
* @param timeout
* 连接超时时间
* */
public
void
scanLargePorts(String ip, Set<Integer> portSet,
int
threadNumber,
int
timeout) {
ExecutorService threadPool = Executors.newCachedThreadPool();
for
(
int
i =
0
; i < threadNumber; i++) {
ScanMethod2 scanMethod2 =
new
ScanMethod2(ip, portSet,
threadNumber, i, timeout);
threadPool.execute(scanMethod2);
}
threadPool.shutdown();
while
(
true
) {
if
(threadPool.isTerminated()) {
System.out.println(
"扫描结束"
);
break
;
}
try
{
Thread.sleep(
1000
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
具体的线程内部类跟上面类似,代码如下:
123456789101112131415161718192021222324252627282930313233343536373839404142434445/**
* 扫描方式二:针对一个待扫描的端口的Set集合进行扫描
*
* */
private
class
ScanMethod2
implements
Runnable {
private
String ip;
// 目标IP
private
Set<Integer> portSet;
// 待扫描的端口的Set集合
private
int
threadNumber, serial, timeout;
// 线程数,这是第几个线程,超时时间
public
ScanMethod2(String ip, Set<Integer> portSet,
int
threadNumber,
int
serial,
int
timeout) {
this
.ip = ip;
this
.portSet = portSet;
this
.threadNumber = threadNumber;
this
.serial = serial;
this
.timeout = timeout;
}
public
void
run() {
int
port =
0
;
Integer[] ports = portSet.toArray(
new
Integer[portSet.size()]);
// Set转数组
try
{
InetAddress address = InetAddress.getByName(ip);
Socket socket;
SocketAddress socketAddress;
if
(ports.length <
1
)
return
;
for
(port =
0
+ serial; port <= ports.length -
1
; port += threadNumber) {
socket =
new
Socket();
socketAddress =
new
InetSocketAddress(address, ports[port]);
try
{
socket.connect(socketAddress, timeout);
socket.close();
System.out.println(
"端口 "
+ ports[port] +
" :开放"
);
}
catch
(IOException e) {
// System.out.println("端口 " + ports[port] + " :关闭");
}
}
}
catch
(UnknownHostException e) {
e.printStackTrace();
}
}
}
四 两种扫描方式的测试用例
123456789101112131415public
static
void
main(String[] args) {
PortScanDemo portScanDemo =
new
PortScanDemo();
//方式1
// portScanDemo.scanLargePorts("ultra-book.co", 20, 10000, 5,800);
// portScanDemo.scanLargePorts("180.97.161.184", 1, 100, 5);
//方式2
Set<Integer> portSet =
new
LinkedHashSet<Integer>();
Integer[] ports =
new
Integer[] {
21
,
22
,
23
,
25
,
26
,
69
,
80
,
110
,
143
,
443
,
465
,
995
,
1080
,
1158
,
1433
,
1521
,
2100
,
3128
,
3306
,
3389
,
7001
,
8080
,
8081
,
9080
,
9090
,
43958
};
portSet.addAll(Arrays.asList(ports));
portScanDemo.scanLargePorts(
"ultra-book.co"
, portSet,
5
,
800
);
}
五 测试结果
注:1 超时时间是以毫秒为单位,其中要是扫描国内的IP可以把这个时间适当设置低一点,200~500左右。相反,要是扫描国外IP就需要把这个时间适当设置大一点,不然有可能把本来打开的端口也漏掉了
本文转自 pangfc 51CTO博客,原文链接:http://blog.51cto.com/983836259/1727023,如需转载请自行联系原作者
-
多线程端口扫描器的实现(java)
2016-07-28 09:08:581.利用Socket通信机制实现一个多线程的端口扫描器。 2.设计要求: 2.1用户界面:用户可以输入IP地址或IP地址段;输入端口号或端口号范围;列表显示主机名、开放的端口及开放端口上相应的服务或恶意程序的名称...这是我大三下学期课程设计的题目,没有想象中的那么难。
一、要求:
1.利用Socket通信机制实现一个多线程的端口扫描器。
2.设计要求:
2.1用户界面:用户可以输入IP地址或IP地址段;输入端口号或端口号范围;列表显示主机名、开放的端口及开放端口上相应的服务或恶意程序的名称;功能按钮。
2.2使用多线程机制对某一地址(段)的主机端口进行扫描;说明开放端口的类型(如UDP端口还是TCP端口);查询数据库,对开放的端口进行说明(如提供的服务或存在的风险)。
2.3有关端口与服务或恶意程序的映射关系保存为数据库表,以扫描出的开放端口号为关键字查询表,将端口的说明显示在界面的列表框中。
二、代码
功能实现类:
数据库工具类public class PortScanner{ public static void main(String[] args){ new EditorWin(); } } class EditorWin extends JFrame implements ActionListener { private JLabel startIp,endIp,l_startPort,l_endPort,l_portOfThread ,showResult ,empty,type ,status; private JTextField f_startIp,f_endIp,f_startPort,f_endPort,f_portOfThread ; private JScrollPane result ; private JComboBox comboBox ; private JButton startScanner,exitScanner ,clear,reset; private JPanel top,bottom ; private JTextArea message ; private String startIpStr ,endIpStr; private int startPort,endPort,portOfThread ,threadNum ; public EditorWin(){ this.setTitle("多线程端口扫描器") ; startIp = new JLabel("扫描的Ip") ; l_startPort = new JLabel("起始端口") ; l_endPort = new JLabel("结束端口") ; l_portOfThread = new JLabel("每个线程扫描端口数") ; status=new JLabel("未开始扫描") ; showResult = new JLabel("扫描结果") ; endIp = new JLabel("结束Ip"); empty = new JLabel(" ") ; type = new JLabel("选择扫描的类型") ; startScanner = new JButton("扫描"); exitScanner = new JButton("退出"); clear = new JButton("清空") ; reset = new JButton("重置") ; f_endIp = new JTextField(12) ; f_startIp = new JTextField(12) ; f_startPort = new JTextField(5) ; f_endPort = new JTextField(5) ; f_portOfThread = new JTextField(5) ; message = new JTextArea(20,20) ; result = new JScrollPane(message) ; result.setColumnHeaderView(showResult) ; comboBox = new JComboBox() ; comboBox.addItem("地址"); comboBox.addItem("地址段"); endIp.setVisible(false) ; f_endIp.setVisible(false) ; top = new JPanel() ; top.add(type); top.add(comboBox) ; top.add(startIp) ; top.add(f_startIp) ; top.add(endIp) ; top.add(f_endIp) ; top.add(l_startPort) ; top.add(f_startPort) ; top.add(l_endPort) ; top.add(f_endPort) ; top.add(l_portOfThread) ; top.add(f_portOfThread) ; bottom = new JPanel() ; bottom.add(status) ; bottom.add(empty) ; bottom.add(empty) ; bottom.add(empty) ; bottom.add(empty) ; bottom.add(empty) ; bottom.add(empty) ; bottom.add(startScanner) ; bottom.add(clear); bottom.add(reset); bottom.add(exitScanner) ; this.add(top,BorderLayout.NORTH); this.add(result,BorderLayout.CENTER) ; this.add(bottom,BorderLayout.SOUTH) ; comboBox.addActionListener(this) ; startScanner.addActionListener(this) ; exitScanner.addActionListener(this) ; clear.addActionListener(this) ; reset.addActionListener(this) ; setSize(1000, 500); setVisible(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } @Override public void actionPerformed(ActionEvent e) { if(e.getSource()==startScanner){ //点击扫描按钮 //点击时刻 startIpStr = f_startIp.getText().trim() ; //得到输入的Ip if(checkIP(startIpStr)){ //判断是否为数字 try{ startPort = Integer.parseInt(f_startPort.getText().trim()) ; endPort = Integer.parseInt(f_endPort.getText().trim()) ; portOfThread =Integer.parseInt(f_portOfThread.getText().trim()) ; threadNum = (endPort-startPort)/portOfThread+1 ; //普安段端口号的范围 if(startPort<0||endPort>65535||startPort>endPort){ JOptionPane.showMessageDialog(this, "端口号范围:0~65535,并且最大端口号应大于最小端口号!") ; } else{ if(portOfThread>endPort-startPort||portOfThread<1){ JOptionPane.showMessageDialog(this, "每个线程扫描的端口数不能大于所有的端口数且不能小于1") ; }else{ if(((String) comboBox.getSelectedItem()).equals("地址")){ message.append("************************************************************"+"\n") ; message.append("正在扫描 "+startIpStr+" 每个线程扫描端口个数"+portOfThread+"\n"+"开启的线程数"+threadNum+"\n") ; message.append("开始端口 "+startPort+" 结束端口" +endPort+"\n") ; message.append("主机名:"+getHostname(startIpStr)+"\n"); message.append("开放的端口如下:"+"\n") ; for(int i = startPort;i <= endPort; i++) { if((i + portOfThread) <= endPort) { new Scan(i, i + portOfThread,startIpStr).start(); i += portOfThread; } else { new Scan(i, endPort,startIpStr).start(); i += portOfThread; } } }else{ endIpStr = f_endIp.getText() ; if(checkIP(endIpStr)){ //扫描Ip地址段 Set ipSet = new HashSet<Object>() ; int start = Integer.valueOf(startIpStr.split("\\.")[3]); int end = Integer.valueOf(endIpStr.split("\\.")[3]); String starts = startIpStr.split("\\.")[0]+"."+startIpStr.split("\\.")[1]+"."+startIpStr.split("\\.")[2]; //生成IP地址 for(int i = start;i<=end;i++){ ipSet.add(starts+"."+i) ; //地海段的每个地址存入集合 } for (Object str : ipSet) { new ScanIp(str.toString()).start() ; } }else{ JOptionPane.showMessageDialog(this, "请输入正确的Ip地址") ; } } } } } catch(NumberFormatException e1){ JOptionPane.showMessageDialog(this, "错误的端口号或端口号和线程数必须为整数") ; } } else{ JOptionPane.showMessageDialog(this, "请输入正确的Ip地址") ; } } else if(e.getSource()==reset){ f_startIp.setText("") ; f_startPort.setText("") ; f_endPort.setText("") ; f_portOfThread.setText("") ; } else if(e.getSource()==clear){ message.setText("") ; System.out.println((String) comboBox.getSelectedItem()); } else if(e.getSource()==exitScanner){ System.exit(1); }else if(e.getSource()==comboBox){ String type=(String) comboBox.getSelectedItem(); if(type.equals("地址")){ endIp.setVisible(false) ; f_endIp.setVisible(false) ; startIp.setText("扫描的Ip") ; }else{ endIp.setVisible(true) ; f_endIp.setVisible(true) ; startIp.setText("开始Ip") ; } } } //扫描端口地址的线程 class Scan extends Thread{ int maxPort, minPort; String Ip; Scan(int minPort, int maxPort,String Ip){ this.minPort=minPort ; this.maxPort=maxPort ; this.Ip=Ip; } @SuppressWarnings("unchecked") public void run() { Socket socket = null ; for(int i = minPort;i<maxPort;i++){ try { socket=new Socket(Ip, i); findInfoByPort(i ,Ip);//通过端口号调用数据库信息 message.append("\n"); socket.close(); } catch (Exception e) { message.append(""); } status.setText("正在扫描"+i) ; } status.setText("扫描结束") ; } } //扫描Ip地址段查看合法Ip的线程 class ScanIp extends Thread{ String Ip ; ScanIp(String Ip ){ this.Ip = Ip ; } public synchronized void run(){ try { for(int i = startPort;i <= endPort; i++) { //扫描开放的Ip InetAddress.getByName(Ip); if((i + portOfThread) <= endPort) { new Scan(i, i + portOfThread,Ip).start(); i += portOfThread; } else { new Scan(i, endPort,Ip).start(); i += portOfThread; } } } catch (Exception e) { System.out.println(Ip+"\n"); } } } //根据端口号,查询数据库中端口号的相应信息并显示在文本域之中 synchronized void findInfoByPort(int port,String Ip){ message.append("-----------------------"+"Ip"+Ip+"的"+"端口号"+port+"------------------------------------"+"\n"); Connection conn ; PreparedStatement pst ; ResultSet rs ; conn = JdbcUtils.getConnection() ;//与数据库建立连接,获取Connection对象 String sql = "Select * from ports where port ="+port; try { pst = conn.prepareStatement(sql) ; rs = pst.executeQuery() ; String totalStr = null ; while(rs.next()){ String server = rs.getString("server"); String info = rs.getString("info") ; message.append("端口信息:"+server+"\n") ; message.append("端口说明:"+info+"\n") ; totalStr = totalStr+server ; } } catch (Exception e) { e.printStackTrace(); } } // 判断输入的IP是否合法 private boolean checkIP(String str) { Pattern pattern = Pattern .compile("^((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]" + "|[*])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]|[*])$"); return pattern.matcher(str).matches(); } //根据Ip获得主机名、 public static synchronized String getHostname(String host){ InetAddress addr ; try { addr = InetAddress.getByName(host); return addr.getHostName(); } catch (UnknownHostException e) { return "网络不通或您输入的信息无法构造InetAddress对象!"; } } }
三、实现功能的界面截图package portScanner; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public final class JdbcUtils { private static String url = "jdbc:mysql://localhost:3306/portInfo?useUnicode=true&characterEncoding=utf8"; private static String user = "root"; private static String psw = "root"; private static Connection conn; static { try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * 获取数据库的连接 * @return conn */ public static Connection getConnection() { if(null == conn) { try { conn = DriverManager.getConnection(url, user, psw); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } } return conn; } /** * 释放资源 * @param conn * @param pstmt * @param rs */ public static void closeResources(Connection conn,PreparedStatement pstmt,ResultSet rs) { if(null != rs) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } finally { if(null != pstmt) { try { pstmt.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } finally { if(null != conn) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } } } } } } } }
地址:
地址
(界面过于丑T-T)
四、多线程扫描端口算法的说明:
原理:根据每个线程扫描端口号的个数,从而对端口号进行分段,每个线程执行一段。for(int i = startPort;i <= endPort; i++) { //扫描开放的Ip InetAddress.getByName(Ip); if((i + portOfThread) <= endPort) { new Scan(i, i + portOfThread,Ip).start(); i += portOfThread; } else { new Scan(i, endPort,Ip).start(); i += portOfThread; }
-
JAVA多线程本地IP端口扫描器
2011-01-19 16:38:53自己制作的JAVA制作的多线程的可用端口扫描。运用了java的swing组件,利用多线程加快扫描速度。功能:获得本地IP,扫描可用端口。 含有两个文件,(main)主类文件,线程类文件。 -
广工_计算机网络课程设计_端口扫描器的设计与实现_代码和报告.zip
2020-01-07 10:46:461.利用Socket通信机制实现一个多线程的端口扫描器。 2.设计要求: 2.1用户界面:用户可以输入IP地址或IP地址段;输入端口号或端口号范围;列表显示主机名、开放的端口及开放端口上相应的服务名称。 2.2端口的... -
online-port-scanner:一个基于Web的在线多线程端口扫描器,前端使用mdui框架开发,后台使用Springboot+...
2021-05-14 04:57:40这是一个Material Design的端口扫描器,前端使用mdui框架开发,后台使用Springboot+SQLite开发。支持单IP单端口快速扫描,指定IP地址段和端口范围批量扫描,使用多线程提高扫描性能。用于检测指定的端口是否开放,并... -
java多线程端口扫描器
2009-11-01 13:20:07此程序可以根据IP地址或者计算机名进行端口扫描! -
基于java多线程的端口扫描器
2009-12-15 23:28:24基于java多线程的端口扫描器,包括如下功能:按照IP地址进行端口扫描,按照给定的IP地址范围,逐个进行扫描、按照主机名进行端口扫描,搜索指定主机名的端口、指定扫描的端口范围、指定扫描的线程数,实现多线程扫描... -
JAVA SWING 多线程扫描局域网IP及端口 shellping v2
2014-03-24 16:37:07描选定IP的常见TCP UDP端口 包括部分常见木马所使用端口 并可以自定义扫描端口 扫描同一网段的IP主要是用SHELL方法 使用PING命令并判断返回值内容 从而确定服务器是否打开 扫描端口的原理是使用socket类判断是否... -
基于多线程的端口扫描器
2009-04-04 18:48:38该扫描器实现了不同方式进行扫描,同时支持端口范围和线程数的手动设定,并且实现了扫描结构的保存功能。 -
java多线程扫描器(转载)
2011-11-27 10:44:41java多线程扫描器,实现对任意主机端口的扫描 -
网络端口扫描器.扫描开放端口.TCP/UDP的Socket通信.支持IP地址网段范围的批量扫描.支持多线程操作,提高...
2022-03-25 13:48:01网络端口扫描器.扫描开放端口 本工具可以扫描一个指定IP的1~65535端口是否开放了TCP/UDP的Socket通信。 特点: 支持TCP/UDP的Socket通信; 支持IP地址网段范围的批量扫描; 支持多线程操作,提高扫描效率; 下载... -
java编写的基于TCP协议的多线程扫描端口程序
2015-10-08 22:40:01java编写的基于TCP协议的多线程扫描端口程序网上找到了一个TCP的扫描端口程序,但发现很慢,于是把它改成了多线程的。 -
java端口扫描器,简单
2008-12-12 10:25:46java端口扫描器,简单易懂,大家来看看1 -
Java编写的多线程端口扫描器
2012-12-05 18:25:00Java中的ServerSocket(int port)可以创建本机指定端口的ServerSocket对象,如果创建失败(端口已经被占用,即系统已经创建了此端口的监听对象实体),因此可以用一个ServerSocket对象逐个创建探测,考虑到端口太多... -
Java编写的多线程本机端口扫描器
2016-02-02 10:33:37Java中的ServerSocket(int port)可以创建本机指定端口的ServerSocket对象,如果创建失败(端口已经被占用,即系统已经创建了此端口的监听对象实体),因此可以用一个ServerSocket对象逐个创建探测,考虑到端口太多... -
Java项目开发系列(端口扫描工具)
2017-12-02 22:09:29首先这是本人写的第一篇博客,可能写的不好请大家见谅 , 以前都是只是记录成笔记放到有道云中 , 自己从来没有分享过任何知识 , 总是看多了别人的分享 . 以后本人每次写了新的项目和学习了新的知识的笔记都会放到这个... -
端口扫描器的设计与实现
2013-04-19 17:05:27三、端口扫描器视图 6 1、工作窗口 6 2、异常窗口 6 3、窗口核心代码 6 四、多线程快速扫描 7 1、多线程机制 7 2、多线程核心代码 8 五、用户使用方法 9 1、页面说明 9 2、按主机名扫描 9 3、按IP地址扫描 9 六、... -
java端口扫描器
2016-03-05 12:11:35因为找不到win8下趁手的端口扫描工具,刚好学了java不久,决定自己动手写个端口扫描练练手 使用了多线程扫描,加快扫描速度 程序很简单,直接上代码 package com.lyp.portscan; import java.io.File; import java.... -
java 实现简单的端口扫描程序
2021-03-19 16:38:26使用多线程加快扫描速度。 package com.zhong.exam7; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; import java.util.concurrent.ExecutorService; import jav