上週末給你們培訓了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) |