验证码破解:极验3.0滑动验证码

验证码破解:极验3.0滑动验证码破解最新俩种方法

 

特点: 对于极验验证码3.0版本,我们首先点击按钮进行智能验证。如果验证不通过,则会弹出滑动的验证的窗口,拖动滑块拼合图像进行验证。之后三个加密参数会生成,通过表单提交到后台,后台还会进行一次验证。

极滑2.0的破解思路:

  1. 模拟点击验证按钮
    直接用Selenium模拟点击按钮
  2. 识别滑动缺口的位置
    利用原图和缺口图对比检测方式来识别缺口的位置,通过遍历俩张图片,找出相同位置像素RGB差距超过此阀值的像素点,那么此像素点的位置就是缺口的位置。
  3. 模拟拖动滑块
    模拟人的移动轨迹通过验证,一般是先加速后减速。

破解的重要点就是:识别滑动缺口的位置。
但是极滑3.0进行了更新,我们点击按钮进行智能验证,然后截图,但是获取到的不再是完整的原图,而是带有缺口的原图,这样子,我们就不能使用极滑2.0的办法来获取到滑动缺口的位置,需要另想获取滑动缺口的位置,下面有分别俩个办法来获取极滑3.0的缺口位置:


方法一、通过超级鹰平台(本博客将以该方法为测试案例)

  1. 通过超级鹰验证码破解平台,我们先截图获取带有缺口的验证码图片,然后再在图片上加上”请点击凹槽左上交“ 这几个打字,然后通过接口发送超级鹰验证平台,他们就会返回给我们凹槽的左上角位置
    获取得到的验证码:
    在这里插入图片描述
    需要添加上”请点击凹槽左上角“,超级鹰才能知道是识别滑动缺口图片的凹槽位置
    在这里插入图片描述
    超级鹰返回的结果为字典类型,其中键"pic_str"的值为结果坐标(60, 52):
    在这里插入图片描述
    图片凹槽的左上角的真实位置为(58,53):
    在这里插入图片描述

方法二、不断截图

通过滑动小块按钮,从左边到右边,然后不断保存滑动过的轨迹和截图到的照片到字典中,通过照片分析,找到其中没有凹槽的图片,也就是将滑块移动到符合位置的轨迹,至于怎么在那么多截图中找到最合适的那种找完美的图片,这个就需要图片处理的算法,这个下次再弄,这次尝试了方法一。


方法一代码:chaojiying.py 、geetest_spider.py

chaojiying.py: 需要使用到超级鹰平台,读者可以看我上一篇博客,有讲到如何注册使用,在geetest_spider.py中需要用到超级鹰的账号、密码、软件ID,这个模块就无要更改

import requests
from hashlib import md5


class Chaojiying_Client(object):

    def __init__(self, username, password, soft_id):
        self.username = username
        self.password = md5(password.encode("utf-8")).hexdigest()
        self.soft_id = soft_id
        self.base_params = {
            'user': self.username,
            'pass2': self.password,
            'softid': self.soft_id,
        }
        self.headers = {
            'Connection': 'Keep-Alive',
            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
        }

    def PostPic(self, im, codetype):
        """
        im: 图片字节
        codetype: 题目类型 参考 http://www.chaojiying.com/price.html
        """
        params = {
            'codetype': codetype,
        }
        params.update(self.base_params)
        files = {'userfile': ('ccc.jpg', im)}
        r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
        return r.json()

    def ReportError(self, im_id):
        """
        im_id:报错题目的图片ID
        """
        params = {
            'id': im_id,
        }
        params.update(self.base_params)
        r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
        return r.json()


if __name__ == '__main__':
	# todo:用户中心>>软件ID 生成一个替换 96001
    chaojiying = Chaojiying_Client('超级鹰账号', '密码', '软件ID')
    # todo:  本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
    im = open('target.png', 'rb').read()	
    # todo:  9101 验证码类型, 滑动验证码就不需要更改  											
    result = chaojiying.PostPic(im, 9101)
    print(result)

geetest_spider.py:需要修改CrackGeetest类中的get_gap()方法中的超级鹰账号、密码以及软件ID

import time
from io import BytesIO
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from chaogjiying import Chaojiying_Client
from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw

EMAIL = 'cqc@cuiqingcai.com'
PASSWORD = '123456'
BORDER_1 = 8
BORDER_2 = 15
BORDER_3 = 28


