【python 逆向分析还原图片】逆向分析一下顶象的滑块和点选的图片还原,仅供学习参考!!

文章日期:2025.04.26

使用工具:python3.12.7

本章知识:逆向分析还原顶象的滑块背景图和点选背景图

jsv: 5.1.49

version:2.5.1 (window.core.version)

文章难度:简单

文章全程已做去敏处理!!!  【需要做的可联系我】 

AES解密处理(直接解密即可)(crypto-js.js 标准算法):​​​​​​在线AES加解密工具

注意:仅供学习!!仅供交流!!仅供测试!!

文章末尾附上源码,如果用不了了,可能是官方更新了,请谅解!!!

先看个小视频

1、打开某某网站(使用文章开头的AES在线工具解密): UGXl3oWuv0ITRPtnTNRRSJ2LR0XN9STAMTBHcK5qBmY=

2、打开网站后,使用选择账号密码登录,然后随便输入测试参数后,点击登录,会看到弹出了这个窗口,我们先分析滑块,如果出现的是点选,我们就不停的刷新,直到出现滑块为止

3、我们找到事件监听器,选择画布断点,然后刷新滑块,当滑块的图片进行渲染的时候,是需要调用画布去还原图片的,所以我们让他断住后,我们就可以知道他是怎么还原的,他的算法是什么,我们都可以去分析

4、断住后,我们需要在这里确认一下是不是滑块,如果不是滑块,那我们就进行刷新,直到出现滑块为止,因为他的点选图片和滑块的图片大小不一样,会影响我们分析的结果,所以我们就先固定分析一种类型,那就是从滑块先入手。

5、如果是滑块图片,那我们就回到已经断住的地方,我们开始逐步分析,他有流程的,【0132】,【01】就是用来创建并设置画布的大小,【3】就是计算混淆的背景图里的单个碎片的宽度,【2】是从混淆的背景图里抽取碎片并拼接在一起。可以大致看一下流程

6、然后来分析一下这个混淆的图片,我们要知道混淆的图片的宽高,包括他是多少层碎片,如下图所示,这个是单层的碎片,这种相对简单些

7、我们对这个【2】打上断点,跟过来,接下来我们单步进去看看是怎么回事

8、单步发现进不去,我们就手动进去这个【o】参数,然后打断点,进去

9、我们打完断点后,进来发现他运算的很简单,可以看一下我下面的图,有点乱,将就一下,然后我们现在知道了每个参数是怎么来的,那我们就用python去模拟一下。

【定值】 = 一串数组,暂时先写死,32位的

【碎片的宽度】 = 混淆图片的宽度 / 定值的长度

【x轴的初始坐标】 = 遍历定值 * 碎片的宽度

【x轴位于初始坐标的右侧坐标(宽度)】 = x轴的初始坐标 + 碎片的宽度

【y轴的初始坐标】 = 0 (这个直接写死)

【y轴位于初始坐标的底部坐标(高度)】 = 混淆图片的高度 (切记这个不能写死,有些图的大小不一样)

10、python模拟了一下,如果没有看懂我上面的讲解,可以结合我下面的这个python代码进行了解分析。

11、我们运行一下,看看效果是什么样的。效果很成功,还原了90%,还原后的图片有一小块没有还原

12、为了方便接下来是视觉展示效果,我更换了滑块图片

13、嘿,他缺少的那一块拼图,就是在最后面,然后我量了一下他最后一块碎片的初始坐标,是384,那么缺少的最后一块的定值应该是【384 / 12 = 32】,然后经过多个测试,发现他所有图片最后一块的碎片的定值都是32,那就妥当了

【x轴的初始坐标】 = 遍历定值 * 碎片的宽度

【定值】 = x轴的初始坐标 / 碎片的宽度(384 / 12 = 32)

14、修改python代码后,我们再次运行,发现已经成功补上了99%,还差1%没补上,怎么办,其实很简单,我们只需要在最后一步,也就是定值为32时,把碎片的宽度改高一点即可

15、我们把碎片的宽度修改为16,切记,只能在裁切的地方修改,其他地方不用改,前面会裁切多余,但会被覆盖的,唯独最后一块碎片,他的宽是16,是唯一不会被覆盖,因为遍历定值已经结束了,没有碎片去覆盖他了。

 16、还原图片到此就结束了,接下来我们要去知道他的定值是怎么来的,因为我看了他的接口,接口是没有返回定值的数据信息,所以我敢肯定他的定值一定是本地通过什么参数生成的。废话不多说,我们直接去分析

17、【定值的生成】我们依然是通过画布去断住,然后我们在这个调用函数的起始位置打断点,然后刷新滑块(此时不用去管是滑块还是点选,因为他们的定值生成都是用的同一种方法)

