1. 程式人生 > >極驗驗證碼的破解2-圖片還原和滑塊位置求解

極驗驗證碼的破解2-圖片還原和滑塊位置求解

上一章我們討論了破解極驗驗證碼的思路和步驟,這一章我將介紹如何還原兩張背景圖和求解滑塊的目標位置。

一、圖片還原

我們首先看看頁面上給了我們什麼引數:

image

這個是完整的背景圖(fullbg)的頁面元素,可以看到他們都是來自於同一張原圖,只是擷取的位置不同。上圖紅框就是該小圖片在原圖中的位置,每一張小圖片都是10個畫素寬,58個畫素高,我們再來看看原圖:

image

確實很亂,根本看不出什麼東西。如果我們把這個原圖下載下來,然後按照頁面上的引數擷取一個個10畫素寬,58畫素高的小圖片拼接在一起便可以得到完整的背景圖了,上程式碼:

複製程式碼
/**
     * 合成指定的多張圖片到一張圖片
     *
     * 
@param imgSrcList 圖片的地址列表 * @param topLeftPointList 每張小圖片的偏移量 * @param countOfLine 每行的小圖片個數 * @param cutWidth 每張小圖片擷取的寬度(畫素) * @param cutHeight 每張小圖片擷取的高度(畫素) * @param savePath 合併後圖片的儲存路徑 * @param subfix 合併後圖片的字尾 * @return 是否合併成功
*/ public static boolean combineImages(List<String> imgSrcList, List<String[]> topLeftPointList, int countOfLine, int cutWidth, int cutHeight, String savePath, String subfix) { if (imgSrcList == null || savePath == null || savePath.trim().length() == 0) return false; BufferedImage lastImage
= new BufferedImage(cutWidth * countOfLine, cutHeight * ((int) (Math.floor(imgSrcList.size() / countOfLine))), BufferedImage.TYPE_INT_RGB); String prevSrc = ""; BufferedImage prevImage = null; try { for (int i = 0; i < imgSrcList.size(); i++) { String src = imgSrcList.get(i); BufferedImage image; if (src.equals(prevSrc)) image = prevImage; else { if (src.trim().toLowerCase().startsWith("http")) image = ImageIO.read(new URL(src)); else image = ImageIO.read(new File(src)); prevSrc = src; prevImage = image; } if (image == null) continue; String[] topLeftPoint = topLeftPointList.get(i); int[] pixArray = image.getRGB(0 - Integer.parseInt(topLeftPoint[0].trim()), 0 - Integer.parseInt(topLeftPoint[1].trim()), cutWidth, cutHeight, null, 0, cutWidth); int startX = ((i) % countOfLine) * cutWidth; int startY = ((i) / countOfLine) * cutHeight; lastImage.setRGB(startX, startY, cutWidth, cutHeight, pixArray, 0, cutWidth); } File file = new File(savePath); return ImageIO.write(lastImage, subfix, file); } catch (Exception ex) { ex.printStackTrace(); return false; } }
複製程式碼

帶洞的背景圖也是一樣的處理,現在看看我們還原後的兩張背景圖:

image

二、求解滑塊移動目標位置

有了第一步的結果,我們只需要對比兩張背景圖的畫素,從左往右掃描即可找到滑塊的目標位置了,還是看程式碼:

複製程式碼
public static int findXDiffRectangeOfTwoImage(String imgSrc1, String imgSrc2) {
        try {
            BufferedImage image1 = ImageIO.read(new File(imgSrc1));
            BufferedImage image2 = ImageIO.read(new File(imgSrc2));
            int width1 = image1.getWidth();
            int height1 = image1.getHeight();
            int width2 = image2.getWidth();
            int height2 = image2.getHeight();

            if (width1 != width2) return -1;
            if (height1 != height2) return -1;

            int left = 0;
            /**
             * 從左至右掃描
             */
            boolean flag = false;
            for (int i = 0; i < width1; i++) {
                for (int j = 0; j < height1; j++)
                    if (isPixelNotEqual(image1, image2, i, j)) {
                        left = i;
                        flag = true;
                        break;
                    }
                if (flag) break;
            }
            return left;
        } catch (Exception ex) {
            ex.printStackTrace();
            return -1;
        }
    }

    private static boolean isPixelNotEqual(BufferedImage image1, BufferedImage image2, int i, int j) {
        int pixel1 = image1.getRGB(i, j);
        int pixel2 = image2.getRGB(i, j);

        int[] rgb1 = new int[3];
        rgb1[0] = (pixel1 & 0xff0000) >> 16;
        rgb1[1] = (pixel1 & 0xff00) >> 8;
        rgb1[2] = (pixel1 & 0xff);

        int[] rgb2 = new int[3];
        rgb2[0] = (pixel2 & 0xff0000) >> 16;
        rgb2[1] = (pixel2 & 0xff00) >> 8;
        rgb2[2] = (pixel2 & 0xff);

        for (int k = 0; k < 3; k++)
            if (Math.abs(rgb1[k] - rgb2[k]) > 50)//因為背景圖會有一些畫素差異
                return true;

        return false;
    }
複製程式碼

值得注意的是,比較畫素的時候要設定一個容差值,可能是兩張背景圖經過多次處理存在了一定的畫素差異,也可能是有個水印。

求解出滑塊的目標位置後,我們是不是直接按照這個位移來拖動滑塊就行了呢?答案是否定的,看下圖:

image

可以看到在滑動之前滑塊與背景圖就已經存在一個距離了,需要做一個位移的調整,經過觀察,這個值大概是7個畫素,因此:最終滑動位移=求解出的滑塊left畫素個數-7。

下一章我將介紹如何使用模擬瀏覽器來載入和渲染頁面。