style: 统一 Ruff 代码格式

This commit is contained in:
yml2213
2026-08-30 21:04:52 +08:00
parent c891ac982e
commit 47e19ed7b2
90 changed files with 5574 additions and 2350 deletions
+193 -52
View File
@@ -4,46 +4,78 @@ from typing import Any
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5, AES
# 随机产生4个字符组成的字符串
def four_random_chart() -> str:
return hex(int(65536 * (1 + random.random())))[2:][1:]
# PKCS#1 v1.5 填充 + RSA 加密
def parse_jsbn_bigint(n_obj:dict[Any, int]) -> int:
def parse_jsbn_bigint(n_obj: dict[Any, int]) -> int:
DB = 28
DV = 1 << DB
t = n_obj['t']
t = n_obj["t"]
result = 0
for i in range(t):
result += n_obj[i] * (DV ** i)
result += n_obj[i] * (DV**i)
return result
def encrypt_data(plaintext:str) -> str:
def encrypt_data(plaintext: str) -> str:
cipher = PKCS1_v1_5.new(public_key)
encrypted = cipher.encrypt(plaintext.encode('utf-8'))
encrypted = cipher.encrypt(plaintext.encode("utf-8"))
# 转换为十六进制,确保偶数长度
hex_result = encrypted.hex()
if len(hex_result) % 2 == 1:
hex_result = '0' + hex_result
hex_result = "0" + hex_result
return hex_result
def RSA_jiami_r(str_16:str) -> str:
def RSA_jiami_r(str_16: str) -> str:
global public_key
# 你的数据
n_data = {
0: 134982529, 1: 254232810, 2: 164556709, 3: 234907349,
4: 134685994, 5: 35463984, 6: 258277946, 7: 12518857,
8: 44638621, 9: 93783641, 10: 212253739, 11: 62792472,
12: 186688352, 13: 109500232, 14: 182488077, 15: 261196188,
16: 26354094, 17: 103248217, 18: 106891695, 19: 165771045,
20: 41530993, 21: 263704736, 22: 111785174, 23: 12753611,
24: 232116673, 25: 155524985, 26: 218291229, 27: 122452343,
28: 248250238, 29: 118739550, 30: 251169095, 31: 129059733,
32: 149835464, 33: 5498868, 34: 71719731, 35: 154456417,
0: 134982529,
1: 254232810,
2: 164556709,
3: 234907349,
4: 134685994,
5: 35463984,
6: 258277946,
7: 12518857,
8: 44638621,
9: 93783641,
10: 212253739,
11: 62792472,
12: 186688352,
13: 109500232,
14: 182488077,
15: 261196188,
16: 26354094,
17: 103248217,
18: 106891695,
19: 165771045,
20: 41530993,
21: 263704736,
22: 111785174,
23: 12753611,
24: 232116673,
25: 155524985,
26: 218291229,
27: 122452343,
28: 248250238,
29: 118739550,
30: 251169095,
31: 129059733,
32: 149835464,
33: 5498868,
34: 71719731,
35: 154456417,
36: 49635,
't': 37, 's': 0
"t": 37,
"s": 0,
}
e = 65537
@@ -54,11 +86,12 @@ def RSA_jiami_r(str_16:str) -> str:
encrypted = encrypt_data(str_16)
return encrypted
# AES加密
# 加密模式: AES-CBC
# 密钥长度: 128位
# IV: 固定为 "0000000000000000"
def parse_string_to_wordarray(text:str) -> list[int]:
def parse_string_to_wordarray(text: str) -> list[int]:
"""将字符串转换为 WordArray 格式"""
length = len(text)
words = []
@@ -81,13 +114,15 @@ def parse_string_to_wordarray(text:str) -> list[int]:
words[word_index] |= char_code << shift
return words
def AES_O(plaintext:str, str_16:str) -> list[int]:
def AES_O(plaintext: str, str_16: str) -> list[int]:
# 密钥
key_words = parse_string_to_wordarray(str_16)
key = b''.join(w.to_bytes(4, 'big') for w in key_words)
key = b"".join(w.to_bytes(4, "big") for w in key_words)
# IV
iv = b'0000' * 4 # "0000000000000000"
iv = b"0000" * 4 # "0000000000000000"
# 填充(PKCS7)
pad_len = 16 - len(plaintext) % 16
@@ -100,13 +135,14 @@ def AES_O(plaintext:str, str_16:str) -> list[int]:
# 结果是字节数组
return list(ciphertext)
# 自定义base64编码
def geetest_base64_encode(data:list[int]) -> dict[str, Any]:
def geetest_base64_encode(data: list[int]) -> dict[str, Any]:
"""极验自定义Base64编码"""
# 配置
charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()'
pad_char = '.'
charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()"
pad_char = "."
# 位掩码 (这些是打乱的)
masks = [7274496, 9483264, 19220, 235]
@@ -159,13 +195,10 @@ def geetest_base64_encode(data:list[int]) -> dict[str, Any]:
break
return {
"res": encoded,
"end": padding
}
return {"res": encoded, "end": padding}
def encrypt_string(e:str, t:list[int], n:str) -> str:
def encrypt_string(e: str, t: list[int], n: str) -> str:
"""
JS加密函数的Python实现
@@ -185,7 +218,7 @@ def encrypt_string(e:str, t:list[int], n:str) -> str:
# 每次读取2个字符(十六进制)
while o < len(n):
r = n[o:o + 2] # 取2个字符
r = n[o : o + 2] # 取2个字符
if len(r) < 2:
break
o += 2
@@ -205,7 +238,7 @@ def encrypt_string(e:str, t:list[int], n:str) -> str:
return i
def simple_md5(message:str) -> str:
def simple_md5(message: str) -> str:
"""
简化版MD5实现,结构更清晰
"""
@@ -216,31 +249,139 @@ def simple_md5(message:str) -> str:
# 轮移位常量
shifts = [
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
7,
12,
17,
22,
7,
12,
17,
22,
7,
12,
17,
22,
7,
12,
17,
22,
5,
9,
14,
20,
5,
9,
14,
20,
5,
9,
14,
20,
5,
9,
14,
20,
4,
11,
16,
23,
4,
11,
16,
23,
4,
11,
16,
23,
4,
11,
16,
23,
6,
10,
15,
21,
6,
10,
15,
21,
6,
10,
15,
21,
6,
10,
15,
21,
]
# K常数(与JavaScript版本中的常数对应)
K = [
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
0xD76AA478,
0xE8C7B756,
0x242070DB,
0xC1BDCEEE,
0xF57C0FAF,
0x4787C62A,
0xA8304613,
0xFD469501,
0x698098D8,
0x8B44F7AF,
0xFFFF5BB1,
0x895CD7BE,
0x6B901122,
0xFD987193,
0xA679438E,
0x49B40821,
0xF61E2562,
0xC040B340,
0x265E5A51,
0xE9B6C7AA,
0xD62F105D,
0x02441453,
0xD8A1E681,
0xE7D3FBC8,
0x21E1CDE6,
0xC33707D6,
0xF4D50D87,
0x455A14ED,
0xA9E3E905,
0xFCEFA3F8,
0x676F02D9,
0x8D2A4C8A,
0xFFFA3942,
0x8771F681,
0x6D9D6122,
0xFDE5380C,
0xA4BEEA44,
0x4BDECFA9,
0xF6BB4B60,
0xBEBFBC70,
0x289B7EC6,
0xEAA127FA,
0xD4EF3085,
0x04881D05,
0xD9D4D039,
0xE6DB99E5,
0x1FA27CF8,
0xC4AC5665,
0xF4292244,
0x432AFF97,
0xAB9423A7,
0xFC93A039,
0x655B59C3,
0x8F0CCC92,
0xFFEFF47D,
0x85845DD1,
0x6FA87E4F,
0xFE2CE6E0,
0xA3014314,
0x4E0811A1,
0xF7537E82,
0xBD3AF235,
0x2AD7D2BB,
0xEB86D391,
]
# 实际实现...
return verify_result(message)
return verify_result(message)
+60 -8
View File
@@ -11,6 +11,7 @@ REQUEST_TIMEOUT = (3.05, 12)
def pilImgToCv2(img: Image.Image, flag=cv2.COLOR_RGB2BGR):
return cv2.cvtColor(np.asarray(img), flag)
# 识别图片缺口返回滑块距离
def shibie(img: Image.Image, slice: Image.Image):
# 通过 pilImgToCv2 将图片置灰
@@ -38,20 +39,70 @@ def shibie(img: Image.Image, slice: Image.Image):
# showImg(resultBg) # 可以通过它来看处理后的图片效果
return distance
# 还原图片
def restore_geetest_image(input_path:str, output_path:str) -> None:
def restore_geetest_image(input_path: str, output_path: str) -> None:
"""
还原极验打乱的验证码图像
"""
Ut = [
39, 38, 48, 49, 41, 40, 46, 47, 35, 34, 50, 51, 33, 32, 28, 29,
27, 26, 36, 37, 31, 30, 44, 45, 43, 42, 12, 13, 23, 22, 14, 15,
21, 20, 8, 9, 25, 24, 6, 7, 3, 2, 0, 1, 11, 10, 4, 5, 19, 18, 16, 17
39,
38,
48,
49,
41,
40,
46,
47,
35,
34,
50,
51,
33,
32,
28,
29,
27,
26,
36,
37,
31,
30,
44,
45,
43,
42,
12,
13,
23,
22,
14,
15,
21,
20,
8,
9,
25,
24,
6,
7,
3,
2,
0,
1,
11,
10,
4,
5,
19,
18,
16,
17,
]
# 打开混淆图像
img = Image.open(input_path)
new_img = Image.new("RGB", (260,160))
new_img = Image.new("RGB", (260, 160))
r = 160
for _ in range(len(Ut)):
a = r / 2
@@ -63,11 +114,12 @@ def restore_geetest_image(input_path:str, output_path:str) -> None:
new_img.save(output_path)
logger.debug("图像已还原并保存到: {}", output_path)
# 下载图片
def download_picture(bg:str, fullbg:str, slice:str) -> int:
def download_picture(bg: str, fullbg: str, slice: str) -> int:
for i in range(3):
if i == 0:
url = "https://static.geetest.com/"+bg
url = "https://static.geetest.com/" + bg
response = requests.get(url, timeout=REQUEST_TIMEOUT)
response.raise_for_status()
with open("bg.jpg", "wb") as f:
@@ -87,4 +139,4 @@ def download_picture(bg:str, fullbg:str, slice:str) -> int:
response.raise_for_status()
with open("slice.jpg", "wb") as f:
f.write(response.content)
return shibie(Image.open('fullbg.jpg'), Image.open('slice.jpg'))
return shibie(Image.open("fullbg.jpg"), Image.open("slice.jpg"))
+173 -143
View File
@@ -29,13 +29,15 @@ def _get(
def _parse_jsonp_response(response: requests.Response, source: str) -> dict:
"""解析极验 JSONP 响应。"""
response.raise_for_status()
match = re.search(r'\((.*)\)$', response.text)
match = re.search(r"\((.*)\)$", response.text)
if not match:
raise ValueError(f"{source} 无法解析 JSONP 响应")
data = json.loads(match.group(1))
if data.get('status') == 'error':
raise ValueError(f"{source} 失败: {data.get('user_error', data.get('error', '未知错误'))}")
if data.get("status") == "error":
raise ValueError(
f"{source} 失败: {data.get('user_error', data.get('error', '未知错误'))}"
)
return data
@@ -55,26 +57,26 @@ def _parse_json_response(response: requests.Response, source: str) -> dict:
def get_challenge_gt_bak() -> Tuple[str, str]:
headers = {
'accept': 'application/json, text/javascript, */*; q=0.01',
'accept-language': 'zh-CN,zh;q=0.9',
'priority': 'u=1, i',
'referer': 'https://demos.geetest.com/slide-float.html',
'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
'x-requested-with': 'XMLHttpRequest',
"accept": "application/json, text/javascript, */*; q=0.01",
"accept-language": "zh-CN,zh;q=0.9",
"priority": "u=1, i",
"referer": "https://demos.geetest.com/slide-float.html",
"sec-ch-ua": '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
"x-requested-with": "XMLHttpRequest",
}
params = {
't': str(int(round(time.time() * 1000))),
"t": str(int(round(time.time() * 1000))),
}
response = requests.get(
'https://demos.geetest.com/gt/register-slide',
"https://demos.geetest.com/gt/register-slide",
params=params,
headers=headers,
timeout=10,
@@ -85,21 +87,21 @@ def get_challenge_gt_bak() -> Tuple[str, str]:
def get_challenge_gt() -> Tuple[str, str]:
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36',
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Content-Type': 'application/x-www-form-urlencoded',
'referer': 'https://passport.douyu.com/member/login?state=https%3A%2F%2Fwww.douyu.com%2Fmember%2FcpSecurity%2Fcheck_geetest_status',
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
"Accept": "application/json, text/javascript, */*; q=0.01",
"Content-Type": "application/x-www-form-urlencoded",
"referer": "https://passport.douyu.com/member/login?state=https%3A%2F%2Fwww.douyu.com%2Fmember%2FcpSecurity%2Fcheck_geetest_status",
}
data = {
'type': '1',
'nicknameOrPhoneEncrypt': '03ILaBwtmmCm0A==',
'password': '57219dddec71c31b7647683fa5306103',
'biz_type': '1',
"type": "1",
"nicknameOrPhoneEncrypt": "03ILaBwtmmCm0A==",
"password": "57219dddec71c31b7647683fa5306103",
"biz_type": "1",
}
response = requests.post(
'https://passport.douyu.com/wgapi/member/passport/login',
"https://passport.douyu.com/wgapi/member/passport/login",
headers=headers,
data=data,
timeout=10,
@@ -114,28 +116,27 @@ def get_challenge_gt() -> Tuple[str, str]:
raise ValueError(f"斗鱼登录接口返回中缺少极验参数: {preview}") from exc
def get_js_address(gt: str, proxies: Optional[Mapping[str, str]] = None) -> dict:
headers = {
'accept': '*/*',
'accept-language': 'zh-CN,zh;q=0.9',
'referer': PASSPORT_REFERER,
'sec-ch-ua': '"Google Chrome";v="149", "Chromium";v="149", "Not)A;Brand";v="24"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"macOS"',
'sec-fetch-dest': 'script',
'sec-fetch-mode': 'no-cors',
'sec-fetch-site': 'cross-site',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36',
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9",
"referer": PASSPORT_REFERER,
"sec-ch-ua": '"Google Chrome";v="149", "Chromium";v="149", "Not)A;Brand";v="24"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"macOS"',
"sec-fetch-dest": "script",
"sec-fetch-mode": "no-cors",
"sec-fetch-site": "cross-site",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36",
}
params = {
'gt': gt,
'callback': 'geetest_' + str(int(round(time.time() * 1000))),
"gt": gt,
"callback": "geetest_" + str(int(round(time.time() * 1000))),
}
response = _get(
'https://api.geetest.com/gettype.php',
"https://api.geetest.com/gettype.php",
params=params,
headers=headers,
proxies=proxies,
@@ -143,6 +144,7 @@ def get_js_address(gt: str, proxies: Optional[Mapping[str, str]] = None) -> dict
return _parse_jsonp_response(response, "极验 gettype")
def get_c_s(
gt: str,
challenge: str,
@@ -150,26 +152,32 @@ def get_c_s(
proxies: Optional[Mapping[str, str]] = None,
) -> Tuple[list[int], str]:
headers = {
'accept': '*/*',
'accept-language': 'zh-CN,zh;q=0.9',
'referer': PASSPORT_REFERER,
'sec-ch-ua': '"Google Chrome";v="149", "Chromium";v="149", "Not)A;Brand";v="24"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"macOS"',
'sec-fetch-dest': 'script',
'sec-fetch-mode': 'no-cors',
'sec-fetch-site': 'cross-site',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36',
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9",
"referer": PASSPORT_REFERER,
"sec-ch-ua": '"Google Chrome";v="149", "Chromium";v="149", "Not)A;Brand";v="24"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"macOS"',
"sec-fetch-dest": "script",
"sec-fetch-mode": "no-cors",
"sec-fetch-site": "cross-site",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36",
}
response = _get(
'https://api.geetest.com/get.php?gt=' + gt + '&challenge=' + challenge + '&lang=zh-cn&pt=0&client_type=web&w=' + w + '&callback=geetest_' + str(
int(round(time.time() * 1000))),
"https://api.geetest.com/get.php?gt="
+ gt
+ "&challenge="
+ challenge
+ "&lang=zh-cn&pt=0&client_type=web&w="
+ w
+ "&callback=geetest_"
+ str(int(round(time.time() * 1000))),
headers=headers,
proxies=proxies,
)
data = _parse_jsonp_response(response, "极验 get.php")
return data['data']['c'], data['data']['s']
return data["data"]["c"], data["data"]["s"]
def req_fullpage_validate(
@@ -180,159 +188,181 @@ def req_fullpage_validate(
) -> dict:
"""HAR 中的 fullpage 最终校验,成功后直接返回 validate。"""
headers = {
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Referer': PASSPORT_REFERER,
'Sec-Fetch-Dest': 'script',
'Sec-Fetch-Mode': 'no-cors',
'Sec-Fetch-Site': 'cross-site',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36',
'sec-ch-ua': '"Google Chrome";v="149", "Chromium";v="149", "Not)A;Brand";v="24"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"macOS"',
"Accept": "*/*",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "keep-alive",
"Referer": PASSPORT_REFERER,
"Sec-Fetch-Dest": "script",
"Sec-Fetch-Mode": "no-cors",
"Sec-Fetch-Site": "cross-site",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36",
"sec-ch-ua": '"Google Chrome";v="149", "Chromium";v="149", "Not)A;Brand";v="24"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"macOS"',
}
response = _get(
'https://api.geetest.com/ajax.php?gt=' + gt + '&challenge=' + challenge + '&lang=zh-cn&pt=0&client_type=web&w=' + w + '&callback=geetest_' + str(
int(round(time.time() * 1000))),
"https://api.geetest.com/ajax.php?gt="
+ gt
+ "&challenge="
+ challenge
+ "&lang=zh-cn&pt=0&client_type=web&w="
+ w
+ "&callback=geetest_"
+ str(int(round(time.time() * 1000))),
headers=headers,
proxies=proxies,
)
return _parse_jsonp_response(response, "极验 fullpage ajax.php")
def req_slide(gt:str, challenge:str, w2:str) -> None:
def req_slide(gt: str, challenge: str, w2: str) -> None:
headers = {
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Referer': 'https://demos.geetest.com/',
'Sec-Fetch-Dest': 'script',
'Sec-Fetch-Mode': 'no-cors',
'Sec-Fetch-Site': 'cross-site',
'Sec-Fetch-Storage-Access': 'active',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
"Accept": "*/*",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "keep-alive",
"Referer": "https://demos.geetest.com/",
"Sec-Fetch-Dest": "script",
"Sec-Fetch-Mode": "no-cors",
"Sec-Fetch-Site": "cross-site",
"Sec-Fetch-Storage-Access": "active",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
"sec-ch-ua": '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
}
response = requests.get(
'https://api.geevisit.com/ajax.php?gt=' + gt + '&challenge=' + challenge + '&lang=zh-cn&pt=0&client_type=web&w=' + w2 + '&callback=geetest_' + str(
int(round(time.time() * 1000))),
"https://api.geevisit.com/ajax.php?gt="
+ gt
+ "&challenge="
+ challenge
+ "&lang=zh-cn&pt=0&client_type=web&w="
+ w2
+ "&callback=geetest_"
+ str(int(round(time.time() * 1000))),
headers=headers,
timeout=REQUEST_TIMEOUT,
)
response.raise_for_status()
def get_picture(gt:str, challenge:str) -> tuple[str, str, list[int], str, str, str]:
def get_picture(gt: str, challenge: str) -> tuple[str, str, list[int], str, str, str]:
headers = {
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Referer': 'https://demos.geetest.com/',
'Sec-Fetch-Dest': 'script',
'Sec-Fetch-Mode': 'no-cors',
'Sec-Fetch-Site': 'cross-site',
'Sec-Fetch-Storage-Access': 'active',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
"Accept": "*/*",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "keep-alive",
"Referer": "https://demos.geetest.com/",
"Sec-Fetch-Dest": "script",
"Sec-Fetch-Mode": "no-cors",
"Sec-Fetch-Site": "cross-site",
"Sec-Fetch-Storage-Access": "active",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
"sec-ch-ua": '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
}
params = {
'is_next': 'true',
'type': 'slide3',
'gt': gt,
'challenge': challenge,
'lang': 'zh-cn',
'https': 'true',
'protocol': 'https://',
'offline': 'false',
'product': 'embed',
'api_server': 'api.geevisit.com',
'isPC': 'true',
'autoReset': 'true',
'width': '100%',
'callback': 'geetest_'+str(int(round(time.time() * 1000))),
"is_next": "true",
"type": "slide3",
"gt": gt,
"challenge": challenge,
"lang": "zh-cn",
"https": "true",
"protocol": "https://",
"offline": "false",
"product": "embed",
"api_server": "api.geevisit.com",
"isPC": "true",
"autoReset": "true",
"width": "100%",
"callback": "geetest_" + str(int(round(time.time() * 1000))),
}
response = requests.get(
'https://api.geevisit.com/get.php',
"https://api.geevisit.com/get.php",
params=params,
headers=headers,
timeout=REQUEST_TIMEOUT,
)
response.raise_for_status()
logger.debug("极验 get.php 原始响应: {}", response.text[:500])
match = re.search(r'\((.*)\)$', response.text)
match = re.search(r"\((.*)\)$", response.text)
if match:
json_str = match.group(1)
data = json.loads(json_str)
if 'data' in data and isinstance(data['data'], dict):
if "data" in data and isinstance(data["data"], dict):
# 新版极验格式
inner_data = data['data']
inner_data = data["data"]
return (
inner_data.get('bg', ''),
inner_data.get('fullbg', ''),
inner_data.get('c', []),
inner_data.get('s', ''),
inner_data.get('slice', ''),
inner_data.get('challenge', '')
inner_data.get("bg", ""),
inner_data.get("fullbg", ""),
inner_data.get("c", []),
inner_data.get("s", ""),
inner_data.get("slice", ""),
inner_data.get("challenge", ""),
)
else:
# 旧版极验格式
return (
data.get('bg', ''),
data.get('fullbg', ''),
data.get('c', []),
data.get('s', ''),
data.get('slice', ''),
data.get('challenge', '')
data.get("bg", ""),
data.get("fullbg", ""),
data.get("c", []),
data.get("s", ""),
data.get("slice", ""),
data.get("challenge", ""),
)
else:
raise ValueError("无法解析 JSONP 响应")
def req_end(gt:str, challenge:str, w:str) -> dict:
def req_end(gt: str, challenge: str, w: str) -> dict:
headers = {
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Referer': 'https://demos.geetest.com/',
'Sec-Fetch-Dest': 'script',
'Sec-Fetch-Mode': 'no-cors',
'Sec-Fetch-Site': 'cross-site',
'Sec-Fetch-Storage-Access': 'active',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36',
'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
"Accept": "*/*",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "keep-alive",
"Referer": "https://demos.geetest.com/",
"Sec-Fetch-Dest": "script",
"Sec-Fetch-Mode": "no-cors",
"Sec-Fetch-Site": "cross-site",
"Sec-Fetch-Storage-Access": "active",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36",
"sec-ch-ua": '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
}
response = requests.get(
'https://api.geevisit.com/ajax.php?gt='+gt+'&challenge='+challenge+'&lang=zh-cn&%24_BCm=0&client_type=web&w='+w+'&callback=geetest_'+str(int(round(time.time() * 1000))),
"https://api.geevisit.com/ajax.php?gt="
+ gt
+ "&challenge="
+ challenge
+ "&lang=zh-cn&%24_BCm=0&client_type=web&w="
+ w
+ "&callback=geetest_"
+ str(int(round(time.time() * 1000))),
headers=headers,
timeout=REQUEST_TIMEOUT,
)
response.raise_for_status()
logger.debug("极验 ajax.php 原始响应: {}", response.text[:500])
match = re.search(r'\((.*)\)$', response.text)
match = re.search(r"\((.*)\)$", response.text)
if match:
json_str = match.group(1)
data = json.loads(json_str)
logger.debug("极验验证响应: {}", data)
# 检查验证是否成功
if data.get('success') == 1:
if data.get("success") == 1:
return data
else:
# 如果验证失败,返回错误信息
return {
'success': 0,
'message': data.get('message', '验证失败'),
'validate': ''
"success": 0,
"message": data.get("message", "验证失败"),
"validate": "",
}
else:
raise ValueError("无法解析 JSONP 响应")
+49 -40
View File
@@ -18,63 +18,70 @@ def generate_fake_performance_timing(base_time: Optional[int] = None) -> dict[st
# 定义合理的时间间隔范围(毫秒)
intervals = {
'fetch': random.randint(1, 2),
'domain_lookup_start': random.randint(3, 5),
'domain_lookup': random.randint(5, 15),
'connect': random.randint(50, 150),
'ssl_offset': random.randint(30, 50),
'request': random.randint(1, 5),
'response': random.randint(20, 100),
'response_end': random.randint(1, 3),
'unload_start': random.randint(1, 3),
'unload': random.randint(1, 5),
'dom_loading': random.randint(1, 3),
'dom_interactive': random.randint(50, 200),
'dom_content_loaded': random.randint(1, 3),
'load_event': random.randint(0, 5)
"fetch": random.randint(1, 2),
"domain_lookup_start": random.randint(3, 5),
"domain_lookup": random.randint(5, 15),
"connect": random.randint(50, 150),
"ssl_offset": random.randint(30, 50),
"request": random.randint(1, 5),
"response": random.randint(20, 100),
"response_end": random.randint(1, 3),
"unload_start": random.randint(1, 3),
"unload": random.randint(1, 5),
"dom_loading": random.randint(1, 3),
"dom_interactive": random.randint(50, 200),
"dom_content_loaded": random.randint(1, 3),
"load_event": random.randint(0, 5),
}
timing = {}
# 按照时间顺序构建
timing['navigationStart'] = base_time
timing['fetchStart'] = timing['navigationStart'] + intervals['fetch']
timing['domainLookupStart'] = timing['fetchStart'] + intervals['domain_lookup_start']
timing['domainLookupEnd'] = timing['domainLookupStart'] + intervals['domain_lookup']
timing["navigationStart"] = base_time
timing["fetchStart"] = timing["navigationStart"] + intervals["fetch"]
timing["domainLookupStart"] = (
timing["fetchStart"] + intervals["domain_lookup_start"]
)
timing["domainLookupEnd"] = timing["domainLookupStart"] + intervals["domain_lookup"]
timing['connectStart'] = timing['domainLookupEnd']
timing['secureConnectionStart'] = timing['connectStart'] + intervals['ssl_offset']
timing['connectEnd'] = timing['connectStart'] + intervals['connect']
timing["connectStart"] = timing["domainLookupEnd"]
timing["secureConnectionStart"] = timing["connectStart"] + intervals["ssl_offset"]
timing["connectEnd"] = timing["connectStart"] + intervals["connect"]
timing['requestStart'] = timing['connectEnd'] + intervals['request']
timing['responseStart'] = timing['requestStart'] + intervals['response']
timing['responseEnd'] = timing['responseStart'] + intervals['response_end']
timing["requestStart"] = timing["connectEnd"] + intervals["request"]
timing["responseStart"] = timing["requestStart"] + intervals["response"]
timing["responseEnd"] = timing["responseStart"] + intervals["response_end"]
timing['unloadEventStart'] = timing['responseEnd'] + intervals['unload_start']
timing['unloadEventEnd'] = timing['unloadEventStart'] + intervals['unload']
timing["unloadEventStart"] = timing["responseEnd"] + intervals["unload_start"]
timing["unloadEventEnd"] = timing["unloadEventStart"] + intervals["unload"]
timing['domLoading'] = timing['unloadEventEnd'] + intervals['dom_loading']
timing['domInteractive'] = timing['domLoading'] + intervals['dom_interactive']
timing['domContentLoadedEventStart'] = timing['domInteractive']
timing['domContentLoadedEventEnd'] = timing['domInteractive'] + intervals['dom_content_loaded']
timing['domComplete'] = timing['domContentLoadedEventEnd']
timing['loadEventStart'] = timing['domComplete']
timing['loadEventEnd'] = timing['loadEventStart'] + intervals['load_event']
timing["domLoading"] = timing["unloadEventEnd"] + intervals["dom_loading"]
timing["domInteractive"] = timing["domLoading"] + intervals["dom_interactive"]
timing["domContentLoadedEventStart"] = timing["domInteractive"]
timing["domContentLoadedEventEnd"] = (
timing["domInteractive"] + intervals["dom_content_loaded"]
)
timing["domComplete"] = timing["domContentLoadedEventEnd"]
timing["loadEventStart"] = timing["domComplete"]
timing["loadEventEnd"] = timing["loadEventStart"] + intervals["load_event"]
# 无重定向的情况
timing['redirectStart'] = 0
timing['redirectEnd'] = 0
timing["redirectStart"] = 0
timing["redirectEnd"] = 0
return timing
def __ease_out_expo(sep):
'''
轨迹相关操作
'''
"""
轨迹相关操作
"""
if sep == 1:
return 1
else:
return 1 - pow(2, -10 * sep)
def get_slide_track(distance):
"""
根据滑动距离生成滑动轨迹
@@ -86,7 +93,9 @@ def get_slide_track(distance):
"""
if not isinstance(distance, int) or distance < 0:
raise ValueError(f"distance类型必须是大于等于0的整数: distance: {distance}, type: {type(distance)}")
raise ValueError(
f"distance类型必须是大于等于0的整数: distance: {distance}, type: {type(distance)}"
)
# 初始化轨迹列表
slide_track = [
[random.randint(-50, -10), random.randint(-50, -10), 0],
@@ -110,4 +119,4 @@ def get_slide_track(distance):
slide_track.append([x, _y, t])
_x = x
slide_track.append(slide_track[-1])
return slide_track, slide_track[-1][2]
return slide_track, slide_track[-1][2]
+85 -25
View File
@@ -2,25 +2,60 @@ import time
import random
import json
from loguru import logger
from core.geetest.common.trajectory import generate_realistic_trajectory, process_mouse_trajectory, compress_trajectory, TrajectoryEncoder, \
H
from core.geetest.common.crypto import four_random_chart, RSA_jiami_r, AES_O, geetest_base64_encode, encrypt_string, simple_md5
from core.geetest.common.trajectory import (
generate_realistic_trajectory,
process_mouse_trajectory,
compress_trajectory,
TrajectoryEncoder,
H,
)
from core.geetest.common.crypto import (
four_random_chart,
RSA_jiami_r,
AES_O,
geetest_base64_encode,
encrypt_string,
simple_md5,
)
from core.geetest.common.imaging import download_picture
from core.geetest.common.network import get_challenge_gt, get_js_address, get_c_s, req_slide, get_picture, req_end
from core.geetest.common.performance import generate_fake_performance_timing, get_slide_track
from core.geetest.common.network import (
get_challenge_gt,
get_js_address,
get_c_s,
req_slide,
get_picture,
req_end,
)
from core.geetest.common.performance import (
generate_fake_performance_timing,
get_slide_track,
)
def _generate_seed() -> str:
return four_random_chart() + four_random_chart() + four_random_chart() + four_random_chart()
return (
four_random_chart()
+ four_random_chart()
+ four_random_chart()
+ four_random_chart()
)
def get_w1(gt:str, challenge:str, str_16:str) -> str:
def get_w1(gt: str, challenge: str, str_16: str) -> str:
r = RSA_jiami_r(str_16)
plaintext = '{"gt":"' + gt + '","challenge":"' + challenge + '","offline":false,"new_captcha":true,"product":"float","width":"300px","https":true,"api_server":"apiv6.geetest.com","protocol":"https://","type":"fullpage","static_servers":["static.geetest.com/","static.geevisit.com/"],"voice":"/static/js/voice.1.2.6.js","click":"/static/js/click.3.1.2.js","beeline":"/static/js/beeline.1.0.1.js","fullpage":"/static/js/fullpage.9.2.0-guwyxh.js","slide":"/static/js/slide.7.9.3.js","geetest":"/static/js/geetest.6.0.9.js","aspect_radio":{"slide":103,"click":128,"voice":128,"beeline":50},"cc":16,"ww":true,"i":"-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1"}'
plaintext = (
'{"gt":"'
+ gt
+ '","challenge":"'
+ challenge
+ '","offline":false,"new_captcha":true,"product":"float","width":"300px","https":true,"api_server":"apiv6.geetest.com","protocol":"https://","type":"fullpage","static_servers":["static.geetest.com/","static.geevisit.com/"],"voice":"/static/js/voice.1.2.6.js","click":"/static/js/click.3.1.2.js","beeline":"/static/js/beeline.1.0.1.js","fullpage":"/static/js/fullpage.9.2.0-guwyxh.js","slide":"/static/js/slide.7.9.3.js","geetest":"/static/js/geetest.6.0.9.js","aspect_radio":{"slide":103,"click":128,"voice":128,"beeline":50},"cc":16,"ww":true,"i":"-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1!!-1"}'
)
o = AES_O(plaintext, str_16)
i = geetest_base64_encode(o)
return i['res'] + i['end'] + r
return i["res"] + i["end"] + r
def get_w2(gt:str, challenge:str, c:list[int], s:str,str_16:str) -> str:
def get_w2(gt: str, challenge: str, c: list[int], s: str, str_16: str) -> str:
# 伪造浏览器性能数据
fake_timing = generate_fake_performance_timing()
# 映射
@@ -45,7 +80,7 @@ def get_w2(gt:str, challenge:str, c:list[int], s:str,str_16:str) -> str:
"r": fake_timing["domContentLoadedEventEnd"],
"s": fake_timing["domComplete"],
"t": fake_timing["loadEventStart"],
"u": fake_timing["loadEventEnd"]
"u": fake_timing["loadEventEnd"],
}
first_time = int(round(time.time() * 1000)) # 伪造脚本开始运行时间
@@ -55,10 +90,9 @@ def get_w2(gt:str, challenge:str, c:list[int], s:str,str_16:str) -> str:
start_y=random.randint(400, 500),
end_x=853,
end_y=288,
start_time=first_time
start_time=first_time,
)
trajectory = process_mouse_trajectory(guiji_yuanshu_shuzu)["data"]
compressed = compress_trajectory(trajectory)
tt = encrypt_string(compressed, c, s)
@@ -67,14 +101,30 @@ def get_w2(gt:str, challenge:str, c:list[int], s:str,str_16:str) -> str:
rp = simple_md5(gt + challenge + passtime)
plaintext = '{"lang":"zh-cn","type":"fullpage","tt":"'+tt+'","light":"DIV_0","s":"c7c3e21112fe4f741921cb3e4ff9f7cb","h":"321f9af1e098233dbd03f250fd2b5e21","hh":"39bd9cad9e425c3a8f51610fd506e3b3","hi":"09eb21b3ae9542a9bc1e8b63b3d9a467","vip_order":-1,"ct":-1,"ep":{"v":"9.2.0-guwyxh","te":false,"$_BBn":true,"ven":"Google Inc. (AMD)","ren":"ANGLE (AMD, AMD Radeon RX 6750 GRE 12GB (0x000073DF) Direct3D11 vs_5_0 ps_5_0, D3D11)","fp":'+json.dumps(guiji_yuanshu_shuzu[0], separators=(',', ':'))+',"lp":'+json.dumps(guiji_yuanshu_shuzu[-1], separators=(',', ':'))+',"em":{"ph":0,"cp":0,"ek":"11","wd":1,"nt":0,"si":0,"sc":0},"tm":'+json.dumps(web_load_time, separators=(',', ':'))+',"dnf":"dnf","by":0},"passtime":'+passtime+',"rp":"'+rp+'","captcha_token":"112439067","tsfq":"xovrayel"}'
plaintext = (
'{"lang":"zh-cn","type":"fullpage","tt":"'
+ tt
+ '","light":"DIV_0","s":"c7c3e21112fe4f741921cb3e4ff9f7cb","h":"321f9af1e098233dbd03f250fd2b5e21","hh":"39bd9cad9e425c3a8f51610fd506e3b3","hi":"09eb21b3ae9542a9bc1e8b63b3d9a467","vip_order":-1,"ct":-1,"ep":{"v":"9.2.0-guwyxh","te":false,"$_BBn":true,"ven":"Google Inc. (AMD)","ren":"ANGLE (AMD, AMD Radeon RX 6750 GRE 12GB (0x000073DF) Direct3D11 vs_5_0 ps_5_0, D3D11)","fp":'
+ json.dumps(guiji_yuanshu_shuzu[0], separators=(",", ":"))
+ ',"lp":'
+ json.dumps(guiji_yuanshu_shuzu[-1], separators=(",", ":"))
+ ',"em":{"ph":0,"cp":0,"ek":"11","wd":1,"nt":0,"si":0,"sc":0},"tm":'
+ json.dumps(web_load_time, separators=(",", ":"))
+ ',"dnf":"dnf","by":0},"passtime":'
+ passtime
+ ',"rp":"'
+ rp
+ '","captcha_token":"112439067","tsfq":"xovrayel"}'
)
result = geetest_base64_encode(AES_O(plaintext, str_16))
return result['res']+result['end']+result['end']
return result["res"] + result["end"] + result["end"]
def get_w3(str_16:str, challenge:str, hkjl:int, c:list[int], s:str, gt:str) -> str:
def get_w3(
str_16: str, challenge: str, hkjl: int, c: list[int], s: str, gt: str
) -> str:
encoder = TrajectoryEncoder()
u = RSA_jiami_r(str_16)
# 伪造浏览器性能数据
@@ -101,11 +151,9 @@ def get_w3(str_16:str, challenge:str, hkjl:int, c:list[int], s:str, gt:str) -> s
"r": fake_timing["domContentLoadedEventEnd"],
"s": fake_timing["domComplete"],
"t": fake_timing["loadEventStart"],
"u": fake_timing["loadEventEnd"]
"u": fake_timing["loadEventEnd"],
}
trajectory = get_slide_track(hkjl)[0]
logger.debug("滑动轨迹: {}", trajectory)
@@ -117,13 +165,25 @@ def get_w3(str_16:str, challenge:str, hkjl:int, c:list[int], s:str, gt:str) -> s
passtime = str(trajectory[-1][2])
rp = simple_md5(gt + challenge[:32] + passtime)
plaintext = '{"lang":"zh-cn","userresponse":"'+userresponse+'","passtime":'+passtime+',"imgload":50,"aa":"'+aa+'","ep":{"v":"7.9.3","$_BIT":false,"me":true,"tm":'+json.dumps(web_load_time, separators=(',', ':'))+',"td":-1},"h9s9":"1816378497","rp":"'+rp+'"}'
plaintext = (
'{"lang":"zh-cn","userresponse":"'
+ userresponse
+ '","passtime":'
+ passtime
+ ',"imgload":50,"aa":"'
+ aa
+ '","ep":{"v":"7.9.3","$_BIT":false,"me":true,"tm":'
+ json.dumps(web_load_time, separators=(",", ":"))
+ ',"td":-1},"h9s9":"1816378497","rp":"'
+ rp
+ '"}'
)
h = geetest_base64_encode(AES_O(plaintext, str_16))["res"]
return h + u
h = geetest_base64_encode(AES_O(plaintext, str_16))['res']
return h+u
def run_solver() -> None:
# 16位字符串
@@ -154,7 +214,7 @@ def run_solver() -> None:
hkjl = download_picture(bg, fullbg, slice)
# 获取第三个w值
w3 = get_w3(str_16,challenge,hkjl,c,s,gt)
w3 = get_w3(str_16, challenge, hkjl, c, s, gt)
# 最后的验证
message = req_end(gt, challenge, w3)