java lsb隐写_LSB隐写工具对比(Stegsolve与zsteg)

189154?display=mobile

起因

很久很久以前,有一道送分题没做出来,后来看writeup,只要zsteg就行了。

命令运行的结果

root@LAPTOP-GE0FGULA:/mnt/d# zsteg 瞅啥.bmp

[?] 2 bytes of extra data after image end (IEND), offset = 0x269b0e

extradata:0 .. ["x00" repeated 2 times]

imagedata .. text: ["r" repeated 18 times]

b1,lsb,bY ..

b1,msb,bY .. text: "qwxf{you_say_chick_beautiful?}"

b2,msb,bY .. text: "i2,C8&k0."

b2,r,lsb,xY .. text: "UUUUUU9VUUUUUUUUUUUUUUUUUUUUUU"

b2,g,msb,xY .. text: ["U" repeated 22 times]

b2,b,lsb,xY .. text: ["U" repeated 10 times]

b3,g,msb,xY .. text: "V9XDR\d@"

b4,r,lsb,xY .. file: TIM image, Pixel at (4353,4112) Size=12850x8754

b4,g,lsb,xY .. text: "3"""""3###33##3#UDUEEEEEDDUETEDEDDUEEDTEEEUT#!"

b4,g,msb,xY .. text: """""""""""""""""""""DDDDDDDDDDDD""""DDDDDDDDDDDD*LD"

b4,b,lsb,xY .. text: "gfffffvwgwfgwwfw"

b1,msb,bY读取到的flag,看的一脸懵逼,msb是啥?不是lsb隐写么?bY的b又是啥?我用stegsolve怎么没找到flag?

结论

两个工具的一些参数在理解上有点疑问,因此查看了源码。

Stegsolve的Data Extract功能,Bit Order选项MSBFirst和LSBFirst的区别,这个在扫描顺序中说明

zsteg不理解参数更多

-c:rgba的组合理解,r3g2b3则表示r通道的低3bit,g通道2bit,r通道3bit,如果设置为rbg不加数字的,则表示每个通道读取bit数相同,bit数有-b参数设置

-b:设置每个通道读取的bit数,从低位开始,如果不是顺序的低位开始,则可以使用掩码,比如取最低位和最高位,则可以-b 10000001或者-b 0x81

-o:设置行列的读取顺序,xy就是从上到下,从左到右,xy任意有大写的,表示倒序,不过栗子中有个bY令我费解,查看源码知道对于BMP的图片,可以不管通道,直接按字节读取,就是b的意思了,b再顺带表示x,也就是bY的顺序和xY是一样的,Yb和Yx的顺序是一样的,但是b这个的读取模式跟-c bgr -o xY好像是一样的(因为看BMP图片通道排列顺序是BGR),不太理解专门弄个这个出来干嘛。

--msb和--lsb这个在组合顺序中说明

扫描顺序

行列顺序

先说下行列的扫描顺序

zsteg可以通过-o选项设置的8种组合(xy,xY,Xy,XY,yx,yX,Yx,YX),个人认为常用的就xy和xY吧

Stegsolve只有选项设置Extract By Row or Column,对应到zsteg的-o选项上就是xy和yx

字节顺序

然后是字节上的扫描顺序,因为是读取的bit再拼接数据的,那么一个字节有8bit数据,从高位开始读还是从低位开始读的顺序

Stegsolve:字节上的读取顺序与Bit Order选项有关,如果设置了MSBFirst,是从高位开始读取,LSBFirst是从低位开始读取

zsteg:只能从高位开始读,比如-b 0x81,在读取不同通道数据时,都是先读取一个字节的高位,再读取该字节的低位。对应到Stegsolve就是MSBFirst的选项。

组合顺序

对于Stegsolve和zsteg,先读取到bit数据都是先拿出来组合的,每8bit组合成一个字节,按照最先存放的Bit在低地址理解的话。

zsteg的--lsb和--msb决定了组合顺序

--lsb:大端存放

--msb:小端存放

源码片段,a内存储的是读取的Bit数据,所以msb是低地址的是低位,因此是小端存放。

if a.size >= 8

byte = 0

if params[:bit_order] == :msb

8.times{ |i| byte |= (a.shift<

else

8.times{ |i| byte |= (a.shift<

end

Stegsolve则是只有大端存放,即对应zsteg的—lsb,因为代码中有个extractBitPos变量,初始值是128,每组合1bit,就右移一次,到0后循环。

源码片段

private void addBit(int num)

{

if(num!=0)

{

extract[extractBytePos]+=extractBitPos;

}

extractBitPos>>=1;

if(extractBitPos>=1)

return;

extractBitPos=128;

extractBytePos++;

if(extractBytePos

extract[extractBytePos]=0;

}

Stegsolve

了解一下Data Extract以及不同通道存储图片的隐写

Data Extract

功能简要说明

面板

189154?display=mobile

配置选项后,是通过Preview按钮进行数据的读取,因此直接跟进该按钮事件。

Bit Planes:选取通道要读取的bit位。

Bit Plane Order:一个像素值包含多个通道,不同通道的读取数据,Alpha一直是最先读的,然后会根据该项的配置决定读取顺序。

Bit Order:读取数据时,每次仅读取1Bit,该项是控制读取一个通道字节数时,读取的方向,MSBFirst表示从高位读取到低位,LSBFirst表示从低位读取到高位。因此只有当通道勾选的Bit个数大于1时,该选项才会影响返回的结果。

代码分析

文件:Extract.java

按钮事件:

/**

* Generate the extract and generate the preview

* @param evt Event

*/

private void previewButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_previewButtonActionPerformed

generateExtract();

generatePreview();

}//GEN-LAST:event_previewButtonActionPerformed

跟进generateExtract(),存在内部调用,先列举了另外两个方法。

/**

* Retrieves the mask from the bits selected on the form

*/

/*读取Bit Planes的配置,图片getRGB会返回一个整型,如果存在alpha,那么范围最大值就是0xffffffff,从高位至低位,每一个字节按顺序对应为 A R G B,所以getMask就是获取要获取对应Bit的掩码,存为this.mask,this.maskbits记录是全部要读取的Bit数。

*/

private void getMask()

{

mask = 0;

maskbits = 0;

if(ab7.isSelected()) { mask += 1<<31; maskbits++;}

if(ab6.isSelected()) { mask += 1<<30; maskbits++;}

if(ab5.isSelected()) { mask += 1<<29; maskbits++;}

if(ab4.isSelected()) { mask += 1<<28; maskbits++;}

if(ab3.isSelected()) { mask += 1<<27; maskbits++;}

if(ab2.isSelected()) { mask += 1<<26; maskbits++;}

if(ab1.isSelected()) { mask += 1<<25; maskbits++;}

if(ab0.isSelected()) { mask += 1<<24; maskbits++;}

if(rb7.isSelected()) { mask += 1<<23; maskbits++;}

if(rb6.isSelected()) { mask += 1<<22; maskbits++;}

if(rb5.isSelected()) { mask += 1<<21; maskbits++;}

if(rb4.isSelected()) { mask += 1<<20; maskbits++;}

if(rb3.isSelected()) { mask += 1<<19; maskbits++;}

if(rb2.isSelected()) { mask += 1<<18; maskbits++;}

if(rb1.isSelected()) { mask += 1<<17; maskbits++;}

if(rb0.isSelected()) { mask += 1<<16; maskbits++;}

if(gb7.isSelected()) { mask += 1<<15; maskbits++;}

if(gb6.isSelected()) { mask += 1<<14; maskbits++;}

if(gb5.isSelected()) { mask += 1<<13; maskbits++;}

if(gb4.isSelected()) { mask += 1<<12; maskbits++;}

if(gb3.isSelected()) { mask += 1<<11; maskbits++;}

if(gb2.isSelected()) { mask += 1<<10; maskbits++;}

if(gb1.isSelected()) { mask += 1<<9; maskbits++;}

if(gb0.isSelected()) { mask += 1<<8; maskbits++;}

if(bb7.isSelected()) { mask += 1<<7; maskbits++;}

if(bb6.isSelected()) { mask += 1<<6; maskbits++;}

if(bb5.isSelected()) { mask += 1<<5; maskbits++;}

if(bb4.isSelected()) { mask += 1<<4; maskbits++;}

if(bb3.isSelected()) { mask += 1<<3; maskbits++;}

if(bb2.isSelected()) { mask += 1<<2; maskbits++;}

if(bb1.isSelected()) { mask += 1<<1; maskbits++;}

if(bb0.isSelected()) { mask += 1; maskbits++;}

}

/**

* Retrieve the ordering options from the form

*/

/* 读取Order setting的配置,主要就是rgbOrder的不同值对应的顺序

*/

private void getBitOrderOptions()

{

if(byRowButton.isSelected()) rowFirst = true;

else rowFirst = false;

if(LSBButton.isSelected()) lsbFirst = true;

else lsbFirst = false;

if(RGBButton.isSelected()) rgbOrder = 1;

else if (RBGButton.isSelected()) rgbOrder = 2;

else if (GRBButton.isSelected()) rgbOrder = 3;

else if (GBRButton.isSelected()) rgbOrder = 4;

else if (BRGButton.isSelected()) rgbOrder = 5;

else rgbO

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值