常规图片隐写:
1.使用Stegsolve查看不同的图层,最低有效位隐藏的数据,图片异或等。
2.使用16进制编辑器查看隐藏的数据和文件,发现文件格式,文件修复。
特殊的图片隐写:
1.图像隐写 将消息编码为图像像素的颜色值,可使用在线工具直接解码。 pixeljihad:在线图片解析工具,能直接将像素值解码为消息 站点:https://sekao.net/pixeljihad/
2.图片嵌入隐藏-大容量的信息隐藏算法 对每个像素点进行判断,根据HVS的特性,在最高非0有效位后的指定位(y)开始嵌入隐藏信息,嵌入到另一个指定位(z)为止。 参考帖子:https://blog.csdn.net/A657997301/article/details/82747506
合并图像
代码语言:javascript复制% 各通道肉眼可接受位差
yr = 4;
yg = 5;
yb = 3;
% 读取原图
Img = imread('原图.png');
figure;imshow(Img,[]);title('原图');
% 读取待隐藏的图
Imgmark = imread('待隐藏的图.png');
figure;imshow(Imgmark,[]);title('待隐藏的图');
% 转为灰度图
Imgmark = rgb2gray(Imgmark);
Imgmark = double(Imgmark);
[markm, markn] = size(Imgmark);
% 将灰度图的二维数组转成一列
Imgmarkline = Imgmark(:);
% 这一列再转化为更长的一列,二进制八位表示
Imgmarklinebin = zeros(markm*markn*8,1);
for ii = 1 : markm*markn
[Imgmarklinebin(8*ii-7), Imgmarklinebin(8*ii-6), Imgmarklinebin(8*ii-5), Imgmarklinebin(8*ii-4), Imgmarklinebin(8*ii-3),...
Imgmarklinebin(8*ii-2), Imgmarklinebin(8*ii-1), Imgmarklinebin(8*ii)] = Find8bits(Imgmarkline(ii));
end
%%
% 获得RGB各通道分量图
Img = double(Img);
ImgR = Img(:,:,1);
ImgG = Img(:,:,2);
ImgB = Img(:,:,3);
% 嵌入
% 对于红色通道
embedNumsed = 0; % 已嵌入个数
[M, N, Z] = size(Img);
y = zeros(8, 1);
flag = 0; % 辅助跳出的标志
ImgRline = ImgR(:); % 转换为一列
ImgRlineNew = ImgRline; % 嵌入后
for ii = 1 : M*N
if flag == 1; % 跳出外层循环
break;
end
[y(8), y(7), y(6), y(5), y(4), y(3), y(2), y(1)] = Find8bits(ImgRline(ii));
posNzreo = FindNotZero(y(8), y(7), y(6), y(5), y(4), y(3), y(2), y(1));
embedNums = posNzreo - yr; % 能嵌入的个数
if embedNums > 0 %符合嵌入条件
for jj = 1 : embedNums
embedNumsed = embedNumsed 1; % 已嵌入个数
if embedNumsed > markm*markn*8 % 嵌入完成
flag = 1; % 设置标识,使外层循环也跳出
break;
end
y(jj) = Imgmarklinebin(embedNumsed);% 嵌入
end
end
ImgRlineNew(ii) = bin2dec_trans(y(8), y(7), y(6), y(5), y(4), y(3), y(2), y(1));% 嵌入后的
end
ImgR2 = reshape(ImgRlineNew, [M, N]);
% 对于G通道
ImgGline = ImgG(:); % 转换为一列
ImgGlineNew = ImgGline; % 嵌入后
for ii = 1 : M*N
if flag == 1; % 跳出外层循环
break;
end
[y(8), y(7), y(6), y(5), y(4), y(3), y(2), y(1)] = Find8bits(ImgGline(ii));
posNzreo = FindNotZero(y(8), y(7), y(6), y(5), y(4), y(3), y(2), y(1));
embedNums = posNzreo-yg; % 能嵌入的个数
if embedNums > 0 % 符合嵌入条件
for jj = 1 : embedNums
embedNumsed = embedNumsed 1; % 已嵌入个数
if embedNumsed > markm*markn*8 % 嵌入完成
flag = 1; % 设置标识,使外层循环也跳出
break;
end
y(jj) = Imgmarklinebin(embedNumsed); % 嵌入
end
end
ImgGlineNew(ii) = bin2dec_trans(y(8), y(7), y(6), y(5), y(4), y(3), y(2), y(1)); % 嵌入后的
end
ImgG2 = reshape(ImgGlineNew, [M, N]);
% 对于B通道
ImgBline = ImgB(:); % 转换为一列
ImgBlineNew = ImgBline; % 嵌入后
for ii = 1 : M*N
if flag == 1; % 跳出外层循环
break;
end
[y(8), y(7), y(6), y(5), y(4), y(3), y(2), y(1)] = Find8bits(ImgBline(ii));
posNzreo = FindNotZero(y(8), y(7), y(6), y(5), y(4), y(3), y(2), y(1));
embedNums = posNzreo - yb; % 能嵌入的个数
if embedNums > 0 % 符合嵌入条件
for jj = 1 : embedNums
embedNumsed = embedNumsed 1; % 已嵌入个数
if embedNumsed > markm*markn*8 % 嵌入完成
flag = 1; % 设置标识,使外层循环也跳出
break;
end
y(jj) = Imgmarklinebin(embedNumsed); % 嵌入
end
end
ImgBlineNew(ii) = bin2dec_trans(y(8), y(7), y(6), y(5), y(4), y(3), y(2), y(1)); % 嵌入后的
end
ImgB2 = reshape(ImgBlineNew, [M, N]);
ImgNew = zeros(M, N, Z);
ImgNew(:,:,1) = ImgR2;
ImgNew(:,:,2) = ImgG2;
ImgNew(:,:,3) = ImgB2;
figure;imshow(uint8(ImgNew),[]);title('合并后的RGB图');
imwrite(uint8(ImgNew), '合并后的RGB图.png'); % 保存图片
分离图像
代码语言:javascript复制% 各通道肉眼可接受位差
yr = 4;
yg = 5;
yb = 3;
% 读取合并后的RGB图
Img = imread('合并后的RGB图.png');
[M, N, Z] = size(Img);
Img = double(Img);
ImgR2 = Img(:,:,1);
ImgG2 = Img(:,:,2);
ImgB2 = Img(:,:,3);
% 提取嵌入图像
flag = 0;
Imgmark_extractlinebin = zeros(M*N*8, 1);
extractNumsed = 0; % 已提取个数
% R通道
ImgRline2 = ImgR2(:); % 转换为一列
for ii = 1 : M*N
if flag == 1; % 跳出外层循环
break;
end
[y(8), y(7), y(6), y(5), y(4), y(3), y(2), y(1)] = Find8bits(ImgRline2(ii));
posNzreo = FindNotZero(y(8), y(7), y(6), y(5), y(4), y(3), y(2), y(1));
embedNums = posNzreo - yr; % 已嵌入的个数
if embedNums > 0 % 符合嵌入条件
for jj = 1 : embedNums
extractNumsed = extractNumsed 1; % 已提取个数
if extractNumsed > M*N*8 % 提取完成
flag = 1; % 设置标识,使外层循环也跳出
break;
end
Imgmark_extractlinebin(extractNumsed) = y(jj); % 提取
end
end
end
% G通道
ImgGline2 = ImgG2(:); % 转换为一列
for ii = 1 : M*N
if flag == 1; % 跳出外层循环
break;
end
[y(8), y(7), y(6), y(5), y(4), y(3), y(2), y(1)] = Find8bits(ImgGline2(ii));
posNzreo = FindNotZero(y(8), y(7), y(6), y(5), y(4), y(3), y(2), y(1));
embedNums = posNzreo - yg; % 已嵌入的个数
if embedNums > 0 % 符合嵌入条件
for jj = 1:embedNums
extractNumsed = extractNumsed 1; % 已提取个数
if extractNumsed > M*N*8 % 提取完成
flag = 1; % 设置标识,使外层循环也跳出
break;
end
Imgmark_extractlinebin(extractNumsed) = y(jj);% 提取
end
end
end
% G通道
ImgBline2 = ImgB2(:); % 转换为一列
for ii = 1:M*N
if flag == 1; % 跳出外层循环
break;
end
[y(8), y(7), y(6), y(5), y(4), y(3), y(2), y(1)] = Find8bits(ImgBline2(ii));
posNzreo = FindNotZero(y(8), y(7), y(6), y(5), y(4), y(3), y(2), y(1));
embedNums = posNzreo - yb; % 已嵌入的个数
if embedNums > 0 % 符合嵌入条件
for jj = 1 : embedNums
extractNumsed = extractNumsed 1; % 已提取个数
if extractNumsed > M*N*8 % 提取完成
flag = 1; % 设置标识,使外层循环也跳出
break;
end
Imgmark_extractlinebin(extractNumsed) = y(jj); % 提取
end
end
end
% 二进制转十进制
Imgmarklinedec = zeros(M*N, 1); % 转化为十进制
for ii = 1 : M*N
Imgmarklinedec(ii) = bin2dec_trans(Imgmark_extractlinebin(8*ii-7), Imgmark_extractlinebin(8*ii-6), Imgmark_extractlinebin(8*ii-5), Imgmark_extractlinebin(8*ii-4),...
Imgmark_extractlinebin(8*ii-3), Imgmark_extractlinebin(8*ii-2), Imgmark_extractlinebin(8*ii-1), Imgmark_extractlinebin(8*ii));
end
Imgmarkextract = reshape(Imgmarklinedec, [M, N]);
figure;imshow(Imgmarkextract,[]);title('提取出的隐藏图');
imwrite(uint8(Imgmarkextract), '提取出的隐藏图.png'); % 保存图片
公共函数
% 二进制转十进制
代码语言:javascript复制function Data=bin2dec_trans(y7,y6,y5,y4,y3,y2,y1,y0)
Data=y7*128 y6*64 y5*32 y4*16 y3*8 y2*4 y1*2 y0;
end
% Find8bits.m
function [y7,y6,y5,y4,y3,y2,y1,y0]=Find8bits(Data)
y0=mod(Data,2);
y7=fix(Data/128);Data=Data-y7*128;
y6=fix(Data/64); Data=Data-y6*64;
y5=fix(Data/32); Data=Data-y5*32;
y4=fix(Data/16); Data=Data-y4*16;
y3=fix(Data/8); Data=Data-y3*8;
y2=fix(Data/4); Data=Data-y2*4;
y1=fix(Data/2); Data=Data-y1*2;
end
% FindNotZero.m
%找出第一个不为零的数位 从最高位(第八位)开始
function posNzreo=FindNotZero(y7,y6,y5,y4,y3,y2,y1,y0)
if y7~=0 posNzreo=8;
elseif y6~=0 posNzreo=7;
elseif y5~=0 posNzreo=6;
elseif y4~=0 posNzreo=5;
elseif y3~=0 posNzreo=4;
elseif y2~=0 posNzreo=3;
elseif y1~=0 posNzreo=2;
else posNzreo=1;
end
end
3.像素近邻法
github:https://github.com/3150601355/SimpleScaleDown
图片特征:图片上均匀分布像素点
将图片嵌入另一个图片
代码语言:javascript复制import sys
from PIL import Image
#将small_img中的像素用近邻法嵌入到big_img中
def my_nearest_resize(big_img, small_img):
big_w, big_h = big_img.size
small_w, small_h = small_img.size
dst_im = big_img.copy()
stepx = big_w/small_w
stepy = big_h/small_h
for i in range(0, small_w):
for j in range(0, small_h):
map_x = int(i*stepx stepx*0.5)
map_y = int(j*stepy stepy*0.5)
if map_x < big_w and map_y < big_h:
dst_im.putpixel((map_x, map_y), small_img.getpixel((i, j)))
return dst_im
if __name__ == '__main__':
big_img = Image.open(sys.argv[1]) # 大图
small_img = Image.open(sys.argv[2]) # 小图
dst_im = my_nearest_resize(big_img, small_img)
dst_im.save(sys.argv[3]) # 嵌入小图像素的大图
使用ps或脚本改变图片尺寸
改变图像尺寸
代码语言:javascript复制import sys
from PIL import Image
img = Image.open(sys.argv[1])
img = img.resize((192, 108), Image.NEAREST)
img.save(sys.argv[2])
4.文本写入bmp
图片特征:图片只有不规则像素点,无图案
将文本写入bmp
代码语言:javascript复制from PIL import Image
import math
def encode(text):
str_len = len(text)
width = math.ceil(str_len ** 0.5)
im = Image.new("RGB", (width, width), 0x0)
x, y = 0, 0
for i in text:
index = ord(i)
rgb = (0, (index & 0xFF00) >> 8, index & 0xFF)
im.putpixel((x, y), rgb)
if x == width - 1:
x = 0
y = 1
else:
x = 1
return im
if __name__ == '__main__':
with open("xxx.txt", encoding="utf-8") as f:
all_text = f.read()
im = encode(all_text)
im.save("encode.bmp")
从bmp中导出文本
代码语言:javascript复制from PIL import Image
def decode(im):
width, height = im.size
lst = []
for y in range(height):
for x in range(width):
red, green, blue = im.getpixel((x, y))
if(blue | green | red) == 0:
break
index = (green << 8) blue
lst.append(chr(index))
return ''.join(lst)
if __name__ == '__main__':
all_text = decode(Image.open("encode.bmp", "r"))
with open("decode.text", "w", encoding="utf-8") as f:
f.write(all_text)
PNG:
文件头:
代码语言:javascript复制89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52
00 00 03 30 00 00 04 DB 08 06 00 00 00 46 2C 50
D4
- 89 50 4E 47 0D 0A 1A 0A:PNG文件标识
- 00 00 00 0D:IHDR数据块数据域长为13
- 49 48 44 52:IHDR数据类型码(标识)
- 00 00 03 30:表示图像的宽度,816像素
- 00 00 04 DB:表示图像的高度,1243像素
- 08 06 00 00 00:对图片的一些描述
- 46 2C 50 D4:CRC校验码
文件尾:
代码语言:javascript复制00 00 00 00 49 45 4E 44 AE 42 60 82
JPG:
文件头:
代码语言:javascript复制FF D8 FF
文件尾:
代码语言:javascript复制FF D9
GIF:
文件头:
代码语言:javascript复制47 49 46 38
文件尾:
代码语言:javascript复制00 3B
TIFF:
文件头:
代码语言:javascript复制49 49 2A 00