吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5528|回复: 53
收起左侧

[Web逆向] 某备案查询网站 汉字点选逆向分析

  [复制链接]
li63033 发表于 2023-12-24 20:25
本帖最后由 li63033 于 2024-3-5 14:35 编辑

声明


本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!

本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请联系作者立即删除!

目标


目标:点选人机验证逆向分析

网址:aHR0cHM6Ly9iZWlhbi5taWl0Lmdvdi5jbi8jL0ludGVncmF0ZWQvaW5kZXg=

流程分析


进入页面前,先打开F12开发者工具

  1. 上来就是个521大礼包,朋友们这可太熟悉了,妥妥的jsl,现在这东西逆向真的已经烂大街了(不排除有刚入坑的小伙伴,后期单独补上)

    1.png

  2. 未进行查询验证前,Network中我们会看到一个/auth接口进行认证操作,请求传递了两个参数。

    • authKey:时间戳加盐后的MD5,需要逆向得到
    • timeStamp:当前时间戳

    2.png

    接口返回了后续请求中,header需要携带的token

    3.png

  3. 点击查询验证后,出现了我们今天分析的主角:文字点选验证码,加载接口为/getCheckImagePoint,传递了一个参数

    • clientUid:设备id,需要逆向得到

      4.png

    接口返回了点选验证码的详细信息

    • bigImage:点选验证码上方的大图base64

    • secretKey:加密坐标时的密钥

    • smallImage:点选验证码下方的小图base64

    • uuid:此验证码的id

    • wordCount:需要点选的文字数量

      5.png

  4. 点选完毕后,进行验证的接口为/checkImage,传递了相关点选的数据

    • clientUid:3中生成的clientUid

    • pointJson:点击坐标密文,需要逆向得到

    • secretKey:加密密钥

    • token:加载接口返回的验证码id

      6.png

    未通过验证,会刷新验证码,验证返回的数据如下

    7.png

    通过验证,会跳转查询请求,验证返回数据中会多一个sign字段

    8.png

  5. 查询请求接口为/queryByCondition,需要再请求头中携带四个正确的字段,才能够请求成功

    • Cookie:jsl生成的cookie,需要逆向得到

    • Sign:点选验证码通过后,返回的sign

    • Token:第一次进入系统,auth接口的返回值

    • Uuid:点选验证码加载时的uuid

      9.png

    参数正确,返回的请求数据如下

    10.png

逆向分析


1. authKey参数

跟到这个参数很简单,直接全局搜就能看到了

11.png

2. clientUid参数

这个参数也很简单,还是全局搜,我们会发现是已经生成好存在了localstorage中

12.png

所以我们干脆直接改为全局搜localStorage.getItem,就能定位到生成&存储的位置了

13.png

3. pointJson参数

仍然是全局搜,很快就能定位到参数生成的位置,入口为h函数,跟进去我们就能看到,是个AES加密,密钥为接口返回的secretKey,加密模式为ECB,填充模式为Pkcs7

14.png

4. Cookie中的__jsluid_s

这是一个辨识度很高的jsl防护,先埋个坑,后期单独出一期jsl的逆向

点选识别


其他所有流程步骤都分析完毕了,就差点选坐标的获取了。

啰嗦两句,其实现在针对点选方式验证码的解决,比较成熟的方案为机器学习+识别推理,模型训练的方法也比较集中为目标检测+孪生神经网络。目标检测经过长时间的发展改进,现在已经挺成熟了,所以难点不在找字,而在于找对点击顺序。ok,现在方向有了,开干

一、目标检测训练

目的:

  • 识别大图中所有的文字位置
  • 识别小图中需要点击的文字位置

步骤

  1. 采集点选验证码的大图和小图

    这一步只要拿到了Token值,直接请求接口getCheckImagePoint就能拿到了

    15.png

  2. 分别对小图和大图中出现的目标字进行标注

    这一步中,我使用的标注工具为labelImglabelImg是一款非常优秀的图片数据标定工具,借助它我们能轻松完成数据集的标注。

    点击 Open Dir ,选择验证码存放的路径。点击 Change Save Dir,选择标注结果存放的路径。点击Pascal VOC,它会变成YOLO,保存的结果可以直接拿来用。勾选右侧Use default labtel,并在输入框填入text,这样接下来所有标注的文字都会打上text的标签

    16.png

    W 键创建一个标记框,框起来验证区域的字。标注完一张图片后,记得按 Ctrl + S 保存。按 D 进入下一张图片,按 A 进入前一张图片。

    我们在目标检测阶段只区分是不是字,不区分具体是什么字,所以标签只有一个 text
    >
    > 下方点击顺序的四个字位置是固定的,所以后期我们统一进行自动化标注。

    17.png

  3. 使用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)

    训练效果

    18.png

二、孪生神经网络训练

目的:

  • 判断待点击字在大图中出现的位置
  • 在大图中按顺序找出小图中的文字

步骤:

  1. 进行目标检测,裁剪预测的结果小图

    剪裁小图代码

    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)

    人工标注后整理,效果如下

    19.png

  2. 进行孪生神经网络训练

    训练代码

    20.png

    预测结果

    21.png

    导出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

结果验证


22.png

免费评分

参与人数 17吾爱币 +17 热心值 +15 收起 理由
笙若 + 1 + 1 谢谢@Thanks!
victim + 1 谢谢@Thanks!
procurve + 1 + 1 谢谢@Thanks!
三滑稽甲苯 + 2 + 1 用心讨论,共获提升!
veddy + 1 + 1 用心讨论,共获提升!
xianjun251 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
munachar + 1 我很赞同!
外酥内嫩 + 1 + 1 学习到了神经网络的知识
onething + 1 + 1 热心回复!
zuishi + 1 + 1 谢谢@Thanks!
我是sss + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Wyiyun777 + 1 + 1 我很赞同!
小菜鸟一枚 + 1 + 1 666
tianluo + 1 + 1 用心讨论,共获提升!
allspark + 1 + 1 用心讨论,共获提升!
Ram9943 + 1 + 1 666
dudupangle + 1 不明觉厉

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

goblack 发表于 2023-12-25 12:53
前排留名。
备案查询接口倒是容易找到,如果是部分行业,还能简单的正规取得官方接口对接(早几年在取得资质的时候就有要求对接联调)。

本文的要点是过验证。
我没用机器学习。类似的验证码用的是色彩。先判断背景色,再寻找在多大的范围内出现了连续的单色,然后对比得到位置。
相对来说还是机器学习最终更简单粗暴。
就类似动态识别号码,物品动态识别,最终都是落入机器学习模糊计算的流程了。。人工算法取巧既复杂,又容易受到干扰。机器学习在有一定数据量的情况下,识别验证码怕是比人工强更多
yjn866y 发表于 2023-12-25 14:46
yuband 发表于 2023-12-25 16:19
如果能拿到对应服务器大部分的验证图片,训练结果应该也是可靠的,不知道接口有没有验证码请求限制
viply 发表于 2023-12-25 16:52
好家伙,都用上yolo来识别了
daitoudage 发表于 2023-12-25 20:59
哈哈哈感谢楼主分享啊啊啊
moka518 发表于 2023-12-26 00:58
高级啊,能把源码发出来不
soughing 发表于 2023-12-26 07:18
厉害厉害,学习学习
Quincy379 发表于 2023-12-26 08:30
学到了,感谢分享!!!
zyzoicq 发表于 2023-12-26 08:45
高手啊~~学习了,没准哪天就用到了呢~~
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-22 20:13

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表