常规图片隐写:
1.使用Stegsolve查看不同的图层,最低有效位隐藏的数据,图片异或等。
2.使用16进制编辑器查看隐藏的数据和文件,发现文件格式,文件修复。
特殊的图片隐写:
1.图像隐写 将消息编码为图像像素的颜色值,可使用在线工具直接解码。 pixeljihad:在线图片解析工具,能直接将像素值解码为消息 站点:https://sekao.net/pixeljihad/
2.图片嵌入隐藏-大容量的信息隐藏算法 对每个像素点进行判断,根据HVS的特性,在最高非0有效位后的指定位(y)开始嵌入隐藏信息,嵌入到另一个指定位(z)为止。 参考帖子:https://blog.csdn.net/A657997301/article/details/82747506
合并图像
% 各通道肉眼可接受位差
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'); % 保存图片
分离图像
% 各通道肉眼可接受位差
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'); % 保存图片
公共函数
% 二进制转十进制
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
图片特征:图片上均匀分布像素点
将图片嵌入另一个图片
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或脚本改变图片尺寸
改变图像尺寸
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
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中导出文本
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:
文件头:
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
文件尾:
00 00 00 00 49 45 4E 44 AE 42 60 82
JPG:
文件头:
FF D8 FF
文件尾:
FF D9
GIF:
文件头:
47 49 46 38
文件尾:
00 3B
TIFF:
文件头:
49 49 2A 00