lsb隐写详讲
上周末给大家培训了lsb隐写,但由于时间仓促,讲得可能过快,导致部分同学未能领悟,故作此文,以帮助各位同学们领悟!
- 首先,给大家讲讲什么叫位图
我们不妨把冠希的照片放大看看
放大后可以注意到,这个图片其实是由一个个不同颜色的格子从左到右从上到下排列组成的。对,就是如此多不同颜色的格子这样排列组成了这张好看图片!这就叫位图!
什么?你觉得我给你的这个解释太粗糙?那我来点比较学术的解释(已经知道什么叫位图的同学可以略过):
- 那么现在我们来说,假如我现在有一串信息
比如说这么一串"JUST{Guan_xi_ge}"
这串信息我们想要隐藏进冠希的这个照片,这样我们想要传递给别人的信息可以以图片为载体传给别人,即便被某个坏人截获了他也很难知道我们真的要传递的信息是什么,因为我们要传递的信息已经被隐藏或者说被隐写进了这个图片!!
- 那么,怎么隐写呢?
这次给大家讲解的隐写方式便是LSB(最低有效位)隐写。
在前文中,我们已经介绍了位图,而LSB隐写便是专门针对这种格式的图片的一种隐写方式。
前文中说到位图是由一个个密密麻麻的各种颜色的小方格一行一行的排列而成的精美图片。
这个小方格,我们称其为"像素点"。
而这些像素点的颜色各种各样才能组成我们眼前这副彩色的图,那么我们的计算机是怎么识别变化每个像素点的颜色的呢?
大家应该都知道红(R)、绿(G)、蓝(B)三元色吧,通过调配这三种颜色,我们可以得到所有的颜色,而在计算机中,每个像素点的颜色便是通过调配其R、G、B的所占成分(值)从而得到的,也就是说,每个颜色的像素点,在计算机看来其实都是一组R、G、B的值。
如下图,我们选中白色,识别出其R、G、B的值分别为255、255、255。在计算机看来,R、G、B这三种颜色中每个颜色对应的值都是一个8位二进制数,因此,在计算机读入时,实际上这三元色的值分别为11111111,11111111,11111111,所以,对于计算机而言,它看到的这么一个像素点实际上就是11111111 11111111 11111111这么一个二进制串,我们称其为该像素点的RGB码(二进制),为了方便人阅读,我们人常常将这串二进制串写作十六进制形式,也就是#ffffff,这也是这个像素点的RGB码(十六进制)。
既然对于计算机而言,每个这样的像素点是一串二进制串(如:11111111 11111111 11111111),而我们在前文中已经说到一张位图是由一行一行密密麻麻排列的像素点构成的,那么这么一张图,不就正是一行一行的二进制串嘛!(示意图如下)
那么我们怎么把"JUST{Guan_xi_ge}"隐写进去呢?
我们知道,在计算机中,每个字符实际上是用ascii码表示的,那我们现在把每位字符转换成其对应的八位二进制ascii码形式即可得到该字符串是这样的一串二进制串:
01001010 01010101 01010011 01010100 01111011 01000111 01110101 01100001 01101110 01011111 01111000 01101001 01011111 01100111 01100101 01111101
把我们要隐写的信息转换成这么一串二进制串后,我们就开始隐写进这个图片!!!!隐写,正式开始!!!
现在我们将刚刚转换成的二进制串的每个二进制位从左至右依次写入上文中所说的图片的每八位二进制的最低位(也就是依次写入图片像素点R、G、B值的最低位)
例如:
按这样写入后,信息的每一位就被我们隐藏进了像素点的R、G、B对应的8位二进制码的末位(最低位),因此这种隐写方式被我们称作"LSB(最低有效位)隐写"
我们写入信息之后,也看不出图片有多大的变化,为什么呢?前面已经说了,在计算机中,每个像素点的颜色便是通过调配其R、G、B的所占成分(值)从而得到的,那按我们这种隐写方式,信息写入R、G、B的最低位,如果R、G、B的最低位因为我们的写入产生变化了,无非也就是1变成了0或者0变成了1,从数值上来讲,被我们隐写过的R、G、B值,最多也就会变化1。这样对每个像素点说,其R、G、B成分的变化是十分微小的,颜色几乎没变,所以人的肉眼是难以察觉到这样的变化的,因此信息才得以悄声无息地被我们藏进去!
以下是由python实现的将信息隐藏进guanxi.bmp这副图的python代码实现(注释对重要功能的代码进行了说明,想习得具体函数细节可自行百度(百度:python XXX函数),"XXX"为你未看懂的函数的名字,一定能搜到的!):
from PIL import Image
# 定义函数getflag将要隐写的文本的内容转换成其对应的二进制串
def getflag(path): # 以二进制文件形式打开文件 f = open(path, "rb") # 读入文件内容 s = f.read() # 将文件内容转换成其对应的二进制码 str0 = "" for i in range(len(s)): str0 = str0+(bin(s[i]).replace("0b", "")).zfill(8) f.closed return str0
# 定义函数对图片进行隐写 def get(impath, txtpath, newpath): flag = getflag(txtpath) flen = len(flag) # 打开图片 im = Image.open(impath) # 读入宽和高 w = im.size[0] h = im.size[1] print("width:"+str(w)) print("height:"+str(h)) cnt = 0 # 将信息逐位隐写进图片 for h in range(h): for w in range(w): pix = im.getpixel((w,h)) r = pix[0] g = pix[1] b = pix[2] if cnt == flen: break r = r - r % 2 + int(flag[cnt]) cnt = cnt + 1
if cnt == flen: im.putpixel((w,h),(r,g,b)) break
g = g - g%2 + int(flag[cnt]) cnt = cnt + 1
if cnt == flen: im.putpixel((w,h),(r,g,b)) break
b = b - b%2 + int(flag[cnt]) cnt = cnt + 1 if cnt == flen: im.putpixel((w, h), (r, g, b)) break
if cnt % 3 == 0: im.putpixel((w, h),(r, g, b)) # 保存隐写后的图片到相应路径 im.save(newpath)
# 开始隐写 impath = "E:\ctf\guanxi.bmp" txtpath = "E:\ctf\\flag.txt" newpath = "E:\ctf\guanxige.bmp" get(impath, txtpath, newpath) |
- 收到这样一幅隐写着信息的图,你该怎么将其信息提取出来呢?
前文已经说了,我们的信息的二进制串被写进了图片中像素点的R、G、B的最低位,那么我们要读取信息,便首先要将图片每个像素点的R、G、B的最低位提取出来,即可得到原来信息对应的二进制串,在前文中我们已经说了,信息的每个字符对应着一个8位二进制码,所以我们就八位八位地读取这个信息对应的二进制串,将其逐个转化为字符,即可得到被藏进去的信息。
- 那么现在我们来实现将隐写进图片信息提取出来这一操作
这里介绍一个图片隐写分析工具叫stegsolve,接下来我们就用它来提取出lsb隐写过的图片的信息。
运行stegsolve需要先安装java环境,java环境的安装和配置教程如下(双击即可点开,你也可以拖到桌面或电脑里其它位置):
<<java环境配置说明(供运行stegsolve图片隐写分析工具用).pdf>>
同时下载好stegsolve(工具在此,双击即可点开,你也可以拖到桌面或电脑里其它位置):
<<Stegsolve.jar>>
运行stegsolve
然后点击"File",再点击"Open",找到我们被隐写后的图片
选中,然后"打开"
现在开始提取信息
点击"Analyse",而后点击"Data Extract",即可进入图片位提取的工具页面
前面我们已经说了,要读取信息,便首先要将图片每个像素点的R、G、B的最低位提取出来,即可得到原来信息对应的二进制串。我们可以看到工具界面中,Red、Green、Blue各有8位选项,即你要提取图片像素点的R、G、B的哪一位,我们要提取的是它们的最低位,因此都勾选0。
点击preview,该工具就会把每个像素点的R、G、B的最低位提取出来,并八位八位地进行读取,即可得到我们藏在图中的信息(如下图)
以下是由python实现的将隐藏进图片的信息提取出来的python代码实现(注释对重要功能的代码进行了说明,想习得具体函数细节可自行百度(百度:python XXX函数),"XXX"为你未看懂的函数的名字,一定能搜到的!):
# coding=utf-8
from PIL import Image
# 定义get函数,用于读取被lsb隐写后的图片中的隐写的信息 def get(impath): # 打开图片 im = Image.open(impath) # 读入宽和高 w = im.size[0] h = im.size[1] print("width:"+str(w)) print("height:"+str(h)) str0 = "" # 提取每个像素的最低位 for h in range(h): for w in range(w): # 提取对应位置处的像素点,并将其r、g、b的值分别赋值给r、g、b pix = im.getpixel((w,h)) r = pix[0] g = pix[1] b = pix[2] # 提取出r、g、b的最低位并依次放入str0中 str0 = str0 + str(r % 2) + str(g % 2) + str(b % 2) # 每八位作为一个二进制ascii码,将其对应的字符读取出来 for i in range(0,len(str0),8): print(chr(int(str0[i:i+8],2)), end = "")
# 开始隐写 impath = "E:\ctf\guanxige.bmp"
get(impath) |
- 看到这里,我想你一定懂怎么进行LSB隐写了吧,试试对这张照片进行隐写和解开隐写吧!!!第一个搞完并把过程和结果截图发给我的人,奖励一杯奶茶!