声明:本文内容仅供学习交流,严禁用于商业用途,否则由此产生的一切后果均与作者无关。
目录
前言
我过的第一个验证码就是极验,当时是极验三代,不仅请求流程多,还有暗坑,当时为了过极验头发都掉了不少,去年就听说极验要出四代了,我以为会变得更难,没想到简单了不少,很快就逆向成功了。
环境:
window10
抓包工具:
Fiddler
浏览器:
谷歌浏览器最新版本
IDE:
                pycharm专业版
  
一、请求流程
逆向第一步一般都是流程分析,打开抓包工具,分析请求流程。
    
二、算法扣取
1.challenge
直接全局搜索


2.w
像w这种全局搜索肯定是很多的,因为极验三代中w的值在一个对象中,并以ASCII编码的形式表示

         
 
 
打上断点,移动滑块,成功断住,进入加密函数中分析逻辑

从上图可以分析出:
1. 函数执行 得到变量n
2.new 一个构造函数得到一个对象,取对象中一个函数,执行函数,实参为e和n,得到结果赋值给o
3.执行函数实参为o,得到的结果与a相加,最后的结果便为w的值
其中e为变量r生成传入的对象
明确目标:
1.扣取生成n的函数 (0, c[$_CEABJ(181)])()
2.扣取构造函数 _[($_CEAAg(91))]()
3.扣取加密e和n生成o得函数 i[$_CEAAg(91)][$_CEAAg(757)]
4.扣取加密o的函数 (0,c[$_CEAAg(139)])
扣取这些函数非常麻烦,这个js文件有13000多行代码,我们可以将整个js文件复制到本地,将要扣取的这几个函数直接调用执行。这样就简单很多了。
 
window = global
window.document = {
    body:{},
    head:{},
}
window.location = {
    protocol:'https:',
}
window.navigator = {
    userAgent:'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.1885.120 Safari/537.36'
}分析扣取下来的js代码:
我们所需要的函数都在自执行函数中,自执行函数的的作用域为函数作用域,所以直接调用加密函数行不通,所以我们需要将加密函数暴露在全局作用域中,在全局作用域中调用加密函数。
 

 
 
 


这样就将需要扣取加密函数暴露给全局了,直接在全局调用

识别滑块缺口得到set_Left的值,首先获取滑块的背景图和滑块图的url地址(在第一次请求返回值中),请求图片的url本地保存然后识别
识别代码:
import os
import cv2
from PIL import Image
def identify_gap(bg, tp):
    '''
    bg: 背景图片
    tp: 缺口图片
    '''
    # 读取背景图片和缺口图片
    bg_img = cv2.imread(bg)  # 背景图片
    tp_img = cv2.imread(tp)  # 缺口图片
    # 识别图片边缘
    bg_edge = cv2.Canny(bg_img, 100, 200)
    tp_edge = cv2.Canny(tp_img, 100, 200)
    # 转换图片格式
    bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)
    tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB)
    # 缺口匹配
    res = cv2.matchTemplate(bg_pic, tp_pic, cv2.TM_CCOEFF_NORMED)
    # 寻找最优匹配
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    # 左上角点的坐标
    tl = max_loc
    # 返回缺口的X坐标
    return tl[0]
if __name__ == "__main__":
    # 接收两个参数
    # 第一个为背景图片地址
    # 第二个为缺口图片地址
    identify_gap('bg_image.png','slide_image.png')
滑动轨迹(track值)生成:
# -*- coding: utf-8 -*-
import random
def __ease_out_expo(x):
    if x == 1:
        return 1
    else:
        return 1 - pow(2, -10 * x)
def __ease_out_quart(x):
    return 1 - pow(1 - x, 4)
def get_slide_track(distance):
    """
    根据滑动距离生成滑动轨迹
    :param distance: 需要滑动的距离
    :return: 滑动轨迹<type 'list'>: [[x,y,t], ...]
        x: 已滑动的横向距离
        y: 已滑动的纵向距离, 除起点外, 均为0
        t: 滑动过程消耗的时间, 单位: 毫秒
    """
    if not isinstance(distance, int) or distance < 0:
        raise ValueError(f"distance类型必须是大于等于0的整数: distance: {distance}, type: {type(distance)}")
    # 初始化轨迹列表
    slide_track = [
        [random.randint(20, 60), random.randint(10, 40), 0]
    ]
    # 共记录count次滑块位置信息
    count = 30 + int(distance / 2)
    # 初始化滑动时间
    t = random.randint(50, 100)
    # 记录上一次滑动的距离
    _x = 0
    _y = 0
    for i in range(count):
        # 已滑动的横向距离
        x = round(__ease_out_expo(i / count) * distance)
        # 滑动过程消耗的时间
        t = random.randint(10, 20)
        if x == _x:
            continue
        slide_track.append([x - _x, _y, t])
        _x = x
    slide_track.append([0, 0, random.randint(200, 300)])
    return slide_track
if __name__ == '__main__':
    s = []
    for _ in get_slide_track(105):
        s.append(_)
    print(s)
这份轨迹也是在csdn找到的,博主叫做带泪的鱼
验证一下是否能通过,成功通过

总结
极验四代相对来说还是比较简单的,主要是思路和方法,如果有哪里写的不对,欢迎大佬指点交流。