class CrackGeetest(object):

    def __init__(self):
        self.url = 'https://account.geetest.com/login'
        self.browser = webdriver.Chrome()
        self.browser.maximize_window()
        self.wait = WebDriverWait(self.browser, 5)
        self.email = EMAIL
        self.password = PASSWORD
        self.success = False
        self.try_num = 3
        self.now_num = 3
        self.flesh_num = 1

    def __del__(self):
        self.browser.close()

    def get_geetest_button(self):
        """
        获取初始验证按钮
        :return: 初始化验证按钮
        """
        button = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_radar_tip')))
        return button

    def get_position(self):
        """
        获取验证码位置
        :return: 验证码位置元组
        """
        img = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'geetest_canvas_img')))
        time.sleep(0.5)
        location = img.location
        size = img.size
        top, bottom, left, right = location['y'], location['y'] + size['height'], location['x'], location['x'] + size[
            'width']
        return top, bottom, left, right

    def get_screenshot(self):
        """
        获取网页截图
        :return: 截图对象
        """
        screenshot = self.browser.get_screenshot_as_png()
        screenshot = Image.open(BytesIO(screenshot))
        return screenshot

    def get_slider(self):
        """
        获取滑块
        :return: 滑块对象
        """
        try:
            slider = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME, 'geetest_slider_button')))
        except Exception:
            self.crack()
            return 
        return slider

    def get_geetest_image(self, name='captcha.png'):
        """
        获取验证码图片
        :return: 图片对象
        """
        top, bottom, left, right = self.get_position()
        screenshot = self.get_screenshot()
        captcha = screenshot.crop((left, top, right, bottom))
        captcha.save(name)
        return captcha

    def open(self):
        """
        打开网页输入用户名密码
        :return: None
        """
        self.browser.get(self.url)
        time.sleep(0.5)
        email = self.browser.find_elements_by_xpath("//i[@class='icon-email']/../../input")[0]
        password = self.browser.find_element_by_xpath("//i[@class='icon-password']/../../input")
        email.send_keys(self.email)
        password.send_keys(self.password)

    @staticmethod
    def get_track(distance):
        """
        根据偏移量获取移动轨迹
        :param distance: 偏移量
        :return: 移动轨迹
        """
        # 移动轨迹
        track = []
        # 当前位移
        current = 0
        # 减速阈值
        mid = distance * 4 / 5
        # 计算间隔
        t = 0.2
        # 初速度
        v = 0

        while current < distance:
            if current < mid:
                # 加速度为正2
                a = 2
            else:
                # 加速度为负3
                a = -3
            # 初速度v0
            v0 = v
            # 当前速度v = v0 + at
            v = v0 + a * t
            # 移动距离x = v0t + 1/2 * a * t^2
            move = v0 * t + 1 / 2 * a * t * t
            # 当前位移
            current += move
            # 加入轨迹
            track.append(round(move))
        return track

    def move_to_gap(self, slider, track):
        """
        拖动滑块到缺口处
        :param slider: 滑块
        :param track: 轨迹
        :return:
        """
        ActionChains(self.browser).click_and_hold(slider).perform()
        for x in track:
            ActionChains(self.browser).move_by_offset(xoffset=x, yoffset=0).perform()
        time.sleep(0.5)
        ActionChains(self.browser).release().perform()

    @staticmethod
    def get_gap():
        """
        通过超级鹰获取缺口位置
        :return: 缺口距离
        """
        # todo:用户中心>>软件ID 生成一个替换 96001
	    chaojiying = Chaojiying_Client('超级鹰账号', '密码', '软件ID')
	    # todo:  本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
	    im = open('target.png', 'rb').read()	
	    # todo:  9101 验证码类型, 滑动验证码就不需要更改  											
	    result = chaojiying.PostPic(im, 9101)
        gap = int(result.get("pic_str").split(",")[0])
        return gap
		
	# 超级赢验证失败,反馈回去,将不扣钱
    @staticmethod
    def fail_to_chaojiying():
        """
        超级赢验证失败,反馈回去,将不扣钱
        :return: None
        """
        # todo:用户中心>>软件ID 生成一个替换 96001
	    chaojiying = Chaojiying_Client('超级鹰账号', '密码', '软件ID')
	    # todo:  本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
	    im = open('target.png', 'rb').read()
        result = chaojiying.ReportError(im)
	
    @staticmethod
    def add_text_to_image():
        """
        给截取的带缺口的图片添加“请点击凹槽左上角"
        :return: None
        """
        # 设置字体样式
        font = ImageFont.truetype("/usr/share/fonts/蓝杰ios加粗.ttf", 32)

        # 打开底版图片
        imageFile = "captcha.png"
        im1 = Image.open(imageFile)

        # 在图片上添加文字 "请点击凹槽左上角"
        add_text = "请点击凹槽左上角"
        draw = ImageDraw.Draw(im1)
        draw.text((2, 120), add_text, "#FF0000", font=font)

        # 保存
        im1.save("target.png")

    def crack(self):
        # 输入用户名密码
        self.open()

        # 点击验证按钮
        time.sleep(1)
        button = self.get_geetest_button()
        button.click()

        # BOREDER有俩种情况,一种是8,一种是15, 还有一种是28
        def slider_try(gap, BORDER):
            if self.now_num:
                # 减去缺口位置
                gap -= BORDER
                # 计算滑动距离
                track = self.get_track(int(gap))

                # 拖动滑块
                slider = self.get_slider()
                self.move_to_gap(slider, track)
                try:
                    self.success = self.wait.until(
                        EC.text_to_be_present_in_element((By.CLASS_NAME, 'geetest_success_radar_tip_content'), '验证成功'))
                except Exception as e:
                    self.now_num -= 1
                    test_num = self.try_num - self.now_num
                    if self.now_num == 0:
                        print("第%d次尝试失败, 验证失败" % test_num)
                    else:
                        print("验证失败,正在进行第%d次尝试" % test_num)

        while not self.success and self.now_num > 0:

            # 获取验证码图片
            try:
                self.get_geetest_image()
            except Exception as e:
                # todo: 其他验证,或者是自动识别通过
                self.success = True
                print("自动识别通过或者验证非滑动验证码,无需滑动%s" % e)
                time.sleep(5)
                return

            # 给验证码加文字
            self.add_text_to_image()

            # 获取缺口位置
            gap = self.get_gap()
            print("缺口位置gap为",gap)

            # 第一中请求,gap减少7
            slider_try(gap, BORDER_1)
            # 成功后退出
            if not self.success:
                # 尝试gap减少14
                slider_try(gap, BORDER_2)
                if not self.success:
                    slider_try(gap, BORDER_3)
                    self.fail_to_chaojiying()
            if self.success:
                test_num = self.try_num - self.now_num + 1
                print("第{}次刷新,第{}次尝试,验证通过".format(self.flesh_num, test_num))
                time.sleep(5)
                self.success = True

        if not self.success:
            print("重新刷新页面,这是第%d次刷新" % self.flesh_num)
            self.flesh_num += 1
            self.now_num = 3
            self.try_num = 3
            self.crack()


