Extreme test generation 4 -js reverse cracking

Statement: the content of this article is only for learning and communication. It is strictly prohibited to use it for commercial purposes. Otherwise, all the consequences arising therefrom have nothing to do with the author.



1, Request process

2, Algorithmic deduction





The first verification code I passed was the extreme test. At that time, it was the third generation of the extreme test. There were not only many request processes, but also dark pits. At that time, a lot of hair was lost in order to pass the extreme test. I heard that the extreme test was going to be the fourth generation last year. I thought it would become more difficult. Unexpectedly, it was much simpler and soon succeeded in reverse.



Bag grabbing tool:



Google browser latest version


pycharm Professional Edition

1, Request process

The first step in reverse is generally process analysis. Open the packet capture tool to analyze the request process.



Encryption parameter analysis

captcha_id = fixed value

challenge locally generated (random value)

client_type = client type (fixed value)

risk_type = verification code type (fixed value)

lang language (fixed value)

callback'geetest_'+ 13 bit timestamp spliced (random value)

lot_number one of the return values of the first url of the request (random value)

pt # fixed value

w) locally generated encryption parameters (random values)

So we need to deduct the challenge generation algorithm and the w-value generation algorithm

2, Algorithmic deduction


Direct global search




There must be a lot of global searches like w, because the value of w in the third generation of polar test is in an object and expressed in ASCII coding



Hit the breakpoint, move the slider, successfully stop, and enter the analysis logic in the encryption function

It can be analyzed from the above figure:

1. Variable n obtained by function execution

2.new a constructor gets an object, takes a function in the object, executes the function, the arguments are e and n, and the result is assigned to o

3. The actual parameter of the execution function is o, the result is added with a, and the final result is the value of w

Where e is the variable r to generate the incoming object

Clear objectives:

        1. Deduct the function generating n (0, c[$_CEABJ(181)]) ()

        2. Buckle constructor_ [($_CEAAg(91))]()

        3. Function i[$_CEAAg(91)][$_CEAAg(757)] generated by deducting encryption e and n

        4. Function of withholding encryption o (0,c[$_CEAAg(139)])


It is very troublesome to deduct these functions. This js file has more than 13000 lines of code. We can copy the whole js file locally and directly call and execute these functions to be deducted. It's much simpler.



window = global
window.document = {
window.location = {
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'

Analyze the removed js code:

The functions we need are all self executing functions, and the middle note of the self executing function is function scope. Therefore, it is not feasible to call the encryption function directly, so we need to expose the encryption function in the global scope and call the encrypted number in the global scope.





In this way, the encryption function that needs to be deducted is exposed to the global, and it can be called directly in the global

Object e parameter analysis:

device_id = fixed value

ep = fixed value

geetest # fixed value

lang = fixed value

lot_number = random value (one of the return values of the first request url)

passtime = random value (time to slide the slider)

pow_msg | random value ("1 | 0 | MD5 |" + DataTime (one of the return values of the first request url) + "|" + captcha_id + "|" + lot_number + '||' + '02a05e16db61a4ac' (random 16 bit characters)

pow_sign # random value (the value of pow_msg is encrypted by md5)

set_Left = random value (distance to move slider)

Track = random value (slider track)

userresponse # random value (set_left / 0.8284266666)

wste # fixed value

Identify the gap of the slider and get the set_ For the value of left, first obtain the background image of the slider and the url address of the slider image (in the return value of the first request), request the url of the image to be saved locally, and then identify it

Identification code:

import os
import cv2
from PIL import Image

def identify_gap(bg, tp):
    bg: Background picture
    tp: Gap picture
    # Read background picture and gap picture
    bg_img = cv2.imread(bg)  # Background picture
    tp_img = cv2.imread(tp)  # Gap picture

    # Identify picture edges
    bg_edge = cv2.Canny(bg_img, 100, 200)
    tp_edge = cv2.Canny(tp_img, 100, 200)

    # Convert picture format
    bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)
    tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB)

    # Notch matching
    res = cv2.matchTemplate(bg_pic, tp_pic, cv2.TM_CCOEFF_NORMED)
    # Find the best match
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    # Coordinates of the upper left corner
    tl = max_loc
    # Returns the X coordinate of the notch
    return tl[0]

if __name__ == "__main__":
    # Receive two parameters
    # The first is the background picture address
    # The second is the address of the gap picture


Generation of sliding track (track value):

# -*- coding: utf-8 -*-
import random

def __ease_out_expo(x):
    if x == 1:
        return 1
        return 1 - pow(2, -10 * x)

def __ease_out_quart(x):
    return 1 - pow(1 - x, 4)

def get_slide_track(distance):
    Generate sliding track according to sliding distance
    :param distance: Distance to slide
    :return: Sliding track<type 'list'>: [[x,y,t], ...]
        x: Lateral distance slid
        y: Longitudinal distance slid, Except the starting point, All 0
        t: Time consumed in sliding process, Company: millisecond

    if not isinstance(distance, int) or distance < 0:
        raise ValueError(f"distance Type must be an integer greater than or equal to 0: distance: {distance}, type: {type(distance)}")
    # Initialize track list
    slide_track = [
        [random.randint(20, 60), random.randint(10, 40), 0]
    # A total of count slider position information is recorded
    count = 30 + int(distance / 2)
    # Initialization slip time
    t = random.randint(50, 100)
    # Record the last sliding distance
    _x = 0
    _y = 0
    for i in range(count):
        # Lateral distance slid
        x = round(__ease_out_expo(i / count) * distance)
        # Time consumed in sliding process
        t = random.randint(10, 20)
        if x == _x:
        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):

This track is also found in csdn. The blogger is called fish with tears

Verify whether it can pass and pass successfully



The fourth generation of extreme experience is relatively simple, mainly ideas and methods. If there is anything wrong, you are welcome to give advice and exchange.

Tags: Python crawler Javascript

Posted by Sephiriz on Fri, 15 Apr 2022 02:46:36 +0930