支付宝VR红包简陋破解方法。(红包图片处理)

临近新年,支付宝今年又出了新花样——VR红包。

大概玩法是,用户根据红包地图指引,走到红白位置,然后根据藏红包的具体地点图片扫描该地点便可打开红包。根据这种玩法,想要获取陌生人的红包难度可想而知,并且很多发红包者定的详细地点在其家中,这种红包根本无法获取。事实是不是这样呢?下面就介绍一种方法,可以破解部分附近的红包,该方法亲测可破解至少50%的红包。

首先说下劳动成果,VR红包每日领取上限是10个,小区附近的几个红包还未领完就到上限了,大概收获了20多块。
这里写图片描述

分析

我们根据红包的打开条件可知要打开VR红包需要两个技术:定位、图像识别。

  • 定位来说,目前VR红包定位并不苛刻,是一个较大的范围,所以不用做考虑。
  • 图像识别,这是红包打开的方式,也是突破点,我们要处理的也就是这一块。

下面是一张VR红包扫描界面的截图,方框显示的是详细地点,而实际场景需与图片中的地点是同一个,红包才可打开,采用的是图像识别技术。所以我们是不是可以直接扫描该截屏中的图片呢?
No,No,No,支付宝为了避免这种状况,所以加了条纹干扰,我们要做的就是讲这种干扰降到最低,让图片可以被识别。

处理前:
处理前

处理后:
这里写图片描述

限于本人技术有限,处理得不算太好,但是也勉强可识别了,下面就给出Java版本的处理方法。

处理思路

大概思路是依次读取像素点,根据像素点的RGB值判断是否为干扰线,是干扰线则进行一些处理。

1、我们看到,详细地点图片是内嵌在整个截图中的,所以我们需要首先把图片扣取出来。用到了BufferedImage的getSubimage方法。

public BufferedImage getCutImage(int x,int y,int w,int h) {
    return bufImg.getSubimage(x,y,w,h);
}

2、判断黑色干扰线,判断干扰线有很多种方法,下面是大概的一种实现思路,读取到图片一行的像素点后,根据该行像素点rgb值得最大值与最小值之差判断,差值较小,则可大概判断该行在干扰线上。

public boolean isBlackLine(BufferedImage bi,int y) {
    int min = 1000000000;
    int max = -1000000000;
    for(int x = bi.getMinX(),width = bi.getWidth();x < width; ++x) {
        int pixel = bi.getRGB(x,y);
        if(pixel > max) {
            max = pixel;
        }
        if(pixel < min) {
            min = pixel;
        }
    }
    return max - min > 9000000 ? false : true;
}

3、处理,大概思路为找到干扰线后,获取到干扰线上方和下放非干扰线的首行像素点的rgb值,干扰线中的rgb值用干扰线上方值渐进到下方值代替,便可大概起到去除干扰线的效果。

下面贴出整个程序完整代码:

package test;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class PacketImage {

    private BufferedImage bufImg;

    public PacketImage(String path) {
        try {
            bufImg = ImageIO.read(new File(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void setImage(String path) {
        try {
            bufImg = ImageIO.read(new File(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public BufferedImage getCutImage(int x,int y,int w,int h) {
        return bufImg.getSubimage(x,y,w,h);
    }

    public BufferedImage getResult(int xx,int yy,int width,int height) {
        BufferedImage cutImg = getCutImage(xx, yy, width, height);
        int creY = 0;
        boolean havaBlackLine = false;
        for (int y = 0; y < height; y++) {
            if(y < height - 1 && !isBlackLine(cutImg,y) && isBlackLine(cutImg,y + 1)) {
                havaBlackLine = true;
                continue;
            }
            if(havaBlackLine) {
                creY++;
            }
            if(y == height - 1) {
                break;
            }
            if(isBlackLine(cutImg,y) && !isBlackLine(cutImg,y + 1)) {
                if(creY == 0) {
                    continue;
                }
                int startY = y - creY;
                int endY = y + 2;
                for(int x = 0;x < width;x++) {
                    int startRGB = cutImg.getRGB(x,startY);
                    int endRGB = cutImg.getRGB(x,endY);
                    int creR = (getR(endRGB) - getR(startRGB)) / creY;
                    int creG = (getG(endRGB) - getG(startRGB)) / creY;
                    int creB = (getB(endRGB) - getB(startRGB)) / creY;
                    for(int i = startY + 1,cr = 0;i < endY;i++,cr++) {
                        int subRGB = new Color(getR(startRGB) + cr * creR,
                                getG(startRGB) + cr * creG,
                                getB(startRGB) + cr * creB).getRGB();
                        cutImg.setRGB(x,i,subRGB);
                    }
                }
                havaBlackLine = false;
                creY = 0;
            }
        }
        return cutImg;
    }

    public boolean isBlackLine(BufferedImage bi,int y) {
        int min = 1000000000;
        int max = -1000000000;
        for(int x = bi.getMinX(),width = bi.getWidth();x < width; ++x) {
            int pixel = bi.getRGB(x,y);
            if(pixel > max) {
                max = pixel;
            }
            if(pixel < min) {
                min = pixel;
            }
        }
        return max - min > 9000000 ? false : true;
    }

    private int getR(int rgb) {
        return (rgb & 0xff0000) >> 16;
    }

    private int getG(int rgb) {
        return (rgb & 0xff00) >> 8;
    }

    private int getB(int rgb) {
        return rgb & 0xff;
    }

    public static void main(String[] args) {
        try {
            ImageIO.write(new PacketImage("C:\\222.PNG")
            .getResult(220,715, 280, 280), "png", new File("C:\\111.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

好了,处理后的图片获取到了,用手机扫一扫领红包吧。

不可能只领住所附近的红包吧,所以想领别的地方的红包怎么办呢?
背着电脑去,太麻烦。下篇将会在此方法的基础上开发Android版本处理,就可以带着初级出去寻宝啦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值