吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7363|回复: 36
上一主题 下一主题
收起左侧

[Web逆向] 顶象滑块验证码纯算逆向分析

  [复制链接]
跳转到指定楼层
楼主
LiSAimer 发表于 2025-8-13 16:30 回帖奖励

声明

本文章中所有内容仅供学习交流使用,不用于其他任何目的,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!若有侵权,请联系作者删除。

逆向目标

目标网站:
aHR0cHM6Ly93d3cuZGluZ3hpYW5nLWluYy5jb20vYnVzaW5lc3MvY2FwdGNoYQ==
关键要点:图像撕裂还原、轨迹、参数【lid, c, ac】

抓包分析

本篇文章以官网demo 5.1.53 版本进行分析,需要注意官网关键js文件每天会动态更新两次

进入网页,按F12打开调试窗口后刷新页面,建议每次都清理一下缓存或者直接使用无痕模式

刷新页面后定位到demo位置,点击滑动拼图查看发送请求

接口 a 请求载荷

这里只需要注意aid的生成

aid = 'dx-' + str(int(time.time() * 1000)) + '-' + str(random.randint(10000000, 99999999)) + '-3'

接口 a 响应内容

p1:背景图地址
p2:滑块图地址
sid 和 y 后面需要用到

当我们滑动滑块完成验证后会发送一个v1接口的请求

提示:本文截图中某些值可能和之前截图中的不一致,以文字说明为准,图知其意便可

ac:包含轨迹的加密参数
c:c1接口获取需要逆向
sid:a接口响应中获取
aid:这里aid要与a接口的aid一致
x:滑动距离
y:a接口响应中获取

v1接口响应中的token值是我们本次逆向的最终目标

流程梳理

1、第一次请求c1接口获取lid
2、第二次请求c1接口获取data值
3、请求a接口获取图片地址以及一些关键参数
4、请求v1接口完成验证获取token

图像还原

老样子打上canvas断点后点击验证滑块,断到如下图位置

分析入参
n:canvas对象
t:img对象
i:图片高度
e:图片高度
r:32位数组

分析代码
1、将一张图像完整绘制到canvas上
2、然后根据数组r的长度将图像水平分割成多个切片
3、再按照数组r的顺序重新排列这些切片绘制到canvas上

知道逻辑了那么就需要找到关键32位数组是如何生成的
继续往上跟栈找到生成位置

函数sn算法还原,传入a接口p1的值也就是背景图地址

def get_arr_32(self, img_url):
    n = img_url.split("/")[-1].split(".")[0]
    c = []
    for i in range(len(n)):
        u = ord(n[i])
        while u % 32 in c:
            u += 1
        c.append(u % 32)
    return c

图像还原算法

def draw_slices_from_array(self, image_content, output_path, arr):
    src_img = Image.open(BytesIO(image_content))
    src_width, src_height = src_img.size
    canvas_width = 32 * 12
    canvas_height = 200
    dest_img = Image.new("RGB", (canvas_width, canvas_height), "white")
    for index, x in enumerate(arr):
        r = x * 12
        if r + 12 > src_width:
            continue
        cropped = src_img.crop((r, 0, r + 12, 200))
        dest_img.paste(cropped, (index * 12, 0))
    dest_img.save(output_path)

还原结果

C 值分析

对v1接口的c值进行搜索后发现是在c1接口返回的
c1接口请求了两次
第一次是get请求,headers中有个短的加密参数Param
返回一个lid

第二次是post请求,表单中有个长的加密参数Param
返回一个data值也就是我们要的 c 值

第一次c1请求的 Param 分析

打上c1的xhr断点清缓存刷新页面
往上跟栈可定位到其生成位置在一个index.js文件中
注意,它有两个index.js文件,咱分析的这个是带?_t=***的

参数除lid外都是固定的
lid生成代码

l = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
lid = str(int(time.time() * 1000)) + ''.join(random.choice(l) for _ in range(32))

进入加密函数后可以看到是个控制流。

整个index.js文件也是存在大量的混淆,为方便读者阅读我这里用ast还原一下,代码就不公布了,写的比较渣,github上也有开源的。简单还原了一下大数组和一些拼接以及控制流这些,有兴趣的还是去找蔡老板进修一下

还原后看起来很清晰了,直接抠算法都很简单了

第二次c1请求的 Param 分析

和第一次一样的分析方式
或者直接断点在上面的加密位置上,两次的加密方法都是同一个
往上跟栈到如下位置

这次要加密的参数更多,所以加密后的Param长度也就更长了

ac 参数分析

给v1打上xhr断点,滑动滑块验证
跟栈跟栈
定位到一个Promise
代码往上看可以看到ac了,给打上断点再定位过去

可以看到在这里用getUA方法提取z里的ua的值,ua就是ac,早已生成了
聪明的我们往下看可以看到有个reload()方法,进去看看

