在这篇文章中,我们将介绍如何使用Python来逆向工程gcaptcha4.js文件,找到并破解w参数的加密算法。这个过程包括观察verify请求,定位加密位置,分析加密算法,最终还原w参数的明文。
一. 观察verify请求
首先,我们需要观察verify请求的发起者。在网络请求中,我们可以看到所有verify请求都来自于gcaptcha4.js文件。因此,这个文件成为我们分析的重点。
我们使用Python的requests库来捕获和分析这些请求。
python
import requests
# 发送一个测试请求,获取响应
response = requests.get('https://example.com/verify')
print(response.text)
通过分析响应内容,可以发现所有的verify请求都指向了gcaptcha4.js文件。
二. 定位w参数加密位置
为了找到w参数的加密位置,我们需要解析gcaptcha4.js文件。我们可以下载并格式化这个文件,然后使用正则表达式搜索关键词:w、.w、'w'或"w"。
python
import re
# 读取gcaptcha4.js文件内容
with open('gcaptcha4.js', 'r') as file:
js_content = file.read()
# 搜索w参数的位置
matches = re.finditer(r'[\.\'\"]w[\.\'\"]', js_content)
for match in matches:
print(match.start(), match.end(), match.group())
通过搜索"w",我们找到了相关代码。在第2527行,我们发现了w的值r在第2525行被定义。
三. 分析w参数加密算法
接下来,我们需要简化代码中w的定义。假设我们已经提取了相关的JavaScript代码,我们可以用Python来模拟这个过程。
python
import json
import hashlib
import random
def js_stringify(data):
return json.dumps(data)
def js_default(data, key):
return hashlib.md5((data + key).encode()).hexdigest()
# 模拟JavaScript的逗号操作符行为
r = js_default(js_stringify(e), a)
首先,js_stringify(e)相当于对e进行JSON序列化操作。然后,我们分析js_default(js_stringify(e), a)的含义。
python
def a(e, t):
s = t.get("options", {})
if not s.get("pt") or s["pt"] == "0":
return urlsafe_encode(e)
if s["pt"] == "1":
n = generate_guid()
a = encrypt(n)
while not a or len(a) != 256:
n = generate_guid()
a = encrypt(n)
o = encrypt(e, n)
return array_to_hex(o) + a
我们可以简化上述Python代码如下:
python
def a(e, t):
n = generate_guid()
a = encrypt(n)
o = encrypt(e, n)
return array_to_hex(o) + a
从这里可以确定参数t未被使用,参数e就是w的明文。接着我们分析e的组成部分:
python
e = {
'device_id': 'A8A0', # 固定值
'em': {
'cp': 0,
'ek': '11',
'nt': 0,
'ph': 0,
'sc': 0,
'si': 0,
'wd': 1,
}, # 固定值
'ep': '123', # 固定值
'geetest': 'captcha', # 固定值
'fq6a': '1925502591', # 固定值
'lang': 'zh', # 固定值
'lot_number': '7e22264d4f3e4dd8a6ffbf6e82e1122d', # load请求返回值
'passtime': 166, # 通过时间
'pow_msg': '1|0|md5|2022-03-25T14:23:36.364152+08:00|24f56dc13c40dc4a02fd0318567caef5|7e22264d4f3e4dd8a6ffbf6e82e1122d||29f07cebf938aa4e', # load请求返回加上某算法返回值
'pow_sign': '2b47a3a9425dd19dd5abf902c8bb0763', # pow_msg的md5值
'setLeft': 88, # 滑动距离
'track': [[38, 18, 0], [1, 0, 33]......], # 轨迹
'userresponse': 87.47978686742837 # 某算法返回值
}
4.1 分析pow_msg和pow_sign
通过搜索pow_msg,我们找到相关代码并解析如下:
python
def generate_guid():
return ''.join([format(random.randint(0, 65535), 'x') for _ in range(4)])
u = f"{n}|{a}|{s}|{o}|{t}|{e}|{r}|"
p = generate_guid()
g = u + p
pow_msg = u + p
pow_sign = hashlib.md5(g.encode()).hexdigest()
4.2 分析set_left、track、passtime、userresponse
set_left:滑块移动距离的整数值
track:移动轨迹,从第二步开始,是相对上一步的相对移动距离(x, y, t)
passtime:总移动时间
userresponse:计算公式为set_left / (0.8876 * 340 / 300)
python
set_left = 88
track = [[38, 18, 0], [1, 0, 33]......]
passtime = 166
userresponse = set_left / (0.8876 * 340 / 300)
至此,我们已经完成了w参数的明文解析。