目录

  1. 1. 前言
  2. 2. 基础知识
    1. 2.1. 文件结构
      1. 2.1.1. png
        1. 2.1.1.1. IHDR
      2. 2.1.2. jpg
      3. 2.1.3. zip
    2. 2.2. 数字水印
      1. 2.2.1. 可见水印
      2. 2.2.2. 不可见水印
      3. 2.2.3. LSB
      4. 2.2.4. 实例——盲水印
      5. 2.2.5. 几种水印实现方法对比
    3. 2.3. 文件隐写
  3. 3. 工具
    1. 3.1. zsteg
    2. 3.2. foremost
    3. 3.3. Stegsolve
      1. 3.3.1. Data Extract——检测LSB(最低有效位)隐写
      2. 3.3.2. Image Combiner——双图操作

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

图片隐写

2024/6/18 杂项
  |     |   总文章阅读量:

前言

本着有接触过就稍微记录一下的原则,于是就有了这个


基础知识

文件结构

png

参考:https://www.freebuf.com/articles/others-articles/265879.html

文件头:89 50 4E 47 0D 0A 1A 0A

IHDR

文件头数据块IHDR(header chunk):它包含有PNG文件中存储的图像数据的基本信息,并要作为第一个数据块出现在PNG数据流中,而且一个PNG数据流中只能有一个文件头数据块。

文件头数据块由13字节组成,它的格式如下表所示:

域的名称 字节数 说明
Width 4 bytes 图像宽度,以像素为单位
Height 4 bytes 图像高度,以像素为单位
Bit depth 1 byte 图像深度: 索引彩色图像:1,2,4或8 灰度图像:1,2,4,8或16 真彩色图像:8或16
ColorType 1 byte 颜色类型: 0:灰度图像, 1,2,4,8或16 2:真彩色图像,8或16 3:索引彩色图像,1,2,4或8 4:带α通道数据的灰度图像,8或16 6:带α通道数据的真彩色图像,8或16
Compression method 1 byte 压缩方法(LZ77派生算法)
Filter method 1 byte 滤波器方法
Interlace method 1 byte 隔行扫描方法: 0:非隔行扫描 1: Adam7(由Adam M. Costello开发的7遍隔行扫描方法)

IHDR(49 48 44 52)数据块关键字之后紧接的就是定义宽与高的字节块,具体可以先看图片属性中的宽高然后转为16进制后再搜索发现对应的字节块(同样也适用于jpg)


jpg


zip

参考:https://goodapple.top/archives/700

实体文件头:包含着文件的各种信息,包括文件名称、解压缩版本、压缩方式、CRC等等,固定值50 4B 03 04


数字水印

image-20250425104329057

基本原理:将一个特定的信息或标识作为水印,通过一定的算法嵌入到宿主媒体数据中。嵌入过程需要在不明显影响媒体内容质量的前提下进行,以确保水印信息的隐蔽性。提取水印时,则需要一个特定的密钥或算法,用于识别和提取嵌入的水印数据。

分类:

按水印的特性:

  • 鲁棒数字水印:要求嵌入的水印能够经受各种常用的编辑处理

  • 脆弱数字水印:需要对信号的改动足够敏感,是人们能够根据脆弱水印的状态判断出数据是否被篡改。

按水印的检测过程:

  • 明文水印:检测工程中,需要原始数据。提取时需原始载体;验证水印时,必须提供未嵌入水印的原始文件(如原图、原音频)作为对比。

    适用于高精度认证

  • 盲水印:只需要秘钥,不需要原始数据。提取时无需原始载体:仅凭嵌入水印后的文件即可提取或验证水印。

    适用于大规模版权保护

可见水印

实现方法包括但不限于像素值调整、颜色叠加、纹理合成等

一种具体的实现方法是使用透明度通道(如alpha通道)。在图像处理软件中,可以设置一个较低的透明度值,将水印图像与原始图像混合。这样可以确保水印既可以看到,又不完全覆盖原始内容。

在 Python 中可以使用 PIL 库(Python Imaging Library)来实现这样的操作:

from PIL import Image

# 打开原始图像和水印图像
original_image = Image.open('original.jpg')
watermark_image = Image.open('watermark.png')
# 调整水印图像的透明度
watermark透明度 = watermark_image.copy()
watermark透明度.putalpha(128)  # alpha通道值范围0-255,128表示半透明
# 将水印图像混合到原始图像上
result_image = ***posite(watermark透明度, original_image, watermark透明度)
# 保存结果
result_image.save('watermarked.jpg')

不可见水印

一种嵌入在媒体内容中的信息,从外观上看,原始媒体内容不会因为水印的嵌入而有任何明显的变化

实现方法:基于数据隐藏的算法,如 LSB

LSB

