注意,本文只提供学习的思路,严禁违反法律以及破坏信息系统等行为,本文只提供思路
本文的验证码网址如下,使用base64解码获得
aHR0cDovL2NhcHRjaGEudGlhbmFpLmNsb3VkLw==
打开官网,由于有许多验证码类型,这里只讲一种,拿滑块验证码举例,通过刷新验证码后,请求验证码接口如下:
请求拿到本地后,需要解决的参数有两个custom和ki,跟栈进去,寻找加密逻辑,发现是混淆代码
大致看了下,都是最基本的混淆,拿出我们自己的混淆代码或者混淆网站还原混淆后,并成功找到加密位置,如下:
还原之后的逻辑非常显而易见了,拿标注库进行AES加密后,再用RSA加密,我们直接在本地也去实现一下
拿到加密值后,再次请求,成功拿到所需参数
接下来分析参数,backgroundImage是背景图片,是经过打乱之后的,templateImage是缺口图片,pos是还原的顺序
可以看到,分割成了两行五列,pos也是每个坐标对应的正确顺序,我们用cv2库简单还原即可
# 将图片切割,2行5列,切割成10块
# 获取图片的高度和宽度
height, width = image.shape[:2]# 计算每个小块的高度和宽度
block_height = height // 2
block_width = width // 5# 切割图片并保存
blocks = []
for i in range(2): # 行数for j in range(5): # 列数# 计算当前小块的起始和结束位置y_start = i * block_heighty_end = (i + 1) * block_heightx_start = j * block_widthx_end = (j + 1) * block_width# 切割图片block = image[y_start:y_end, x_start:x_end]blocks.append(block)# 加载并排列图片
arranged_images = []
for idx in pos:# 加载对应索引的图片image = blocks[int(idx)]arranged_images.append(image)# 创建一个空白画布,用于排列图片
canvas_height = blocks[0].shape[0] * 2 # 乘以 2 是因为有两行
canvas_width = blocks[0].shape[1] * 5 # 乘以 5 是因为有五列
canvas = np.zeros((canvas_height, canvas_width, 3), dtype=np.uint8)# 排列图片
for i in range(2): # 行数for j in range(5): # 列数idx = i * 5 + j # 计算对应图片的索引if idx < len(arranged_images):# 将图片复制到画布上canvas[i * blocks[0].shape[0]: (i + 1) * blocks[0].shape[0], j * blocks[0].shape[1]: (j + 1) * blocks[0].shape[1]] = arranged_images[idx]# cv2.resize(canvas, (300, 180))
# 保存排列后的图片
cv2.imwrite('arranged_image.png', canvas)
还原之后效果如下:
经过多次请求发现,滑块有可能是两个缺口,有可能是一个缺口,针对这种情况,我们可以使用模板匹配的方法去校验缺口距离,具体可以参考我这篇文章:Python-Opencv 识别滑块验证码缺口位置
我这里也放出相关代码
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import osdef cv_show(img): # 展示图片cv2.imshow("img", img)cv2.waitKey(0)cv2.destroyAllWindows()def get_q():# 转换颜色通道,保持颜色准确image = cv2.imread(r"arranged_image.png")gap = cv2.imread(r"que.png")image_gray = cv2.cvtColor(image.copy(), cv2.COLOR_BGR2GRAY)gap_gray = cv2.cvtColor(gap.copy(), cv2.COLOR_BGR2GRAY)h, w = gap_gray.shapew_start_index, h_start_index = 0, 0w_end_index, h_end_index = w, h# 缺口图去除背景for i in range(h):if not any(gap_gray[i, :]):h_start_index = ielse:breakfor i in range(h - 1, 0, -1):if not any(gap_gray[i, :]):h_end_index = ielse:breakfor i in range(w):if not any(gap_gray[:, i]):w_start_index = ielse:breakfor i in range(w - 1, 0, -1):if not any(gap_gray[:, i]):w_end_index = ielse:break# 取出完整的缺口图gap_gray = gap_gray[h_start_index:h_end_index+1, w_start_index:w_end_index+1]image_gray = cv2.adaptiveThreshold(image_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 5, 0)gap_gray = cv2.adaptiveThreshold(gap_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 5, 0)image_v1 = cv2.Canny(image_gray, 0, 500)gray_v1 = cv2.Canny(gap_gray, 0, 500)# cv_show(gray_v1)result = cv2.matchTemplate(image_v1, gray_v1, cv2.TM_CCOEFF_NORMED)min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)x, y = max_loch, w = gap_gray.shaperesult = np.array(image.copy())color = (0, 0, 255)# print(check_box)cv2.rectangle(result, (x, y), (x + w, y + h), color, 2)# res = np.hstack([image_gray,gray_v1, image_v1, result])# cv_show(result)return x
经测试,准确率还是蛮高的,接下来,回到网页中去查找发送参数,可以看到,发送参数比之前多了个id和data
这里的id就是之前请求验证码的id,data就是我们需要破解的参数,继续回到之前加密的地方可以发现,加密还是同一个地方,只是这次多一次加密,加密的数据如下
这里就很简单了,我们把参数构造下,轨迹模拟下,再次请求,就能得到成功响应结果
这里,也感谢我的一位小伙伴,告诉我滑块轨迹非常严格,让我少走弯路