BUUCTF 每日打卡 2021-8-1

引言

[2021i春秋云上巅峰赛]MediclImage

题面:
在这里插入图片描述
加密代码如下:

from PIL import Image
from decimal import *
import numpy as np
import random
getcontext().prec = 20

def f1(x):
    # It is based on logistic map in chaotic systems
    # The parameter r takes the largest legal value
    assert(x>=0)
    assert(x<=1)
    ...

def f2(x):
    # same as f1
    ...
def f3(x):
    # same as f1
    ...

def encryptImage(path):
    im = Image.open(path)
    size = im.size
    pic  = np.array(im) 
    im.close()
    r1 = Decimal('0.478706063089473894123')
    r2 = Decimal('0.613494245341234672318')
    r3 = Decimal('0.946365754637812381837')
    w,h = size
    for i in range(200):
        r1 = f1(r1)
        r2 = f2(r2)
        r3 = f3(r3)
    const = 10**14
    for x in range(w):
        for y in range(h):
            x1 = int(round(const*r1))%w
            y1 = int(round(const*r2))%h
            r1 = f1(r1)
            r2 = f2(r2)
            tmp = pic[y,x]
            pic[y,x] = pic[y1,x1]
            pic[y1,x1] = tmp
    p0 = random.randint(100,104)
    c0 = random.randint(200,204)
    config = (p0,c0)
    for x in range(w):
        for y in range(h):
            k = int(round(const*r3))%256
            k = bin(k)[2:].ljust(8,'0')
            k = int(k[p0%8:]+k[:p0%8],2)
            r3 = f3(r3)

            p0 = pic[y,x]
            c0 = k^((k+p0)%256)^c0
            pic[y,x] = c0

    return pic,size,config
def outputImage(path,pic,size):
    im = Image.new('P', size,'white')
    pixels = im.load()
    for i in range(im.size[0]):
        for j in range(im.size[1]):
            pixels[i,j] = (int(pic[j][i]))

    im.save(path)


def decryptImage(pic,size,config):
    .....
    
enc_img = 'flag.bmp'
out_im = 'flag_enc.bmp'

pic,size,_ = encryptImage(enc_img)
outputImage(out_im,pic,size)

看起来很复杂,而且函数f1(x)f2(x)f3(x)是未知的(虽然三个函数是一样的,不妨都记为f(x))
根据注释内容搜了一下Logistic map(单峰映象)
在这里插入图片描述
又搜了一下针对医学影像的加密系统,里面也提到了一个Logistic映射
基本上可以确定f(x)=rx(1-x),关键是确定这个r
wiki里面也提到了r不同情况下x的变化趋势:
在这里插入图片描述
注释中说是在混沌系统中,可以排除r小于3的情况
比较常见也是最初研究的是r=4的情况,那姑且认为r=4
再看加密函数encryptImage(path),分成两段看
先看第一段:

    im = Image.open(path)
    size = im.size
    pic  = np.array(im) 
    im.close()
    r1 = Decimal('0.478706063089473894123')
    r2 = Decimal('0.613494245341234672318')
    r3 = Decimal('0.946365754637812381837')
    w,h = size
    for i in range(200):
        r1 = f1(r1)
        r2 = f2(r2)
        r3 = f3(r3)
    const = 10**14
    for x in range(w):
        for y in range(h):
            x1 = int(round(const*r1))%w
            y1 = int(round(const*r2))%h
            r1 = f1(r1)
            r2 = f2(r2)
            tmp = pic[y,x]
            pic[y,x] = pic[y1,x1]
            pic[y1,x1] = tmp

先导入图片,这没什么好说的
然后r1,r2,r3经过200次f(x)后和常量const生成新的坐标,对原来的图片像素进行移位
要解密的话,只要存储原来坐标的列表或者矩阵,然后换回来就行
再看第二段:

    p0 = random.randint(100,104)
    c0 = random.randint(200,204)
    config = (p0,c0)
    for x in range(w):
        for y in range(h):
            k = int(round(const*r3))%256
            k = bin(k)[2:].ljust(8,'0')
            k = int(k[p0%8:]+k[:p0%8],2)
            r3 = f3(r3)

            p0 = pic[y,x]
            c0 = k^((k+p0)%256)^c0
            pic[y,x] = c0

先随机生成了一个config = (p0,c0),不过幸运的是p0和c0的范围都在random.randint(100,104),遍历config的话也只要25种情况
后面就是对每个像素的加密,也可以分成两段
前一段:

