Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 510|回复: 0

[图像处理学习]自动识别图形验证码

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-29 23:57:00 | 显示全部楼层 |阅读模式
    现在大多数网站都采用了验证码来防止暴力破解或恶意提交。但验证码真的就很安全吗?真的就不能被机器识别??
    我先讲讲我是怎么实现站外提交留言到一个网站的程序。
    这个网站的留言版大致如下:




    我一看这种简单的4位数字验证码,马上就感觉到有戏了。直觉告诉我让电脑来识别这些图片验证码据对简单o(∩_∩)o...
    首先我马上在这个页面用右键菜单看源代码


    知道验证码获取页面后 你可以直接用 http://www.XXXX.com/imgchk/validatecode.asp 这样去访问你会发现你打开的就是一个验证码图片。




    对的其实返回的就是图片文件的2进制流而已。接着先用右键保存一张验证码的图片。因为要开始分析这张图片了,什么用什么工具?PhotoShop????不用就一般的画图工具就可以了。我们要搞清楚的是 这几个数字分别占几个像素就可以了。




    可以看出 一个数字5*9  也就是45个像素。恩 这就可以了 另外我们可以看出 默认区域就是白色
    (姑且说是白色因为我们肉眼看就是白色)
    那么我的程序识别原理就是固定去扫描这45个像素点。看每个点的颜色是不是和默认的颜色一致
    一致的话就标记为0 ,不一致就标记为1 。
    如一个数子是2 那么我的程序扫描出来的图像就应该是:
    011110
    100001
    000001
    000001
    000010
    000100
    001000
    010000
    100000
    111111
    如果一个数字是7那么扫描出来的图像就是:
    111111
    100001
    000010
    000010
    000100
    000100
    001000
    001000
    010000
    010000

    恩,就这么简单呵呵。下面给出图像 扫描的java类 (不好意思,在我会的语言里面除开java就剩sql了)
       
       
         



         package
          com.util;


         //
         ~--- JDK imports ------------------------------------------------------------
         

         

         import
          com.sun.image.codec.jpeg.JPEGCodec;

         import
          com.sun.image.codec.jpeg.JPEGEncodeParam;

         import
          com.sun.image.codec.jpeg.JPEGImageEncoder;


         import
          java.awt.
         *
         ;

         import
          java.awt.image.
         *
         ;


         import
          java.io.
         *
         ;

         import
          java.io.FileOutputStream;

         import
          java.io.OutputStream;


         import
          java.net.
         *
         ;


         import
          javax.imageio.
         *
         ;

         import
          javax.imageio.ImageIO;


         /** */
         /**
      *   登陆验证图片转换为数字
      *
      *
      * @version    1.0, 08/04/20
      * @author     张健滢
      */
         

         public
          
         class
          ImgIdent
         ...
         {

         // 数字字符比特表
        private final long[][] NUMERIC = ...{
            ...{ 512104545, 562436190 },    // "0"
            ...{ 148931080, 136348222 },    // "1"
            ...{ 511971394, 69273663 },     // "2"
            ...{ 511971406, 17045598 },     // "3"
            ...{ 35168914, 586948743 },     // "4"
            ...{ 1065486398, 17045598 },    // "5"
            ...{ 239208494, 830871646 },    // "6"
            ...{ 1065623684, 69239824 },    // "7"
            ...{ 512104542, 562436190 },    // "8"
            ...{ 512104547, 486805660 }
         };                               // "9"

         // 字框高
         private int intCharHeight = 10;

         // 字框横向间隙
         private int intCharSpaceH = 5;

         // 字框纵向间隙
         private int intCharSpaceY = 1;

         // 字框宽
         private int           intCharWidth = 5;
         private int           IntImgHeight;
         private BufferedImage img;
         private int           intBgColor;
         private int           intCharColor;
         private int           intImgWith;
         private int           intMaxX;
         private int           intMaxY;
         private int           intMinX;
         private int           intMinY;

         // 座标原点
         private Point  pOrigin;
         private String strNum;

        /** *//**
          * Constructs ...
          *
          *
          * @param img
          *
          * @throws IOException
          */
        public ImgIdent(BufferedImage img) throws IOException ...{
             this.img = img;
             init();
         }

        /** *//**
          *   构造函数
          *   @param   file     本地文件
          *   @throws   IOException
          */
        public ImgIdent(File file) throws IOException ...{
             img = ImageIO.read(file);
             init();
         }

        /** *//**
          *   构造函数
          *   @param   url    远程文件
          *   @throws   IOException
          */
        public ImgIdent(URL url) throws IOException ...{
             img = ImageIO.read(url);
             init();
         }

        /** *//**
          *   类初始工作
          */
        private void init() ...{

             // 得到图象的长度和宽度
             intImgWith   = img.getWidth();
             IntImgHeight = img.getHeight();

             // 得到图象的背景颜色
             intBgColor = img.getRGB(7, 4);

             // System.out.println(intBgColor);

             // 初始化图象原点座标
             pOrigin = new Point(0, 0);
         }

        /** *//**
          * Method description
          *
          */
        private void getBaseInfo() ...{
             System.out.println(intBgColor + "|" + intCharColor);
             System.out.println(intMinX + "|" + intMinY + "|" + intMaxX + "|" + intMaxY);
         }

        /** *//**
          *   得到字符的左上右下点座标
          *   @param   intNo   int                                   第n个字符
          *   @return   int[]
          */
        private Point[] getCharRange(int intNo) ...{

             // 左上右下点座标
             Point pTopLeft     = new Point(0, 0);
             Point pBottomRight = new Point(0, 0);

             // 左上点
             pTopLeft.x = pOrigin.x + intCharWidth * (intNo - 1) + intCharSpaceH * (intNo - 1);
             pTopLeft.y = pOrigin.y;

             // 右下点
             pBottomRight.x = 1 + pOrigin.x + intCharWidth * intNo + intCharSpaceH * (intNo - 1) - 1;
             pBottomRight.y = pOrigin.y + intCharHeight - 1;

            return new Point[] ...{ pTopLeft, pBottomRight };
         }

        /** *//**
          *   与背景颜色比较返回相应的字符
          *   @param   x   int                                           横座标
          *   @param   y   int                                           纵座标
          *   @return   char                                           返回字符
          */
        private char getBit(int x, int y) ...{
             int intCurtColor;

             intCurtColor = img.getRGB(x, y);

             //System.out.println("[" + x + "," + y + "]" + intCurtColor + "==" + intBgColor + "==>" + (Math.abs(intCurtColor) >7308252));
    //      return (Math.abs(intCurtColor) >= 5689325)
    //              ? "0"
    //              : "1";
             return (intCurtColor == intBgColor)
                    ? "0"
                    : "1";

             // 5689325    6008535
         }

        /** *//**
          *   得到第n个字符对应的字符串
          *   @param   intNo   int                                   第n个字符
          *   @return   String                                       代表字符位的串
          */
        private String getCharString(int intNo) ...{

             // 本字符的左上右下点座标
             Point[] p            = getCharRange(intNo);
             Point   pTopLeft     = p[0];
             Point   pBottomRight = p[1];

             // 换算边界值
             int intX1, intY1, intX2, intY2;

             intX1 = pTopLeft.x;
             intY1 = pTopLeft.y;
             intX2 = pBottomRight.x;
             intY2 = pBottomRight.y;

    //      System.out.println("intX1=" + intX1);
    //      System.out.println("intY1=" + intY1);
    //      System.out.println("intX2=" + intX2);
    //      System.out.println("intY2=" + intY2);

             // 在边界内循环取象素
             int    i, j;
             String strChar = "";

            for (i = intY1; i <= intY2; i++) ...{
                for (j = intX1; j <= intX2; j++) ...{
                     System.out.print(getBit(j, i));
                     strChar = strChar + getBit(j, i);
                 }

                 System.out.println();
             }

             System.out.println();

             return strChar;
         }

        /** *//**
          *   得到第n个字符对应数值
          *   @param   intNo   int                                   第n个字符
          *   @return   int                                             对应数值
          */
        public int getNum(int intNo) ...{

             // 取得位字符串
             String strChar = getCharString(intNo);

             // System.out.println(intNo+"=="+strChar);
             // 取得串高位串和低位串
             String strCharHigh = strChar.substring(0, strChar.length() / 2);
             String strCharLow  = strChar.substring(strChar.length() / 2);

             // 计算高位和低位值
             long lCharHigh = Long.parseLong(strCharHigh, 2);

             System.out.println(lCharHigh);

             long lCharLow = Long.parseLong(strCharLow, 2);

             System.out.println(lCharLow);

             // 在数字中循环比较
             int intNum = "*";

            for (int i = 0; i <= 9; i++) ...{
                if ((lCharHigh == NUMERIC[0]) && (lCharLow == NUMERIC[1])) ...{
                     intNum = i;

                     break;
                } else ...{
                    if ((lCharHigh == 834533329) && (lCharLow == 242870177)) ...{
                         intNum = 6;
                     }    // 834533329 242870177
                            else ...{
                         intNum = 1;
                     }    // 默认为1   低位为    937393609  937393601
                 }
             }

             return intNum;
         }

        /** *//**
          * 保存图片
          *
          *
          * @param length
          *
          * @return
          */
        public String getValidatecode(int length) ...{
             String strNum = "";

            for (int i = 1; i <= length; i++) ...{
                synchronized (this) ...{
                     strNum += String.valueOf(getNum(i));
                 }
             }

             return strNum;
         }

        /** *//**
          * Method description
          *
          *
          * @param iag
          * @param savePath
          *
          * @throws FileNotFoundException
          * @throws IOException
          */
        public void saveJPEG(BufferedImage iag, String savePath) throws FileNotFoundException, IOException ...{
             OutputStream     jos     = new FileOutputStream(savePath);
             JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(jos);
             JPEGEncodeParam  jpegEP  = JPEGCodec.getDefaultJPEGEncodeParam(iag);

             jpegEP.setQuality((float) 1, true);
             encoder.encode(iag, jpegEP);
             jos.flush();
             jos.close();
         }
    }
         

         
       

    恩这样数字是可以识别出来了,可以我要怎么完成提交那块的工作呢?好在Apache已经为我做完了。我用了
    HttpClient这样一个模拟Http协议的小工具包。我只要往那个 Add_MSG.asp里面提交就完了。


       
       
         package
          com.util;


         //
         ~--- non-JDK imports --------------------------------------------------------
         

         

         import
          org.apache.commons.httpclient.
         *
         ;

         import
          org.apache.commons.httpclient.methods.GetMethod;

         import
          org.apache.commons.httpclient.methods.PostMethod;

         import
          org.apache.commons.httpclient.params.HttpClientParams;

         import
          org.apache.commons.httpclient.params.HttpMethodParams;


         //
         ~--- JDK imports ------------------------------------------------------------
         

         

         import
          java.awt.image.BufferedImage;


         import
          java.io.InputStream;


         import
          javax.imageio.ImageIO;



         public
          
         class
          MyHttpClient
         ...
         {

        /** *//**
          * Method description
          *
          *
          * @param title 留言标题
          * @param name 留言者
          * @param Content 内容
          * @param proIP 代理IP
          * @param port  代理端口
          * @param usePro 是否使用代理
          */
         public synchronized void doSomeThing(String title, String name, String Content, String proIP, int port,
                boolean usePro) ...{

             // 构造HttpClient的实例
             HttpClient       httpClient   = new HttpClient();
             HttpClientParams clientParams = new HttpClientParams();

             // 隐藏自己请求相关的信息
             clientParams.setParameter("http.useragent", "Mozilla/4.0 (compatible; FIREFOX 9.0; IBM AIX 5)");

             // httpClient.getHttpConnectionManager().getParams().setSoTimeout(30 * 1000);
             clientParams.setHttpElementCharset("GBK");

             HttpState httpState = new HttpState();

             httpClient.setParams(clientParams);
             httpClient.getParams().setParameter(HttpClientParams.HTTP_CONTENT_CHARSET, "GBK");
             httpClient.setState(httpState);
             clientParams.setVersion(HttpVersion.HTTP_1_1);

             // httpClient.getHostConfiguration().setProxy("148.233.159.58", 3128);

             if (usePro)    // 使用代理
            ...{
                 httpClient.getHostConfiguration().setProxy(proIP, port);
             }

             // 创建GET方法的实例
             GetMethod getMethod = new GetMethod("http://www.XXXcom/Guestbook/imgchk/validatecode.asp");

             // 使用系统提供的默认的恢复策略
             getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());

            try ...{

                 // 执行getMethod
                 int statusCode = httpClient.executeMethod(getMethod);

                 // System.out.println(statusCode);
                if (statusCode != HttpStatus.SC_OK) ...{
                     System.err.println("Method failed: " + getMethod.getStatusLine());
                 }    // 读取内容

                 InputStream inStream = getMethod.getResponseBodyAsStream();

                 // 处理内容
                 // System.out.println(new String(responseBody));
                 BufferedImage iag      = ImageIO.read(inStream);
                 ImgIdent      imgIdent = new ImgIdent(iag);

                 // imgIdent.saveJPEG(iag, "C:/ddd.jpg");
                 String validate = imgIdent.getValidatecode(4);

                 System.out.println(validate);

                 PostMethod method  = new PostMethod("http://www.XXX.com/Guestbook/add_msg.asp");
                 String     connect = Content;
                 String     Title   = title;

                 method.setParameter("subject", Title);
                 method.setParameter("g_name", name);
                 method.setParameter("companyname", "");
                 method.setParameter("mail", "");
                 method.setParameter("homepageurl", "http://");
                 method.setParameter("pic", "p5.gif");
                 method.setParameter("validatecode", validate);
                 method.setParameter("content", connect);

    //          if (todo) {
                 int code = httpClient.executeMethod(method);

                 // String Stringresponse = new String(method.getResponseBodyAsString().getBytes("8859_1"));
                 // 打印返回的信息
                 // System.out.println(Stringresponse);
    //          }

                 method.releaseConnection();

    //          System.out.println(iag.getHeight());
    //          System.out.println(iag.getWidth());
    //          //背景 颜色
    //          intBgColor = iag.getRGB(38, 0);
    //          System.out.println("intBgColor=" + intBgColor);
    //
    //
    //          intBgColor = iag.getRGB(0, 0);
    //          System.out.println("intBgColor=" + intBgColor);
            } catch (Exception e) ...{

                 // 发生网络异常
                 e.printStackTrace();
            } finally ...{}

             // 释放连接   getMethod.releaseConnection();  }
             getMethod.releaseConnection();
         }
    }
         

         
       

    恩 就这样了,最后结合SAF整成这样了。什么?为什么不用SWT?想过了SWING才是王道o(∩_∩)o...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-26 01:25 , Processed in 0.318154 second(s), 36 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表