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.
catalogue
preface
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.
Environment:
window10
Bag grabbing tool:
Fiddler
Browser:
Google browser latest version
IDE:
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
1.challenge
Direct global search
2.w
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 = { 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' }
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 identify_gap('bg_image.png','slide_image.png')
Generation of sliding track (track value):
# -*- 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): """ 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: 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)
This track is also found in csdn. The blogger is called fish with tears
Verify whether it can pass and pass successfully
summary
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.