通过比较rgb破解滑动验证码
目标url:信用中国(广东中山)行政处罚
/** * base64转BufferedImage * * @param base64 * @return */ public static BufferedImage base64ToBufferedImage(String base64) { BufferedImage ret = null; try { Decoder decoder = Base64.getDecoder(); ByteArrayInputStream bais = new ByteArrayInputStream(decoder.decode(base64)); ret = ImageIO.read(bais); return ret; } catch (IOException ex) { Logger.getLogger(SliderUtil.class.getName()).log(Level.SEVERE, null, ex); return ret; } } /** * 获取滑块偏移距离和session * * @param url * @param session * @return * @throws IOException */ public static int getDistanceAndSession(String url, StringBuffer session) throws IOException { int ret = -1; Gson gson = new Gson(); Connection conn = Jsoup.connect(url); conn.method(Connection.Method.GET).timeout(10 * 1000).ignoreContentType(true).maxBodySize(0); Response res = conn.execute(); //获取session //先清空 session.delete(0, session.length()); session.append(res.cookie("JSESSIONID")); HashMap<String, Object> hm = gson.fromJson(res.body(), HashMap.class); //滑块相对于原图的y坐标偏移 int puzzleYAxis = Integer.parseInt(hm.get("puzzleYAxis").toString()); //图片的base64字符 String sourceBase64 = hm.get("sourceImg").toString().replace("\r\n", ""); String puzzleBase64 = hm.get("puzzleImg").toString().replace("\r\n", ""); //原图 BufferedImage sourceImg = base64ToBufferedImage(sourceBase64); //滑块 BufferedImage puzzleImg = base64ToBufferedImage(puzzleBase64); //滑块宽度 int puzzleImgWidth = puzzleImg.getWidth(); //滑块高度 int puzzleImgHeight = puzzleImg.getHeight(); //原图宽度 int width = sourceImg.getWidth(); //原图高度 int height = sourceImg.getHeight(); // //用于保存原图的rgb // int[] rgbArray = new int[width * height]; // sourceImg.getRGB(0, 0, width, height, rgbArray, 0, width); //保存原图待对比的rgb数组 int[] sourceImgRgbArr = new int[width * puzzleImgHeight]; //保存滑块的rgb数组 int[] puzzleImgRgbArr = new int[puzzleImgWidth * puzzleImgHeight]; //将滑块的rgb复制到rgb数组中 puzzleImg.getRGB(0, 0, puzzleImgWidth, puzzleImgHeight, puzzleImgRgbArr, 0, puzzleImgWidth); int k = 0; //截取与滑块等高的rgb数组 for (int i = puzzleYAxis; i < puzzleYAxis + puzzleImgHeight; i++) { for (int j = 0; j < width; j++) { //获取需要对比的原图rgb数组 sourceImgRgbArr[k++] = sourceImg.getRGB(j, i); // System.out.printf("%10x", img.getRGB(j, i)); // System.out.println(k); } // System.out.println(); } //记录当前比对的第几列 int index = 0; //记录已比对的列数 int c = 0; //总的比对列数 //只要比对六列相等,就认为找到位置 int count = 6; //是否找到rgb相等的值 boolean isFind = false; //比对每一列的数据 for (int i = 0; i < width; i++) { //记录当前比对的第几列 index = i; for (int j = 0; j < puzzleImgHeight; j++) { //判断rgb值是否相等 if (sourceImgRgbArr[j * width + i] != puzzleImgRgbArr[j * puzzleImgWidth + c]) { //标志更新为false isFind = false; // System.out.println(i); //重置比对的次数 c = 0; //只要不相等就跳过此次列的比对 break; } else if (c == count && isFind) { //找count次并且标志为true就算找到 break; } isFind = true; // System.out.print(" "); } ////找count次并且标志为true就算找到,不再继续 if (isFind && c == count) { break; } // System.out.println(); //更新目前已比对的列数 c++; } //如果找到,返回初始比对的第几列 //后比对的第几列 - 已经比对的列数 = 初始比对的位置(即滑块的正确位置) if (isFind) { ret = index - count; } return ret; }
原理:通过滑块的rgb数组与原图rgb数组进行对比。
1.把rgb数组看成二维
2.比对滑块rbg数组的前几列(自定义)与原图rgb数组进行循环比对
3.只要前几列对比成功就返回初始对比列的索引