文章目录
- 概要
- 整体架构流程
- 小结
概要
提示:仅供学习,不得用做商业交易,如有侵权请及时联系v:wzwzwz0613
逆向:99某某中心(滑块验证)
URL:aHR0cHM6Ly9hcS45OS5jb20vVjMvTkRVc2VyX0xvZ2luLmh0bQ==
目的:滑块验证
整体架构流程
提示:获取配置参数接口,获取滑块背景图片接口,验证滑块接口
一、点击登录按钮,出现俩个接口(一个是配置接口,一个是获取滑块背景图片接口):
1、Default接口:Data参数相当于appid,写死即可
url = "https://xxx/Default.ashx"
data = {
"Action": "checkcodeinit",
"Data": "xxx",
"Business": "common"
}
response = requests.post(url, headers=headers, data=data).json()
返回响应参数(Message下个接口的请求参数challenge):
二、slide接口:
请求参数:challenge上个接口返回值,ts是时间戳
观察发现背景图片是乱的,所以我们得还原背景图片,我们可以通过事件监听器进行断点,也就是画布断点:
响应参数:
imageRandomPos:底图还原的数组
originalImageBase64:乱的背景图片
secretKey:加密密钥(后面验证接口的参数会用到)
sliderImageBase64:滑块图片
这里我就不说怎么还原了,直接帖代码:
# order:还原数组,img_data:originalImageBase64,_img:还原的图片地址
# 底图还原
def huanyuan(order, img_data, _img):
img_data = base64.b64decode(img_data)
# 创建图像对象
img = Image.open(io.BytesIO(img_data))
a = img.width # 宽度
s = img.height # 高度
i = a // len(order) # 每个块的宽度
# 创建新的空白图像
new_img = Image.new('RGB', (a, s))
d = 0 # 当前位置
for v in range(len(order)):
h = order[v]
y = i if h != len(order) - 1 else a - i * (len(order) - 1)
# 获取拼图块
l = img.crop((d, 0, d + y, s))
# 粘贴到新图像中
new_img.paste(l, (h * i, 0))
d += y
new_img.save(_img)
三、验证滑块接口,通过启动器断点,往上找,会找到这个位置:
那么c就是我们验证接口的参数:
challenge:上个接口的
k:通过上个接口返回的secretKey对随机生成的16位字符串进行aes加密
i:通过上个接口返回的secretKey对随机生成的16位字符串进行aes加密
from Crypto.Cipher import PKCS1_v1_5,AES
from Crypto.PublicKey import RSA
# Aes加密 Utf
def aesEncrypt(text,key=None,iv=None):
cipher = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
pad = 16 - len(text) % 16
text = text + pad * chr(pad)
encrypted_text = cipher.encrypt(text.encode('utf-8'))
return base64.b64encode(encrypted_text).decode('utf-8')
最后就是w参数的生成,先看s生成:
s = {
// 当前时间 new Date
t: a.stopTime,
// 滑块轨迹
pj: a.trackArr,
// 滑动时间
ut: a.stopTime - a.startTime,
// 背景图片宽
iw: parseInt(a.bgImageWidth),
// 背景图片高
ih: parseInt(a.bgImageHeight),
// 滑块背景图片 + new Date +'' 进行md5(大写)
sm: zt.md5Encrypt(a.sliderImageBase64 + a.stopTime).toString().toUpperCase(),
// 浏览器指纹信息
bi: n.config.fp,
// 配置接口Date参数
bf: n.config.fpHash,
ct: "slide"
}
获取滑动距离代码:
# 获取滑块距离
def identify_gap(bg, tp):
"""
bg: 背景图片
tp: 缺口图片
out: 输出图片
"""
# 读取背景图片和缺口图片
bg_img = cv2.imdecode(np.frombuffer(bg, np.uint8), cv2.IMREAD_GRAYSCALE)
tp_img = cv2.imdecode(np.frombuffer(tp, np.uint8), cv2.IMREAD_GRAYSCALE) # 缺口图片
yy = []
xx = []
for y in range(tp_img.shape[0]):
for x in range(tp_img.shape[1]):
r = tp_img[y, x]
if r < 200:
yy.append(y)
xx.append(x)
tp_img = tp_img[min(yy):max(yy), min(xx):max(xx)]
# 识别图片边缘
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) # 寻找最优匹配
# # 绘制方框
th, tw = tp_pic.shape[:2]
tl = max_loc # 左上角点的坐标
br = (tl[0] + tw, tl[1] + th) # 右下角点的坐标
cv2.rectangle(bg_img, tl, br, (0, 0, 255), 2) # 绘制矩形
cv2.imwrite('distinguish.jpg', bg_img) # 保存在本地
# 返回缺口的X坐标
return max_loc[0]
获取轨迹代码:
# 获取滑块轨迹1
def guiji(distance):
trackList = 收集浏览器从头滑到尾的距离
# 检查value是否在轨迹的x值中
for trajectory in trackList:
if trajectory['x'] == distance:
# 如果找到,截取从轨迹开始到该点的子数组
return [t for t in trackList if t['x'] <= distance]
# 如果value不在x值中,找到最接近value的x值
closest_x = None
min_diff = float('inf')
for trajectory in trackList:
if abs(trajectory['x'] - distance) < min_diff:
min_diff = abs(trajectory['x'] - distance)
closest_x = trajectory['x']
# 截取从轨迹开始到最接近的x值的子数组
result = [t for t in trackList if t['x'] <= closest_x]
result[-1]['x'] = distance
return result
RSA加密:
# RSA加密
def RsaEncrypt(plaintext,key):
key_bytes = base64.b64decode(key)
public_key = RSA.importKey(key_bytes)
cipher = PKCS1_v1_5.new(public_key)
bits_len = int(public_key.size_in_bits() / 1024 * 100)
ciphertext = b""
for i in range(0, len(plaintext), bits_len):
ciphertext += cipher.encrypt(plaintext[i:i + bits_len].encode())
result = base64.b64encode(ciphertext).decode('utf-8')
return result
四、最后我们看效果
小结
提示:学习交流群:v:wzwzwz0613