好友
阅读权限 10
听众
最后登录 1970-1-1
本帖最后由 li63033 于 2024-3-5 14:35 编辑
声明
本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!
本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请联系作者立即删除!
目标
目标:点选人机验证逆向分析
网址:aHR0cHM6Ly9iZWlhbi5taWl0Lmdvdi5jbi8jL0ludGVncmF0ZWQvaW5kZXg=
流程分析
进入页面前,先打开F12开发者工具
上来就是个521大礼包,朋友们这可太熟悉了,妥妥的jsl,现在这东西逆向真的已经烂大街了(不排除有刚入坑的小伙伴,后期单独补上)
未进行查询验证前,Network中我们会看到一个/auth
接口进行认证操作,请求传递了两个参数。
authKey:时间戳加盐后的MD5,需要逆向得到
timeStamp:当前时间戳
接口返回了后续请求中,header需要携带的token
点击查询验证后,出现了我们今天分析的主角:文字点选验证码,加载接口为/getCheckImagePoint
,传递了一个参数
clientUid:设备id,需要逆向得到
接口返回了点选验证码的详细信息
点选完毕后,进行验证的接口为/checkImage
,传递了相关点选的数据
clientUid:3中生成的clientUid
pointJson:点击坐标密文,需要逆向得到
secretKey:加密密钥
token:加载接口返回的验证码id
未通过验证,会刷新验证码,验证返回的数据如下
通过验证,会跳转查询请求,验证返回数据中会多一个sign
字段
查询请求接口为/queryByCondition
,需要再请求头中携带四个正确的字段,才能够请求成功
参数正确,返回的请求数据如下
逆向分析
1. authKey
参数
跟到这个参数很简单,直接全局搜就能看到了
2. clientUid
参数
这个参数也很简单,还是全局搜,我们会发现是已经生成好存在了localstorage中
所以我们干脆直接改为全局搜localStorage.getItem
,就能定位到生成&存储的位置了
3. pointJson
参数
仍然是全局搜,很快就能定位到参数生成的位置,入口为h
函数,跟进去我们就能看到,是个AES加密,密钥为接口返回的secretKey
,加密模式为ECB
,填充模式为Pkcs7
4. Cookie中的__jsluid_s
这是一个辨识度很高的jsl防护,先埋个坑,后期单独出一期jsl的逆向
点选识别
其他所有流程步骤都分析完毕了,就差点选坐标的获取了。
啰嗦两句,其实现在针对点选方式验证码的解决,比较成熟的方案为机器学习+识别推理,模型训练的方法也比较集中为目标检测+孪生神经网络。目标检测经过长时间的发展改进,现在已经挺成熟了,所以难点不在找字,而在于找对点击顺序。ok,现在方向有了,开干
一、目标检测训练
目的:
识别大图中所有的文字位置
识别小图中需要点击的文字位置
步骤
采集点选验证码的大图和小图
这一步只要拿到了Token
值,直接请求接口getCheckImagePoint
就能拿到了
分别对小图和大图中出现的目标字进行标注
这一步中,我使用的标注工具为labelImg
,labelImg
是一款非常优秀的图片数据标定工具,借助它我们能轻松完成数据集的标注。
点击 Open Dir
,选择验证码存放的路径。点击 Change Save Dir
,选择标注结果存放的路径。点击Pascal VOC
,它会变成YOLO
,保存的结果可以直接拿来用。勾选右侧Use default labtel
,并在输入框填入text
,这样接下来所有标注的文字都会打上text
的标签
按 W
键创建一个标记框,框起来验证区域的字。标注完一张图片后,记得按 Ctrl
+ S
保存。按 D
进入下一张图片,按 A
进入前一张图片。
我们在目标检测阶段只区分是不是字,不区分具体是什么字,所以标签只有一个 text
。
>
> 下方点击顺序的四个字位置是固定的,所以后期我们统一进行自动化标注。
使用YOLOv8训练目标检测模型
使用YOLOv8前,确保你的电脑有N卡,并安装 好了CUDA
+cudnn
相关深度学习的环境,安装完上述环境,再安装Python包ultralytics
即可。
目标检测模型训练配置yaml
# 指定训练集、验证集、测试集路径
train: /path/to/your/train/images
val: /path/to/your/valid/images
test: /path/to/your/test/images
# 有多少个分类
nc: 1
# 分类分别是什么
names: ['text']
目标检测模型训练代码
from ultralytics import YOLO
# 预训练模型下载 https://github.com/ultralytics/ultralytics?tab=readme-ov-file#models
model = YOLO("./model/yolov8n.pt", task="detect")
model.train(data="./dataset/detect.yaml", epochs=20, cache=True, imgsz=320, batch=16, workers=0, device=0)
导出onnx模型
model = YOLO('./path/to/your/train/output/best.pt', task='detect')
model.export(format='onnx', imgsz=320, simplify=True)
模型使用
model = YOLO(model='./path/to/your/model/best.onnx', task='detect')
results = model.predict(source='./path/to/your/test/dataset/images/folder', show=False, save=True, imgsz=500, device=0)
print(f"total_标签名字:{results[0].names}")
def y8_detect_xy(result):
"""
输出坐标信息
:param result:
:return:
"""
cls_xy = list()
cls_dict = result.names
cls_all = result.boxes.cls.tolist()
print(f">>识别结果目标类 {len(cls_all)}个: {cls_all}")
xyxy_all = result.boxes.xyxy.tolist()
for i in range(len(cls_all)):
label_name = cls_dict[int(cls_all[i])]
box_xyxy = xyxy_all[i]
box_mid_xy = [(box_xyxy[0] + box_xyxy[2]) / 2, (box_xyxy[1] + box_xyxy[3]) / 2]
# print(f"目标点{i}: 标签名字: {label_name}, 中心坐标:{box_mid_xy}, xyxy坐标:{box_xyxy}")
cls_xy.append({
"label_id": i, "label_name": label_name,
"box_mid_xy": box_mid_xy, "xyxy": box_xyxy
})
print(f"==识别结果: {cls_xy}==")
return cls_xy
for result in results:
y8_detect_xy(result)
训练效果
二、孪生神经网络训练
目的:
判断待点击字在大图中出现的位置
在大图中按顺序找出小图中的文字
步骤:
进行目标检测,裁剪预测的结果小图
剪裁小图代码
def extract_correct_word():
save_to = '/path/to/save/word'
if not os.path.exists(save_to):
os.mkdir(save_to)
images = glob('./cut/images/*.png')
for image_path in tqdm(images):
results = model.predict(source=image_path, show=False, save=True, imgsz=500, device=0)
num = image_path.split('/')[-1].split('.')[0].split('_')[1]
im = np.asarray(Image.open(image_path).convert("RGB"))
for result in results:
labels = y8_detect_xy(result)
for i, label in enumerate(tqdm(labels)):
x1, y1, x2, y2 = label["xyxy"]
word_im = im[math.floor(y1):math.ceil(y2), math.floor(x1):math.ceil(x2)]
cv2.imwrite(os.path.join(save_to, 'x-{}-{}.png'.format(num, i)), word_im)
人工标注后整理,效果如下
进行孪生神经网络训练
训练代码
预测结果
导出onnx模型
def pth2onnx():
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model_path = r"/path/to/your/train/output/model.pth"
model = Siamese((105, 105, 3))
model.load_state_dict(torch.load(model_path, map_location=device))
model.eval()
dummy_input = [torch.randn(1, 3, 105, 105), torch.randn(1, 3, 105, 105)]
torch.onnx.export(
model, dummy_input, 'weights_self_12071503.onnx', verbose=True, input_names=['x1', 'x2'], output_names=['output']
)
print("Successful!")
三、模型融合使用
目的:
核心代码:
def judge_max_sim(self, cls_xys, img):
targets = [(i["xyxy"], i["box_mid_xy"]) for i in cls_xys if i["label_name"] == "target"]
target_chars = []
# 将提供的顺序,按照x坐标轴从小到大排序,确保识别的字符顺序正确
targets = sorted(targets, key=lambda x: x[0][0])
for xyxy, _ in targets:
target_chars.append(img.crop(xyxy))
texts = [(i["xyxy"], i["box_mid_xy"]) for i in cls_xys if i["label_name"] == "text"]
text_chars = []
for xyxy, _ in texts:
text_chars.append(img.crop(xyxy))
# 获取点击顺序
click_seq_result = []
for m, target_img in enumerate(target_chars):
slys = []
if len(texts) == 0:
break
elif len(texts) == 1:
slys_index = 0
else:
for n, text_img in enumerate(text_chars):
similarity = self.siam_model.predict(target_img, text_img)
slys.append(similarity)
slys_index = slys.index(max(slys))
click_seq_result.append(texts[slys_index][1])
texts.pop(slys_index)
text_chars.pop(slys_index)
if len(texts) == 0:
break
return click_seq_result
def get_xy_seq(self, img_path):
"""
获取点击顺序
:param img_path:
:return:
"""
img = self.open_image(img_path)
# yolov8识别
obj_result = self.yolo_v8_model_predict(img_path)[0]
cls_xys = self.target_detection_xy(obj_result)
# 孪生判断相似度
xy_seq = self.judge_max_sim(cls_xys, img)
return xy_seq
结果验证
免费评分
查看全部评分