18、【定值的生成】刷新滑块后,断住了,然后我们打开闭包,可以看到定值是已经生成了,而且堆栈的信息都出来了,可以进行调试了,那我们就向上跟栈,看看哪里有可疑之处,就打断点排查。

19、【定值的生成】经过排查,发现他的生成位置,我们直接打上断点,然后刷新滑块

20、【定值的生成】进来后,我们发现他其实是将滑块的链接里的hash提取了出来,然后用【H】函数生成的定值,这就简单了,我们直接进到【H】方法里

21、【定值的生成】进来后,发现他这个计算方式很简单,就是将hash字符串一个一个都转为ASCII码,然后再用ASCII码去计算结果,得出结果后,要先检测这个结果有没有出现过,如果出现过这个结果,那么就需要将ASCII值+1,然后再进行计算,然后再进行检测,如果还是重复,那就重复刚刚的+1步骤,如果不重复,则添加到列表内。接下来我用python给大家模拟一下

22、【定值的生成】用python模拟出来的效果就是这样的,可以看注释,比较详细点,这个不复杂。运算后得出的定值和官方的一模一样,这就成功了

 23、我把python代码进行了修改,看下面的展示示例

24、【点选的背景图还原】这个我就不过多阐述了,答案都已经出来了。滑块和点选用的都是同一种算法,只是过程中容易混淆,所以一开始让大家固定选择滑块去分析,就是为了不被点选的参数所混淆,点选的图片大小和碎片宽度都是不一样的,这一点在做分析的时候容易出现问题。

现在已经把整个流程都对接完成了,参数的生成都没有问题了。给大家看一下点选的还原。

【附上完整代码】 

from PIL import Image
def dingxiang(file_path, save_file_path):
    """
    file_path:混淆的图片路径
    save_file_path:要保存的图片路径
    """
    def o(hash_value):
        '''
        网站:https://user.dingxiang-inc.com/
        通过hash值计算出回复滑块的定值
        '''

        def get_unique_num(i, used_numbers):
            """递归"""
            # 将ASCII码取模32 运算
            num = i % 32
            # 检测运算后的值是否已经出现过了,有没有重复出现,如果没有重复出现,则返回这个定值
            if num not in used_numbers:
                used_numbers.add(num)
                return num
            # 运算后的值如果已经出现过了,那么就需要将ASCII值+1,然后再次调用自身去运算,直到返回一个不重复的值为止(递归)
            return get_unique_num(i + 1, used_numbers)

        # 用于检测是否已经存在过了
        used_numbers = set()
        # 存储最终的定值
        data = []
        # 遍历hash字符串
        for char in hash_value:
            # 将字符转为ASCII码
            i = ord(char)
            # 进入递归,获取定值
            unique_num = get_unique_num(i, used_numbers)
            # 将定值存储到列表内
            data.append(unique_num)
        return data
    hash_data = file_path.split('/')[-1].split('.')[0]
    # 读取 滑块混淆图片
    image = Image.open(file_path)
    # 获取 混淆图片 的 宽高
    width, height = image.size
    print('[混淆图片][宽高] -> ', width, height)
    # 碎片的宽度 = 混淆图片的宽度 // 定值的长度
    s = width // 32
    print('碎片的宽度 -> ', s)

    # 创建新的空白图片(相当于画布)宽高要和混淆的图片保持一致
    new_image = Image.new('RGBA', (width, height))

    # 定值 数组列表,可以先临时写死。 注意:如果混淆的图片更改了,这个定值也要修改,这个定值是动态的,不是静态的
    o = o(hash_data) + [32]
    print('定值 -> ', o)
    # 新画布的初始坐标点
    k = 0
    # 遍历定值列表
    for _ in o:
        # 【x轴】初始坐标
        c = _ * s
        # 【y轴】初始坐标 0 固定写死的
        # 【x轴】位于初始坐标的右侧坐标(宽度) = c + s
        # 【y轴】位于初始坐标的底部坐标 = height (和混淆的图片的高度保持一致)
        image2 = image.crop((c, 0, c + 16, height))  # 裁切小碎片
        # 将裁切的碎片按顺序一个一个的存储到新建的画布中
        new_image.paste(image2, (k, 0))
        # 更新 新画布的初始坐标点 我们存储的碎片的宽度是s,那我们就需要把坐标+s,那么我们下次在进行存储就不会覆盖原来的碎片
        k += s
    # 将数据写入buffered里
    new_image.save(save_file_path, format="PNG")

dingxiang(file_path='e9ee618000f54c34bcae598f16cf3814.webp',
          save_file_path='1.jpg')

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小木_.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值