上图我们可以看到,十进制的235表示的是绿色,我们修改了在二进制中的最低位,但是颜色看起来依旧没有变化。我们就可以修改最低位中的信息,实现信息的隐写。
下载地址:
http://www.caesum.com/handbook/Stegsolve.jar
0通道
信息,在这三个颜色的0通道
上打勾,并按下Preview键,当隐写的内容为文本文件时如下所示:由PNG文件头可以看出隐写内容为PNG文件,按save Bin
键保存为PNG文件
我在github上参考了这位大佬的脚本,
https://github.com/librauee/Steganalysis/tree/master/LSB
但感觉用起来不是很方便,稍微修改了一下,如下所示:
from PIL import Image
import sysdef toasc(strr):
return int(strr, 2)
#str1为所要提取的信息的长度(根据需要修改),str2为加密载体图片的路径,str3为提取文件的保存路径
def decode(str1,str2,str3):
b=""
im = Image.open(str2)
lenth = int(str1)*8
width,height = im.size[0],im.size[1]
count = 0
for h in range(height):
for w in range(width):
#获得(w,h)点像素的值
pixel = im.getpixel((w, h))
#此处余3,依次从R、G、B三个颜色通道获得最低位的隐藏信息
if count%3==0:
count+=1
b=b+str((mod(int(pixel[0]),2)))
if count ==lenth:
break
if count%3==1:
count+=1
b=b+str((mod(int(pixel[1]),2)))
if count ==lenth:
break
if count%3==2:
count+=1
b=b+str((mod(int(pixel[2]),2)))
if count ==lenth:
break
if count == lenth:
break
with open(str3,"w",encoding='utf-8') as f:
for i in range(0,len(b),8):
#以每8位为一组二进制,转换为十进制
stra = toasc(b[i:i+8])
#将转换后的十进制数视为ascii码,再转换为字符串写入到文件中
#print((stra))
f.write(chr(stra))
print("sussess")
def plus(string):
#Python zfill() 方法返回指定长度的字符串,原字符串右对齐,前面填充0。
return string.zfill(8)
def get_key(strr):
#获取要隐藏的文件内容
with open(strr,"rb") as f:
s = f.read()
string=""
for i in range(len(s)):
#逐个字节将要隐藏的文件内容转换为二进制,并拼接起来
#1.先用ord()函数将s的内容逐个转换为ascii码
#2.使用bin()函数将十进制的ascii码转换为二进制
#3.由于bin()函数转换二进制后,二进制字符串的前面会有"0b"来表示这个字符串是二进制形式,所以用replace()替换为空
#4.又由于ascii码转换二进制后是七位,而正常情况下每个字符由8位二进制组成,所以使用自定义函数plus将其填充为8位
string=string+""+plus(bin(s[i]).replace('0b',''))
#print(string)
return string
def mod(x,y):
return x%y
#str1为载体图片路径,str2为隐写文件,str3为加密图片保存的路径
def encode(str1,str2,str3):
im = Image.open(str1)
#获取图片的宽和高
width,height= im.size[0],im.size[1]
print("width:"+str(width))
print("height:"+str(height))
count = 0
#获取需要隐藏的信息
key = get_key(str2)
keylen = len(key)
for h in range(height):
for w in range(width):
pixel = im.getpixel((w,h))
a=pixel[0]
b=pixel[1]
c=pixel[2]
if count == keylen:
break
#下面的操作是将信息隐藏进去
#分别将每个像素点的RGB值余2,这样可以去掉最低位的值
#再从需要隐藏的信息中取出一位,转换为整型
#两值相加,就把信息隐藏起来了
a= a-mod(a,2)+int(key[count])
count+=1
if count == keylen:
im.putpixel((w,h),(a,b,c))
break
b =b-mod(b,2)+int(key[count])
count+=1
if count == keylen:
im.putpixel((w,h),(a,b,c))
break
c= c-mod(c,2)+int(key[count])
count+=1
if count == keylen:
im.putpixel((w,h),(a,b,c))
break
if count % 3 == 0:
im.putpixel((w,h),(a,b,c))
im.save(str3)
if __name__ == '__main__':
if '-h' in sys.argv or '--help' in sys.argv or len(sys.argv) < 2:
print ('Usage: python test.py <cmd> [arg...] [opts...]')
print (' cmds:')
print (' encode image + flag -> image(encoded)')
print (' decode length + image(encoded) -> flag')
sys.exit(1)
cmd = sys.argv[1]
if cmd != 'encode' and cmd != 'decode':
print('wrong input')
sys.exit(1)
str1 = sys.argv[2]
str2 = sys.argv[3]
str3 = sys.argv[4]
if cmd != 'encode' and cmd != 'decode':
print ('Wrong cmd %s' % cmd)
sys.exit(1)
elif cmd=='encode':
encode(str1,str2,str3)
elif cmd=='decode':
decode(str1,str2,str3)
如果把文件大小设置太小得到的flag不完整,设置太大会产生一些额外的字符,为得到完整的flag,可以把大小设置稍大一些。
不同于文本文件的大小可以任意调整,不影响文件的阅读,图片调整大小对图片的影响较大,而且在一般情况下,我们是不知道被隐写的文件的大小,所以并不推荐用脚本来获取flag,推荐使用工具来解题,脚本可以使用在出题中。
由于LSB隐写在只知道加密图片的情况下就可以知道隐写的内容,可见加密性是比较差的。
我们通过测试来检测LSB隐写的鲁棒性,首先我们对合天_txt.png图片
进行以下操作。
合天网安实验室_jpg.png
图片进行处理,结果如图所示:LSB图片隐写 https://segmentfault.com/a/1190000016223897隐写脚本 https://github.com/librauee/Steganalysis/tree/master/LSB