k = int(round(const*r3))%256
k = bin(k)[2:].ljust(8,'0')
k = int(k[p0%8:]+k[:p0%8],2)
r3 = f3(r3)
p0 = pic[y,x]

就是搞了个k,解密的时候也只要把每一次的k存储起来就行
后一段:

p0 = pic[y,x]
c0 = k^((k+p0)%256)^c0
pic[y,x] = c0

这里把之前生成的p0和c0给换了,也就是pic[y,x] = c0 = k ^ ((k+p0)%256) ^ c0,而这里的p0是未加密时该点的像素值,这里的c0是加密过的前面一点的像素值
解密的时候只要将加密后的像素值与前一点的像素值还有之前储存的k的值作异或就可以得到(k+p0)%256,记为k_p
又因为k和p0都是小于等于256的,为了得到p0,也就是原来的像素值,只要

k_p -= k
if k_p < 0:
	k_p += 256

得到的k_p就是原来的像素值
分析完毕,完整的解密代码如下:

from PIL import Image
import numpy as np
from decimal import *
getcontext().prec = 20

def f(x):
    # It is based on logistic map in chaotic systems
    # The parameter r takes the largest legal value
    assert (x >= 0)
    assert (x <= 1)
    r = 4
    x = r * x * (1 - x)
    return x

im = Image.open('flag_enc.bmp')
pixels = im.load()
size = im.size
w, h = size
print(size)
# print(np.array(im))
pic = np.zeros((h, w))
const = 10 ** 14
r1 = Decimal('0.478706063089473894123')
r2 = Decimal('0.613494245341234672318')
r3 = Decimal('0.946365754637812381837')
for i in range(im.size[0]):
    for j in range(im.size[1]):
        pic[j][i] = pixels[i, j]
print(pic)

for i in range(200):
    r1 = f(r1)
    r2 = f(r2)
    r3 = f(r3)
p0 = range(100, 105)
c0 = range(200, 205)
config = []
# 列出(p0, c0)的所有情况
for p in p0:
    for c in c0:
        config.append((p, c))

# 记录原先的坐标x1, y1
list_x1 = np.zeros((h, w))
list_y1 = np.zeros((h, w))
for x in range(w):
    for y in range(h):
        x1 = int(round(const * r1)) % w
        y1 = int(round(const * r2)) % h
        list_x1[y][x] = x1
        list_y1[y][x] = y1
        r1 = f(r1)
        r2 = f(r2)

list_k = []
for conf in config:
    arrk = np.zeros((h, w))
    k = 0
    p0 = conf[0]
    c0 = conf[1]
    for x in range(w):
        for y in range(h):
            k = int(round(const * r3)) % 256
            k = bin(k)[2:].ljust(8, '0')
            k = int(k[p0 % 8:] + k[:p0 % 8], 2)
            r3 = f(r3)
            p0 = int(pic[y, x])
            arrk[y][x] = k
    list_k.append(arrk)
print(list_k)

list_p = []
for conf in config:
    x1 = 0
    y1 = 0
    picture = pic.copy()
    arrk = list_k[config.index(conf)]
    p0 = conf[0]
    c0 = conf[1]
    for x in range(w-1, -1, -1):
        for y in range(h-1, -1, -1):
            k = int(arrk[y][x])
            p0 = pic[y][x]
            if (y-1) >= 0:
                c0 = int(pic[y-1][x])
            elif (y - 1) < 0 and (x-1) < 0:
                pass
            else:
                c0 = int(pic[h-1][x-1])

            k_p = k ^ (int(pic[y][x])) ^ c0
            k_p -= k
            if k_p < 0:
                k_p += 256
            picture[y][x] = k_p

    for x in range(w - 1, -1, -1):
        for y in range(h - 1, -1, -1):
            x1 = int(list_x1[y][x])
            y1 = int(list_y1[y][x])
            tmp = picture[y1][x1]
            picture[y1][x1] = picture[y][x]
            picture[y][x] = tmp
    list_p.append(picture)
    print(picture)

for k in range(len(list_p)):
    im = Image.new('P', size, 'white')
    pixels = im.load()
    for i in range(im.size[0]):
        for j in range(im.size[1]):
            pixels[i, j] = (int(list_p[k][j][i]))
    im.save('p' + str(k) + '.bmp')

最后得到25张图片,除了第一张图片,都能看到flag
挑了一张比较清晰的:
在这里插入图片描述
看不清的话可以和别的比对着看

结语

还有一道crtrsa比赛的时候没有做出来,后来在badm0nkey前辈的指导下解出来了,留着明天讲
感谢Phoenix大佬帮我指出错误
希望继续坚持

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值