编码增强型LSB反向器

时间:2013-09-01 21:04:41

标签: c++ python image-processing steganography

我绊倒了隐藏式图像,其IDAT结构分为12个区块(最后一个LSB​​略小)( .PNG )。在我得到问题的真实要点之前,我会详细说明问题的结构,因为我需要澄清一些事情,所以请不要将其标记为偏离主题,因为事实并非如此。我只需要解释脚本背后的概念,以便我可以自己解决问题。它肯定有嵌入数据本身。数据似乎已被隐藏,通过改变增强的LSB 值,消除了除最后一个最低有效位之外的每个像素的高电平位。所以所有字节都将是0或1,因为在256个值范围内0或1不会给出任何可见颜色。基本上,0保持为0,1变为最大值,或255.我已经用许多不同的方式分析了这个图像,但是除了完全没有任何一个值之外,没有看到任何奇怪的东西。三个颜色值(RGB)和1/3颜色值中另一个值的高度存在。然而,研究这些并替换字节并没有给我任何帮助,而且我不知道这条道路是否值得追求。

因此,我正在研究用相反的 Python PHP C / C ++ 开发一个脚本来反转这个过程并且恢复'增强的LSB。

我已将其转换为 24位.BMP 并追踪卡方式隐写分析中的红色曲线,这是肯定的文件中有一个隐写数据。

enter image description here enter image description here

首先,有8个以上的垂直区域。这意味着隐藏数据略多于8kB。一个像素可用于隐藏三个比特(每个RGB色调的LSB中有一个)。所以我们可以隐藏(98x225)x3位。为了获得千字节数,我们除以8和1024:((98x225)x3)/(8x1024)。那么,应该是大约8.1千字节。但这就是这种情况。

APPO APP1 标记 .JPG 扩展名的文件也会产生一些尴尬的输出:

Start Offset: 0x00000000
*** Marker: SOI (xFFD8) ***
  OFFSET: 0x00000000

*** Marker: APP0 (xFFE0) ***
  OFFSET: 0x00000002
  length     = 16
  identifier = [JFIF]
  version    = [1.1]
  density    = 96 x 96 DPI (dots per inch)
  thumbnail  = 0 x 0

*** Marker: APP1 (xFFE1) ***
  OFFSET: 0x00000014
  length          = 58
  Identifier      = [Exif]
  Identifier TIFF = x[4D 4D 00 2A 00 00 00 08 ]
  Endian          = Motorola (big)
  TAG Mark x002A  = x[002A]

  EXIF IFD0 @ Absolute x[00000026]
    Dir Length = x[0003]
    [IFD0.x5110                          ] = 
    [IFD0.x5111                          ] = 0
    [IFD0.x5112                          ] = 0
    Offset to Next IFD = [00000000]

*** Marker: DQT (xFFDB) ***
  Define a Quantization Table.
  OFFSET: 0x00000050
  Table length = 67
  ----
  Precision=8 bits
  Destination ID=0 (Luminance)
    DQT, Row #0:   2   1   1   2   3   5   6   7 
    DQT, Row #1:   1   1   2   2   3   7   7   7 
    DQT, Row #2:   2   2   2   3   5   7   8   7 
    DQT, Row #3:   2   2   3   3   6  10  10   7 
    DQT, Row #4:   2   3   4   7   8  13  12   9 
    DQT, Row #5:   3   4   7   8  10  12  14  11 
    DQT, Row #6:   6   8   9  10  12  15  14  12 
    DQT, Row #7:   9  11  11  12  13  12  12  12 
    Approx quality factor = 94.02 (scaling=11.97 variance=1.37)

我几乎确信没有应用加密算法,因此隐藏后没有关键实现。我的想法是编写一个可以移动LSB值并返回原件的脚本。我在几个结构分析,统计攻击,BPCS,

下运行了该文件

图像的直方图显示特定的颜色,并有不寻常的尖峰。我尽可能地操纵我试图查看任何隐藏的数据,但无济于事。这些是RGB值的直方图如下:

enter image description here

然后有多个 IDAT 块。但是,我通过在每个像素位置定义随机颜色值来组合一个类似的图像,我也完成了其中的几个。到目前为止,我发现他们内心很少。更有趣的是,颜色值在图像中重复的方式。看来,重复使用的颜色的频率可以保留一些线索。但是,我还没有完全理解这种关系,如果存在的话。此外,只有一列和一行像素在其Alpha通道上不具有255的完整值。我甚至解释了 X Y A R G ,和 B 图像中每个像素的值为ASCII,但最终没有太清晰。即使是LSB平均值的绿色曲线也无法告诉我们什么。没有明显的突破。以下是几个其他直方图,显示RGB中蓝色值的奇怪曲线:

enter image description here

但红色曲线,即卡方分析的输出,显示出一些差异。它可以看到我们看不到的东西。统计检测比我们的眼睛更敏感,我想这是我的最后一点。但是,红色曲线中也存在一种延迟。即使没有隐藏数据,它也会以最大值开始并保持一段时间。它接近于误报。它看起来像图像中的LSB并且非常接近随机,并且算法需要大量的人口(记住分析是在递增的像素群上完成的),然后才能达到阈值,在此阈值可以确定实际上,它们不是随机的毕竟,红色曲线开始下降。隐藏数据会发生同样的延迟。您隐藏1或2 kb,但红色曲线在此数据量之后不会立即下降。它等了一点,分别在1.3 kb和2.6 kb左右。以下是十六进制编辑器中数据类型的表示:

byte = 166
signed byte = -90
word = 40,358
signed word = -25,178
double word = 3,444,481,446
signed double word = -850,485,850
quad = 3,226,549,723,063,033,254
signed quad = 3,226,549,723,063,033,254
float = -216652384.
double = 5.51490063721e-093
word motorola = 42,653
double word motorola = 2,795,327,181
quad motorola = 12,005,838,827,773,085,484

这是另一个确认蓝色(RGB)值行为的光谱。

enter image description here

请注意,我需要完成所有这些工作,以便澄清我所追求的情况和编程问题。这本身就使我的问题偏离主题,所以如果它没有被标记,我会感到高兴。谢谢。

1 个答案:

答案 0 :(得分:0)

如果应用了LSB增强的图像,我无法想到将其反转回原始状态的方法,因为没有关于RGB原始值的线索。它们被设置为255或0,具体取决于它们的最低有效位。我在这里看到的另一个选择是,这是否包含量子隐写术的某种协议。

Matlab和一些隐写分析技术可能是你问题的关键。

这是一个用于某些统计分析的 Java卡方类:

private long[] pov = new long[256];
and three methods as

public double[] getExpected() {
        double[] result = new double[pov.length / 2];
        for (int i = 0; i < result.length; i++) {
            double avg = (pov[2 * i] + pov[2 * i + 1]) / 2;
            result[i] = avg;
        }
        return result;
}
public void incPov(int i) {
        pov[i]++;
}
public long[] getPov() {
        long[] result = new long[pov.length / 2];
        for (int i = 0; i < result.length; i++) {
            result[i] = pov[2 * i + 1];
        }
        return result;

或尝试使用一些按位移位操作:

int pRGB = image.getRGB(x, y);
int alpha = (pRGB >> 24) & 0xFF;
int blue = (pRGB >> 16) & 0xFF;
int green = (pRGB >> 8) & 0xFF;
int red = pRGB & 0xFF;