上周末给你们培训了lsb隐写,但因为时间仓促,讲得可能过快,致使部分同窗未能领悟,故做此文,以帮助各位同窗们领悟! java
咱们不妨把冠希的照片放大看看 python
放大后能够注意到,这个图片实际上是由一个个不一样颜色的格子从左到右从上到下排列组成的。对,就是如此多不一样颜色的格子这样排列组成了这张好看图片!这就叫位图! 函数
什么?你以为我给你的这个解释太粗糙?那我来点比较学术的解释(已经知道什么叫位图的同窗能够略过): 工具
好比说这么一串"JUST{Guan_xi_ge}" spa
这串信息咱们想要隐藏进冠希的这个照片,这样咱们想要传递给别人的信息能够以图片为载体传给别人,即使被某个坏人截获了他也很难知道咱们真的要传递的信息是什么,由于咱们要传递的信息已经被隐藏或者说被隐写进了这个图片!! blog
此次给你们讲解的隐写方式即是LSB(最低有效位)隐写。 教程
在前文中,咱们已经介绍了位图,而LSB隐写即是专门针对这种格式的图片的一种隐写方式。 图片
前文中说到位图是由一个个密密麻麻的各类颜色的小方格一行一行的排列而成的精美图片。 utf-8
这个小方格,咱们称其为"像素点"。 ci
而这些像素点的颜色各类各样才能组成咱们眼前这副彩色的图,那么咱们的计算机是怎么识别变化每一个像素点的颜色的呢?
你们应该都知道红(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) |