FrancescoPaoloL/imgpoison
GitHub: FrancescoPaoloL/imgpoison
一款用 C 语言从零实现的图像隐写术学习工具,支持 LSB 和扩频两种方法,用于研究隐藏文本在图像中的嵌入与检测,特别关注 payload 在多模态 AI 系统中的存活能力。
Stars: 1 | Forks: 0
# imgpoison
一款使用隐写术将文本隐藏在图像中的命令行工具。
处理后的图像看起来与原图毫无二致——隐藏的文本肉眼不可见
并且能够经受住 JPEG 压缩。
**这是一个学习项目。** 旨在从基本原理出发理解隐写术
并探索 LLM 安全概念。非生产就绪,未做优化,也未进行加固。
## 为什么做这个
研究隐藏的 payload 如何在图像处理流程中存活——具体来说,就是探究
嵌入图像中的提示注入在经历 JPEG 压缩、缩放或重新编码后,
是否仍能影响多模态 AI 系统。
## 方法
**LSB** (最低有效位) —— 翻转每个像素的最后一位来编码数据。
速度快且容量大,但非常脆弱:JPEG 压缩会破坏 payload。
仅适用于无损格式 (PNG)。
**SS** (扩频) —— 使用伪随机 chip 序列将 payload 信号分散到数百个像素中。
能够在 JPEG 压缩后存活。需要一个 seed(密钥)来嵌入和提取。
## 构建
```
sudo apt install libjpeg-turbo8-dev
make
```
依赖项:zlib, libjpeg-turbo, libm。没有使用 libpng —— PNG 编解码器是手工编写的。
## 用法
嵌入:
```
./bin/imgpoison --embed --method ss --seed 42 --payload "text" input.png output.jpg
```
提取:
```
./bin/imgpoison --extract --method ss --seed 42 output.jpg
```
LSB 嵌入(仅限 PNG):
```
./bin/imgpoison --embed --method lsb --payload "text" input.png output.png
```
检测 LSB 嵌入:
```
./bin/imgpoison --extract --detect input.png
```
分析 —— 检查图像中是否存在隐藏的 payload 而不将其提取出来:
```
./bin/imgpoison --analyze --method ss --seed 42 output.jpg
./bin/imgpoison --analyze --method lsb input.png
```
SS 分析需要使用与嵌入时相同的 seed。它会打印每个 header 位的关联
强度及结论。LSB 分析会对像素值分布运行卡方检验。
## 参数
| 参数 | 默认值 | 备注 |
|--------------|---------|----------------------------------------------|
| --seed | 42 | 嵌入和提取的密钥 —— 必须匹配 |
| --strength | 10 | 信号强度。越高 = 越稳健,但也越明显 |
| --method | lsb | lsb 或 ss |
## STRENGTH 权衡
| STRENGTH | 相对 JPEG 噪声的 SNR | 可见吗? | 能在 q95 压缩下存活吗? |
|----------|-------------------|----------|---------------|
| 3 | ~96:1 | 几乎不可见 | 是 |
| 10 | ~320:1 | 略微可见 | 是 |
| 20 | ~1280:1 | 是 | 是 |
## SS 的工作原理
每个 payload 位都被隐藏在两组像素(块 A 和 块 B)中。
块 A 稍微变亮一点,块 B 稍微变暗一点(或反之)。
提取时:比较 A 和 B —— 较亮的那一个就编码了该位的值。
JPEG 会给像素添加随机噪声,但由于噪声对 A 和 B 的影响是同等的,
在将两者相减时噪声会被抵消。信号从而得以保留。LSB 无法存活的原因是
JPEG 会使用于存储数据的精确位随机化。
seed 控制着一个伪随机序列 (chip),用于打乱所使用的像素及其方式。
没有 seed,就无法进行提取。
## 工具
**diffmap** —— 可视化原图与隐写图像之间的差异。
有助于验证嵌入是否正常工作。
```
python tests/diffmap.py img/original.png img/stego.jpg
```
需要关注的特征:
- SS → 整张图像均匀分布着椒盐噪声(信号散布在各处)
- LSB → 左上角有一小块明亮区域(payload 集中在开头)
**test_robustness** —— 测试 payload 在图像变换中的存活情况。
```
python tests/test_robustness.py
```
使用默认设置 (STRENGTH=10, CHIP_SIZE=256) 的结果:
| 变换 | 结果 |
|------------------------|--------|
| baseline | PASS |
| recompress q90 | PASS |
| recompress q85 | FAIL |
| recompress q75 | FAIL |
| rotate 1 degree | FAIL |
q85 及以下的压缩会在 STRENGTH=10 时超过噪声阈值。
增加 --strength 可以提高稳健性,但代价是可见性增加。
## 待办事项
- Shell 脚本回归测试(嵌入 → 提取的完整往返测试)
- LLM 安全视角的文档
- 修复 --analyze 中的强度估算(目前因 JPEG 噪声而被放大)
## 参考
Marvel, Boncelet, Retter —— Methodology of Spread-Spectrum Image
Steganography, ARL-TR-1698, 1998. apps.dtic.mil/sti/citations/ADA349102
Press, Teukolsky, Vetterling, Flannery —— Numerical Recipes in C, 2nd ed., 1992.
LCG 常量(乘数 1664525,增量 1013904223)来自第 7 章。
Knuth —— The Art of Computer Programming, vol. 2, sec. 3.4.2.
Fisher-Yates 洗牌算法实现。
ITU-R BT.601 —— 亮度系数参考。
en.wikipedia.org/wiki/Luma_(video)#Rec._601_luma_versus_Rec._709_luma
## 与我联系
[LinkedIn](https://www.linkedin.com/in/francescopl/) · [Kaggle](https://www.kaggle.com/francescopaolol)
标签:AI安全研究, DNS 反向解析, LSB隐写, 信息隐藏, 图像处理, 图像隐写分析, 图片木马, 多媒体安全, 多模态AI, 客户端加密, 对抗性机器学习, 扩频技术, 抗压缩隐写, 提示注入, 搜索语句(dork), 数字水印, 数据隐藏, 网络安全, 隐写术, 隐私保护, 集群管理, 鲁棒性分析