Java写黑软-端口扫描器篇

Java写黑软-端口扫描器篇
海啸天鸣(Ansty)
上次我们用Java写了一个“文件最后修改时间编辑器”的小黑软,现在我们来用Java来写我们平时经常用的端口扫描器。这次为了方便和避免GUI编程的麻烦,我们就直接做成命令行下面的工具,用参数来启动它。我们姑且把它命名为“Java版简单端口扫描工具”,因为本文只是提供Java写黑软的思路,许多算法优化和功能附加不在本文的讨论之列,使用的也是单线程。
程序界面:



程序原理:
利用java.net.Socket类来建立socket连接,如果无法与指定的IP和端口建立连接,将会抛出IOException。我们用try-catch对这个IOException这个异常进行捕获,以判断是否成功与指定的IP端口建立连接。如果成功建立了连接,说明指定IP的指定端口已经开放;如果程序抛出了一个IOException异常被我们捕获,则说明指定的IP没有开放指定的端口。扫描指定端口段则是利用循环不断与服务器的指定端口进行连接,供我们判断是否开放。

我一直坚信,世界上的所有问题只要有了明确的算法,我们就一定能用程序语言来实现它,无论什么语言!现在,我们有了原理就等于有了算法,你说我们除了技术以外还缺什么?只缺动手了!

因为我们要从程序启动的参数中获得服务器地址、起始端口、终止端口的信息,所以我们就要用到下面这段代码:
ip = args[0]; //获得我们指定的服务器地址
startPort = Integer.parseInt(args[1]); //获得起始端口号,因为args[]是String类型,所以要强制转换成int类型。
endPort = Integer.parseInt(args[2]); //获得终止端口号,同上
在得到端口和建立socket之前一定要判断端口的合法性,因为端口的范围是在1~65535,如果我们去建立范围外端口的连接是没必要的,而且是不可行的。既然是起始端口和终止端口,那么就要有个大小顺序问题,就是判断它们的大小。

Copy code
if(startPort<1||startPort>65535||endPort<1||endPort>65535){    //检查端口是否在合法范围1~65535
System.out.printf("端口范围必须在1~65535以内!");
return;
}else if(startPort>endPort){ //比较起始端口和终止端口
System.out.println("端口输入有误!/n起始端口必须小于终止端口");
return;
}


建立与服务器指定端口的连接,这里就要用到java.net.Socket类了,首先我们来看看它的构造方法:
Socket() 通过系统默认类型的 SocketImpl 创建未连接套接字
Socket(InetAddress address, int port) 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
Socket(InetAddress address, int port, InetAddress localAddr, int localPort) 创建一个套接字并将其连接到指定远程端口上的指定远程地址。
Socket(Proxy proxy) 根据不管其他设置如何都应使用的指定代理类型(如果有),创建一个未连接的套接字。
Socket(SocketImpl impl) 创建带有用户指定的 SocketImpl 的未连接 Socket。
Socket(String host, int port) 创建一个流套接字并将其连接到指定主机上的指定端口号。
Socket(String host, int port, InetAddress localAddr, int localPort) 创建一个套接字并将其连接到指定远程主机上的指定远程端口。
可以看到,我们有很多中构造方法,我们现在只需要关心第二种构造方法Socket(InetAddress address, int port),因为我们并不需要与服务器运行在端口的服务进行交互,所以我们只要建立连接,然后关闭连接即可。即:
Socket s = new Socket(address,port);
我们在建立连接之前,首先要把ip转换成InetAddress类型,不是说String类型不能用,是为了能减少出现更多异常的可能。
static InetAddress getByName(String host) 在给定主机名的情况下确定主机的 IP 地址。这是静态方法,直接InetAddress.getByName()就行了。

Copy code
try{
InetAddress address = InetAddress.getByName(ip); //转换类型
}catch(UnknownHostException e){
System.out.println("无法找到 "+ ip);
return;
}


下面是我们的核心算法了
循环指定端口段的所有端口,对所有端口建立连接。连接成功后我们就算完成了当前循环的任务,然后就调用close()方法关闭连接。因为在Socket s = new Socket(address,nport)执行的时候,如果成功建立连接,就不会执行到catch里面,就能执行到下面result.add(“”+nport)语句;如果不能连接上去就会抛出一个异常被我们捕获,程序就会运行到catch里面,执行catch里面的语句;最后继续下一个循环。

Copy code
for(int nport=startPort;nport<=endPort;nport++){    //从起始端口到终止端口进行循环
try{
System.out.print("Scanning "+nport); //打印扫描进度
Socket s=new Socket(address,nport); //建立连接
s
.close(); //关闭连接
result
.add(""+nport); //将打开的端口添加到ArrayList result里面
System.out.println(" : open"); //打印状态
}catch(IOException e){
System.out.println(":close"); //打印状态
}
}