LSB替换写基本思路是用嵌入的秘密信息取代载体图像的最低比特位(Least Significant Bit,LSB),原来的7个高位平面与替代秘密信息的最低为平面组合成含隐藏信息的新图形。

原理:

任何一幅图片都具备一定的容噪性,这表现在像素数据的最低有效位对人眼的视觉影响很小,秘密信息就隐藏在图像每一个像素的最低位或次低位 ,实现其不可见性。

在 png 图片的存储中,每个颜色表示需要有 8bit,即有 256 种颜色,一共包含 256 的三次方个颜色,即 16777216 种颜色,人类的眼睛可以区分约 1,000 万种不同的颜色,剩下无法区分的颜色就有 6777216 。

那么就可以对像素三原色 RGB 中的最低位进行修改,通过修改像素中最低位的 1bit 来达到隐藏的效果。

嵌入水印:

import numpy as np
 
def encode_watermark(image, watermark, threshold=128):
    # 将图像和水印转换为numpy数组
    image_array = np.array(image)
    watermark_array = np.array(watermark)
    # 获取图像和水印的尺寸
    h, w, c = image_array.shape
    hw, ww = watermark_array.shape
    # 检查水印是否可以嵌入
    if h < hw or w < ww:
        raise ValueError("Watermark dimensions too large for image")
    # 对每个像素进行LSB替换
    for i in range(0, hw):
        for j in range(0, ww):
            # 对每个颜色通道进行编码
            for k in range(0, c):
                image_array[i, j, k] &= ~1  # 保留除最低位之外的所有位
                image_array[i, j, k] |= watermark_array[i, j, k] & 1  # 添加水印信息的最低位
    # 返回修改后的图像
    return image_array
# 使用方法
encoded_image = encode_watermark(np.array(original_image), np.array(watermark))

解码工具:stegsolve、zsteg、python 脚本等

实例——盲水印

这里使用 WaterMark 工具,导入原图

选择盲水印,图片水印

image-20250425112849779

设置完成后添加水印,然后另存为导出即可


再将导出的图片打开,选择提取盲水印,即可发现水印内容

image-20250425113121162


几种水印实现方法对比

特性 空域水印 时域水印 频域水印
嵌入域 像素/采样点 时间序列 频率系数
鲁棒性 中等
计算复杂度 低~中
隐蔽性 高(LSB类) 高(回声隐藏) 高(中频嵌入)
典型载体 图像、静态数据 音频、视频流 图像、视频
抗攻击能力 易被压缩破坏 抗部分时序攻击 抗压缩/滤波

文件隐写

使用 DOS 命令 copy 即可实现

image-20250425113746894

使用 010editor 打开,可以看到文件内容被拼接在了末尾,并且图片本身能正常查看无变化

image-20250425113906879


工具

zsteg

参考:https://blog.csdn.net/Amherstieae/article/details/107512398

可以检测并提取出PNG和BMP图片里的隐写数据

github:https://github.com/zed-0xff/zsteg

安装:

sudo gem install zsteg

查看lsb数据:

zsteg xxx.bmp
zsteg xxx.png
zsteg -a (文件名)    #查看各个通道的lsb

image-20240618153734927

检测zlib:

#-b的位数是从1开始的
zsteg zlib.bmp -b 1 -o xy -v

提取图片对应通道的内容,根据对应通道的文件类型确定后缀名:

zsteg -E b1,rgb,lsb,xy 1.png > out.zip

foremost

参考:https://www.freebuf.com/sectool/359063.html

将图片中的隐藏文件拆分出来

安装:

apt install foremost

分析文件,然后输出到output文件夹:

foremost -I file -o output

audit.txt分析报告也会一并输出到文件夹中


Stegsolve

参考:https://blog.csdn.net/dyw_666666/article/details/88650738

下载地址:http://www.caesum.com/handbook/Stegsolve.jar

Analyse下的功能:

  • File Format:文件格式,这个主要是查看图片的具体信息

  • Data Extract:数据抽取,图片中隐藏数据的抽取

  • Frame Browser:帧浏览器,主要是对GIF之类的动图进行分解,动图变成一张张图片,便于查看

  • Image Combiner:拼图,图片拼接

Data Extract——检测LSB(最低有效位)隐写

参考:https://developer.aliyun.com/article/1090023

Data Extract下调整Bit Planes、Bit Order、Bit Plane Order

一般Bit Planes都是把rgb通道设置为0,然后调整剩下的几个选项

Image Combiner——双图操作

参考:https://developer.aliyun.com/article/1090023

当两张 jpg 图片外观、大小、像素都基本相同时,可以考虑进行综合分析,即将两个文件的像素RGB值进行XOR、ADD、SUB等操作,看能否得到有用的信息

这里使用Image Combiner

只需要在弹出的窗口中点击左右按钮选择处理方式,有两张图片的RGB值进行XOR、ADD、SUB等操作