if __name__ == '__main__':
    crack = CrackGeetest()
    crack.crack()
    del crack

测试数据:

次数验证何时通过(每次刷新尝试最多3次机会)
1第1次刷新,第1次尝试,验证通过
2第2次刷新,第3次尝试,验证通过
3第1次刷新,第2次尝试,验证通过
4第1次刷新,第1次尝试,验证通过
5第8次刷新,第1次尝试,验证通过过
6第1次刷新,第3次尝试,验证通过

该验证的通过率,取决于超级鹰平台的返回的坐标,不过从结果可以看出来,基本都是要识别好几次,才可以成功,这个算法有点不行,可以通过celery异步让他处理,结果会更好,如果有机会,还不如自己写个识别图片凹槽的算法,感觉不会特别难

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
3.0滑动拼图验证是一种常用的人机验证方式,可以有效防止机器恶意攻击,保障网站安全。在Java中,可以通过调用的API来实现滑动验证功能。下面是一个简单的使用示例: 1. 在官网申请账号,并创建一个验证项目,获得验证ID和密钥。 2. 下载的Java SDK,解压后将其中的geetest-lib.jar文件添加到项目的classpath中。 3. 在Java代码中调用API实现验证功能,示例代码如下: ```java import com.geetest.sdk.GTConfig; import com.geetest.sdk.GeetestLib; public class GeetestVerify { private static final String GEETEST_ID = "your_geetest_id"; // 验证ID private static final String GEETEST_KEY = "your_geetest_key"; // 验证密钥 public static boolean verify(String challenge, String validate, String seccode) { GeetestLib gtSdk = new GeetestLib(GEETEST_ID, GEETEST_KEY); GTConfig config = new GTConfig(); config.setCaptchaId(GEETEST_ID); config.setPrivateKey(GEETEST_KEY); gtSdk.setConfig(config); // 自定义参数,可选择添加 // Map<String, String> paramMap = new HashMap<>(); // paramMap.put("user_id", "your_user_id"); // paramMap.put("client_type", "web"); // paramMap.put("ip_address", "127.0.0.1"); // 调用验证接口 int result = gtSdk.enhencedValidateRequest(challenge, validate, seccode, null); // 验证结果,0表示成功,1表示失败 return result == 0; } } ``` 4. 在前端页面中嵌入验证组件,具体实现方式可参考官网提供的相关文档和示例代码。在用户完成验证后,将验证结果传递给后台Java程序进行验证,通过调用上述示例代码实现验证功能即可。 总的来说,Java实现滑动验证相对较为简单,只需要调用提供的Java SDK即可。需要注意的是,官网提供的Java SDK版本可能会更新,需要及时更新SDK文件以保证验证功能的正常运作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值