恢复黑白图片
buuoj 静静听这么好听的歌
由于网上wp只给了代码而且函数非常吓人,因此我写了一个新手版的wp。
以下是源码,注释是我自己加的。(因为不是很熟悉matlab代码因此特意详细分析了这一道题目)。代码逻辑是什么呢?非常简单。
- 先打开BGM.wav文件然后再打开img文件,通过设置一个flag值(这里是44,也可以任意修改,当flag值为5时会破坏文件头结构(不过也没什么关系,反正隐写后文件都打不开),因此一般设置稍高一点)。
- 当拿到img的二维数组后,将其转为一维数组wi。
- 把wi数组通过for循环写入BGM.wav文件中。
加密脚本:
fid=fopen('BGM.wav','rb');
%此处的inf表示无穷大,表示取尽wav文件。
a=fread(fid,inf,'uchar');
%为什么这里是44?只是一个标志性数字可以当做hint使用.
n=length(a)-44;
fclose(fid);
img=imread('flag.bmp');
[row,col]=size(img);
%二维数组转换为一维数组
%388*100的二维数组img被转换为38800*1的一维数组wi
wi=img(:);
if row*col>n
error('文件太小');
end
%watermarkedaudio即为隐写文件(文件大小有限制)
watermarkedaudio=a;
%需要lsb隐写的长度
watermarklength=row*col;
%循环插入低位。不使用文件的前44个字节。
for k=1:row*col
watermarkedaudio(44+k)=bitset(watermarkedaudio(44+k),1,wi(k));
end
figure;
subplot(2,1,1);plot(a);
subplot(2,1,2);plot(watermarkedaudio);
%将修改后的字节写入wav文件
fid = fopen('2.wav', 'wb');
fwrite(fid,watermarkedaudio,'uchar');
fclose(fid);
那么我们来思考一下,当我们已经成功拿到了该wav文件的加密脚本,对于解密脚本该如何编写呢?
首先读取该文件。对于标志位44我们要循环读取对应的低位数字并还原为img数组。那么要完成这个操作我们需要数组长度,也就是上面的38800。我们该如何得到宽高呢?
属实是一个脑洞呢。然后需要去爆破高度值或者猜测。
这里我们就假设已经知道了宽高为388*100吧。
然后我们去读取45-38845的低位值并转换为二维数组。函数:
function A=convert(oi,row,col)
%创建一个二维空数组
A = zeros(row,col);
for i=1:row
for j=1:col
A(i,j) = oi((i-1)*col+j);
end
end
end
那么现在就开始编写解密脚本吧。
clc;
clear;
row = 388;
col = 100;
marklength = row*col;
imgData = [0]*marklength;
wavFile = fopen('静静听这么好听的歌.wav','rb');
data = fread(wavFile,inf,'uchar');
for i=45:marklength+45
imgData(i-44) = bitget(data(i),1);
end
%拿到一维数组后进行转换
img = convert(imgData,row,col);
imwrite(img,'flag.bmp');
imshow('flag.bmp');
title('extracted watermark');
同时可以看到生成了flag.bmp文件了。
这里保留一个疑问?我们这里输出的是一幅黑白图。那如果是一幅彩色图的话我们这种解密方法还是可以使用吗?
关键点在该语句。
imgData(i-44) = bitget(data(i),1);
我们首先将data(i)转为二进制数字然后取1位(最后一位)。那么需要考虑什么呢?若我们的wav文件中存在大量FF的hex代码时,我们是无法使用该隐写方法的。同时在此条件下我们只能写黑白图片。
https://blog.csdn.net/zrools/article/details/50630780
彩色转黑白图
对于这道题的学习不止于此。当我考虑是否能够编写出一个隐写彩色图的方法时。
编写了一个能把彩色图变为黑白图的脚本。
(调整255为其他值可以调整色度)
clc;
clear;
img = imread('test.png');
[row,col] = size(img);
for i=1:row
for j=1:col
if img(i,j)~=0
%调整255为其他值可以调整色度
img(i,j)=255;
end
end
end
imwrite(img,"test-output.bmp");
恢复RGB图片思路
matlab读取RGB图片代码。
test.png是一张420*560的彩色图片,我们用于实验。
[x,img] = imread('test.png');
imshow(x,img);
那么x和img分别是什么呢?
注意到x是420*560的,很明显这是我们的像素点,而这个数值代表着索引。
可以看到img数组是一个256*3的数组,是RGB数组,通过x的索引对应相应的RGB值。拿到对应的RGB值后我们就能恢复我们的彩色图像了。
那么现在思路很清晰了。如果我们要进行彩色图像的隐写,只要需要两个文件。一个是索引文件,一个是RGB数组文件。突然发现红帽做过一样的题目,可能也是我这个出题思路?(可惜了,本来想出题的)。
红帽杯
索引文件:data1。
RGB数组:data2。然后我们把这里的hex代码分为三个一组为RGB值。
网上有很多wp,这里不再说了。
至于宽高是通过质数分解得到的。共有7067个索引,因此分解为37*191。
http://tools.jb51.net/jisuanqi/factor_calc
以下为解密的python脚本。之前读到过一篇文章。学习图像处理时matlab十分方便,但是我们需要继续深入学习时也该深入以下python的图像处理,感触颇深。至于matlab代码可以在网上自行寻找。
from PIL import Image
f1 = open('data1','r')
f2 = open('data2','rb')
pic = Image.new("RGB",(37,191),(255,255,255))
pocLis = f1.read()
arrs = f2.read()
pocLis = pocLis.split(' ')
r = []
for i in range(len(arrs)//3):
rgbTemp = arrs[i*3:i*3+3]
RGB = rgbTemp[0],rgbTemp[1],rgbTemp[2]
r.append((RGB))
for i in range(37):
for j in range(191):
rgb = r[int(pocLis[i*191+j])]
pic.putpixel((int(i),int(j)),rgb)
pic.save('flag.png')