进入reload方法后又是一个新的js文件greenseer.js
关键的算法都在这个文件中代码每天动态更新两次

又是大量的混淆,混淆方式和index.js一样,再解混淆方便各位阅读

清晰了,又可以愉快地分析了
分析reload方法可知这是在初始化z里的参数
最后再调用start方法
进start再看看

都是一些检测然后进行加密的流程
加密也都是一些简单的运算直接算法拿下就行

getTM:tm时间的加密
getBR:系统、浏览器版本的加密
getLO:document.referrer、location.href加密
getCF:随机数加密
getDI:判断window.top是否等于window.self以及window窗口宽高
getEM:自动化特征检测
getJSV:js版本号的加密
getTK:sid加密
getSC:window.screen加密
bindDomEvents:监听轨迹加密

所有方法最终都会调用app这个方法

进入app方法中可以看到最终ua的生成逻辑
将加密的参数追加到_ua中再将_ua经过btoa方法得到ua

进入bindDomEvents方法前已经生成了一个短的ua了
下面就是将轨迹加进去了

滑动距离识别随便找个开源ocr或者用cv2,注意图像的缩放
轨迹检测也不严格,随便网上找个或者模拟写个和浏览器上差不多的就行
轨迹算法

def get_track(self, distance):
    def __ease_out_expo(sep):
        if sep == 1:
            return1
        else:
            return1 - math.pow(2, -10 * sep)

    def random_randint(min, max):
        range_val = max - min
        rand = random.random()
        num = min + round(rand * range_val)
        return int(num)

    slide_track = [[755, 325, 3526]]
    count = 30 + distance // 2
    t = random_randint(50, 100)
    _x = 0

    for i in range(1, count + 1):
        sep = i / count
        x = round(__ease_out_expo(sep) * distance)
        t += random_randint(30, 50)

        if x == _x:
            continue

        slide_track.append([755 + x, random_randint(320, 330), 3526 + t])
        _x = x

    return slide_track

轨迹加密共有三处
其中1和2不是强校验可以不处理不追加进ua
1、点击事件轨迹,将点击验证出现滑块图前的点击轨迹加密进去
2、移动事件轨迹,将点击验证出现滑块图前的移动轨迹加密进去
3、移动事件轨迹,将滑动滑块时的轨迹加密进去

这里只分析移动滑块轨迹的加密逻辑
进入recordSA方法
分析可知这里获取了pageX、pageY、轨迹点时间,加密后存入_sa数组

需要注意,滑动距离是有偏移计算的

recordSA方法之后需要进入sendSA方法处理_sa数组

sendSA方法就是遍历_sa数组调用app更新ua

sendSA完事后进入最后的sendTemp方法

传入一个xpath、x距离、y是获取图片地址的a接口响应中的参数
获取html标签中的一些信息再拼接上传入的参数进行加密更新ua

现在的ua就是我们需要的最终结果了
以上就是全部ac的逻辑了

结果验证

算法不难但建议找个第三方固定js的网站去练习
官网每天早上10点和晚上7点更新js(实际会延迟1个小时)
建议先用补环境方法理解全部过程后再抠算法

免费评分

参与人数 13吾爱币 +13 热心值 +10 收起 理由
jiajia005200 + 1 牛哇
lucifer11 + 1 + 1 谢谢@Thanks!
yuchen123 + 1 + 1 用心讨论,共获提升!
fiscivaj + 1 鼓励转贴优秀软件安全工具和文档!
JiangtaoChiu + 1 + 1 谢谢@Thanks!
anyiy + 1 + 1 谢谢@Thanks!
silenter6speake + 1 热心回复!
KOCBT + 1 + 1 用心讨论,共获提升!
fengbolee + 2 用心讨论,共获提升!
allspark + 1 + 1 用心讨论,共获提升!
user23456 + 1 + 1 谢谢@Thanks!
liuxuming3303 + 1 + 1 谢谢@Thanks!
helian147 + 1 + 1 热心回复!

查看全部评分

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

推荐
tian214216 发表于 2025-8-17 18:59
不明觉厉!!!
推荐
guxing666 发表于 2026-3-31 21:00
跟着步骤走,完成了算法的还原,但是这个每次更新加密的算法都不一样,楼主是有什么好办法解决的吗?
3#
131486352 发表于 2025-8-14 16:13
4#
loading2025 发表于 2025-8-15 01:24
第一次看到有人逆向这
5#
kongyueshang 发表于 2025-8-16 18:56
66666666666666666666666
6#
ljl9090 发表于 2025-8-16 21:36
66666666666666
7#
tianmiao 发表于 2025-8-17 10:38
大佬大佬upup牛
8#
想喝饮料 发表于 2025-8-17 19:11
大佬!!!膜拜666
9#
Xuan688 发表于 2025-8-20 09:22
感谢大佬分享
10#
bighero006 发表于 2025-8-20 09:53
牛,开始学习
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2026-4-15 00:04

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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