打印结果,因为我们用到了ArrayList来存储扫描结果,Java里面没有C语言意义上的指针,所以我们在访问ArrayList里面的元素要用到ListIterator。
ListIterator li = result.listIterator(); //获得ArrayList的ListIterator
while(li.hasNext()){ // 如果li里面有元素
System.out.println(li.next().toString()+"/tOpen"); //打印出指向的元素,同时将指向下一个元素
}
好了,现在我们就已经把主要功能的程序代码介绍完了,相信读者看完以后能用Java编写自己的Java版黑软了。正如我前文说的,本文只提供一种思路。如果朋友有兴趣,可以自己在本文的基础上实现多线程、扩展一些有用的功能,把GUI界面做出来,或者做成仿SuperScan就更强大了。本人在黑防论坛的ID是Ansty,大家对本文有问题可以到论坛里M我

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
public static JFrame main=new JFrame("JAVA端口扫描器"); //显示扫描结果 public static JTextArea Result=new JTextArea("",4,40); //滚动条面板 public static JScrollPane resultPane = new JScrollPane(Result,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); //输入主机名文本框 public static JTextField hostname=new JTextField("localhost",8); //输入ip地址前3位的输入框 public static JTextField fromip1=new JTextField("0",3); //输入ip地址4~6位的输入框 public static JTextField fromip2=new JTextField("0",3); //输入ip地址7~9位的输入框 public static JTextField fromip3=new JTextField("0",3); //输入起始ip地址最后4位的输入框 public static JTextField fromip4=new JTextField("0",3); //输入目标ip地址最后4位的输入框 public static JTextField toip=new JTextField("0",3); //输入最小端口的输入框 public static JTextField minPort=new JTextField("0",4); //输入最大端口的输入框 public static JTextField maxPort=new JTextField("1000",4); //输入最大线程数量的输入框 public static JTextField maxThread=new JTextField("100",3); //错误提示框 public static JDialog DLGError=new JDialog(main,"错误!"); public static JLabel DLGINFO=new JLabel(""); public static JLabel type=new JLabel("请选择:"); //扫描类型 public static JRadioButton radioIp = new JRadioButton("IP地址:"); public static JRadioButton radioHost = new JRadioButton("主机名:",true); //单选框组 public static ButtonGroup group = new ButtonGroup(); public static JLabel P1=new JLabel("端口范围:"); public static JLabel P2=new JLabel("~"); public static JLabel P3=new JLabel("~"); public static JLabel Pdot1 = new JLabel("."); public static JLabel Pdot2 = new JLabel("."); public static JLabel Pdot3 = new JLabel("."); public static JLabel TNUM=new JLabel("线程数:"); public static JLabel RST=new JLabel("扫描结果: "); public static JLabel con=new JLabel(" "); //定义按钮 public static JButton OK = new JButton("确定"); public static JButton Submit = new JButton("开始扫描"); public static JButton Cancel = new JButton("退出"); public static JButton saveButton = new JButton("保存扫描结果"); //菜单栏 public static JMenuBar myBar = new JMenuBar(); public static JMenu myMenu = new JMenu("文件(F)"); public static JMenuItem saveItem = new JMenuItem("保存扫描结果(S)"); public static JMenuItem exitItem = new JMenuItem("退出(Q)"); public static JMenu myMenu2 = new JMenu("帮助"); public static JMenuItem helpItem = new JMenuItem("阅读"); public static void main(String[] args){ main.setSize(500,400); main.setLocation(300,300); main.setResizable(false); main.setLayout(new GridBagLayout()); main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); DLGError.setSize(300,100); DLGError.setLocation(400,400); //添加“菜单栏” myMenu.add(saveItem); myMenu.add(exitItem); myMenu2.add(helpItem); myBar.add(myMenu); myBar.add(myMenu2); main.setJMenuBar(myBar); //设置热键 myMenu.setMnemonic('F'); saveItem.setMnemonic ('S'); //为“另存为”组件设置快捷键为ctrl+s saveItem.setAccelerator (KeyStroke.getKeyStroke (KeyEvent.VK_S,InputEvent.CTRL_MASK)); exitItem.setMnemonic('Q'); exitItem.setAccelerator (KeyStroke.getKeyStroke (KeyEvent.VK_E,InputEvent.CTRL_MASK)); //采用表格包型布局 Container mPanel = main.getContentPane(); GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(10,0,0,10); c.gridx = 0; c.gridy = 0; c.gridwidth = 10; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(type,c); group.add(radioIp); group.add(radioHost); c.gridx = 0; c.gridy = 1; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(radioIp,c); c.gridx = 1; c.gridy = 1; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(fromip1,c); c.gridx = 2; c.gridy = 1; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(Pdot1,c); c.gridx = 3; c.gridy = 1; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(fromip2,c); c.gridx = 4; c.gridy = 1; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(Pdot2,c); c.gridx = 5; c.gridy = 1; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(fromip3,c); c.gridx = 6; c.gridy = 1; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(Pdot3,c); c.gridx = 7; c.gridy = 1; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(fromip4,c); c.gridx = 8; c.gridy = 1; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(P2,c); c.gridx = 9; c.gridy = 1; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(toip,c); c.gridx = 0; c.gridy = 2; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(radioHost,c); c.gridx = 1; c.gridy = 2; c.gridwidth = 3; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(hostname,c); c.gridx = 0; c.gridy = 3; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(P1,c); c.gridx = 1; c.gridy = 3; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(minPort,c); c.gridx = 2; c.gridy = 3; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(P3,c); c.gridx = 3; c.gridy = 3; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(maxPort,c); c.gridx = 0; c.gridy = 4; c.gridwidth = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(TNUM,c); c.gridx = 1; c.gridy = 4; c.gridwidth = 3; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; mPanel.add(maxThread,c);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值