Web Hosting:
Help Irongeek.com pay for bandwidth and research equipment:
Unicode and LSB Steganography program examples
Unicode and LSB Steganography program examples
I wrote these
Autoit3 code examples to illustrate some of
the ways that steganography (hiding data in other data, or as I like to call it
"hiding your stuff in other stuff so people can't find your stuff") can be done.
These sorts of techniques can be of great use in passing messages without others
knowing, in anti-forensics activities, or as covert command and control channels
for botnets (as I plan to study for my final project in the malware class I'm
enrolled in). There are probably better stego tools out there for these
tasks, I know steghide is a better option if you want to encode hidden data into
images. Still, these examples are fairly simple and should help students begin
to learn the concepts. The download contains two programs and their source code:
unisteg.exe: This tool lets you encode data using different
representations Unicode of characters. The hidden message can then be pasted
into Twitter or Facebook. On Twitter, I can only get 17 hidden characters
encoded into a 140 byte message, but for a command and control channel I'm
sure I can split it up across multiple posts. I'm hoping to get Robin Wood
to implement an encoding scheme similar to this one into his
KreiosC2 project.
lsbsteg.exe: This tool is a simple image editor that takes a message and
hides it as bits in a lossless image format (PNGs for example).
I plan to use some of these stego techniques in future projects. Looks at the comments at the
top of the source code for more details on the specifics of how each algorithm
works. Most of the real technical information is in those comments.
#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_icon=steg.ico #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #cs Steganography using Unicode homoglyphs example ver 1.0 From: Adrian Crenshaw http://irongeek.com Written in Autoit3
In Unicode there are multiple ways to encode characters that look more or less the same to the human eye, but have different numerical values (homoglyphs). I thought this would be a great way to try to hide data in user generated content. I did some searching around, but did not find any code. Antonio Alcorn had a demo page (link below), which he may put up code for later. I looked at what he did, but went a slightly different direction in how I do my encoding (his results looks better, mine hides more data). It seems the characters:
are represented in both the 0021-007E (Basic Latin) and the FF01-FF5E (Fullwidth Latin) ranges. This means I can use the lower range to represent 0s and the higher range to represent 1s. I have to do something special with spaces and encode them as Unicode number 8287 decimal. This means changing from one encoding to another is as easy as adding the decimal values 65248 to the lower range versions. With some effort, I should be able to encode more data or make the output look better by using other homoglyphs, but that will make the algorithm more complicated. Also, some sort of XOR based encryption to the payload would be an easy option to add. Since this first release is for learning, I’ve opted for simplicity of concept. Great thing about this code, you can hide your messages in Twitter or Facebook posts. :)
EndIf Case$DecodeBut GUICtrlSetData($OutputEdit, UniDecodeString($InputMessageStr)) Case$Info ;GUICtrlSetData($OutputEdit, "a " & "b" & ChrW(8287) & "c" & chrW(32+65248) & "d") ; Code I use for testing MsgBox(0,"Unicode Values", PrintDecodeString(GUICtrlRead($OutputEdit))) Case$GUI_EVENT_CLOSE Exit EndSwitch WEnd
;Function checks to see if a valid encode is possible Func CanEncode($CoverStr,$InputMessageStr) $TotalCoverChrs=StringLen($CoverStr) ;$CoverStrNoSpaces = StringReplace($CoverStr, " ", "") ;$EncodablePlaces = StringLen($CoverStrNoSpaces) / 8 $EncodablePlaces=StringLen($CoverStr)/8 $ChrToEncode=StringLen($InputMessageStr) If$EncodablePlaces>=$ChrToEncodeThen ReturnTrue Else ReturnFalse
EndIf EndFunc;==>CanEncode
;This function just lets the use know what they can encode Func ShowInfo($CoverStr,$InputMessageStr) $TotalCoverChrs=StringLen($CoverStr) ;$CoverStrNoSpaces = StringReplace($CoverStr, " ", "") ;$EncodablePlaces = StringLen($CoverStrNoSpaces) / 8 $EncodablePlaces=StringLen($CoverStr)/8 $ChrToEncode=StringLen($InputMessageStr) $InfoMessage="You have "&$ChrToEncode&" characters to encode"&@CRLF $InfoMessage=$InfoMessage&"With the current cover text, you can only encode "&$EncodablePlaces&" characters"&@CRLF $InfoMessage=$InfoMessage&"You have "&$TotalCoverChrs&" total cover characters (140 is all Twitter will allow)" Return$InfoMessage EndFunc;==>ShowInfo
;Encodes the input string into the cover text Func UniEncodeString($CoverStr,$InputMessageStr) $HideMeBin= BinEncodeString($InputMessageStr) $results="" $BinIndex=0 For$i=1ToStringLen($CoverStr) $TheChr=StringMid($CoverStr,$i,1) IfAscW($TheChr)>31Then;do nothing if it's a lower ASCII character $BinIndex=$BinIndex+1 $TheBit=StringMid($HideMeBin,$BinIndex,1) Select Case$TheBit="1" $TheChr= UnicodeReplace($TheChr) CaseElse ;Just leave it latin EndSelect EndIf $results=$results&$TheChr Next Return$results EndFunc;==>UniEncodeString
;Decodes the input string into the hidden text Func UniDecodeString($InputStr) $BinTemp="" For$i=1ToStringLen($InputStr) $TheChr=StringMid($InputStr,$i,1) Select CaseAscW($TheChr)<32 ;do nothing, it's a lower ASCII character, so we skip it CaseAscW($TheChr)>126 $BinTemp=$BinTemp&"1" CaseElse $BinTemp=$BinTemp&"0" EndSelect Next Return BinDecodeString($BinTemp) EndFunc;==>UniDecodeString
;Somethin I put here to help me debug Func PrintDecodeString($arg) $results="" For$i=1ToStringLen($arg) $TheChr=StringMid($arg,$i,1) $results=$results&$TheChr&" "&AscW($TheChr)&@CRLF Next Return$results EndFunc;==>PrintDecodeString
;Just a simple function to make the code easier to read Func UnicodeReplace($arg) IfAscW($arg)=32Then ReturnChrW(8287);encode a space this way, since 32+65248 does not work Else ReturnChrW(AscW($arg)+65248) EndIf EndFunc;==>UnicodeReplace
;Loops though the sting, turing the Binary to ASCII Func BinDecodeString($arg) $results="" For$i=1ToStringLen($arg)Step8 $results=$results& Byte2Asc(StringMid($arg,$i,8)) Next Return$results EndFunc;==>BinDecodeString
;Loops though the sting, turing the ASCII to a series of 1s and 0s Func BinEncodeString($arg) $results="" For$i=1ToStringLen($arg) $results=$results& Asc2Byte(StringMid($arg,$i,1)) Next Return$results EndFunc;==>BinEncodeString
Func Asc2Byte($arg) $tempasc=Asc($arg) Local$result="" While($tempasc>=1) $tempasc/=2 IfStringIsDigit($tempasc)Then $result&=0 Else $split=StringSplit($tempasc,".") $tempasc=$split[1] $result&=1 EndIf WEnd $result=_StringReverse($result) WhileStringLen($result)<8 $result="0"&$result WEnd Return$result EndFunc;==>Asc2Byte ;based on a post from Mpro
Least Signifigant Bit in a PNG Steganography
#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Icon=steg.ico #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #cs Steganography using LSB (least significant bit) example ver 1.1 From: Adrian Crenshaw http://irongeek.com Written in Autoit3
This simple sample code shows using “Least Significant Bit” encoding on a lossless image file format. We can modify the LSB to hide data if we wish. The human eye would have a hard time telling the difference between the RGB color value FF9999 (light red) and FF9899 (which encodes the binary value 101 on the least significant bit of Red Green and Blue), but a computer has no problem. Using a lossy algorithm would make this tougher so this educational code only used PNGs(For JPGs, look up “StegHide”). Also, some sort of XOR based encryption to the payload would be an easy option to add. Since this first release is for learning, I’ve opted for simplicity of concept.
Changes: 02/24/2010 - Made a change so the Encode/Decode functions use null termination so they don't have to iterate through the whole image. 02/24/2010 - First released.
;Main code begins $choice=MsgBox(3,"Irongeek's LSB Stego 1.1: Decode or Encode?","Yes=Encode"&@CRLF&"No=Decode"&@CRLF&"Cancel=Exit") Select Case$choice=6 $TextToEncode=FileOpenDialog("What text should I encode?",@ScriptDir,"Text (*.txt)") $InputImage=FileOpenDialog("What image should I use as cover?",@ScriptDir,"PNGs (*.png)") $OutputImage=FileSaveDialog("Where should I save the output image?",@ScriptDir,"PNGs (*.png)") $DataToEncode=FileRead($TextToEncode) ;msgbox(0,"",$DataToEncode) EncodeImage($DataToEncode,$InputImage,$OutputImage) Case$choice=7 $ImageToDecode=FileOpenDialog("What should I decode?",@ScriptDir,"PNGs (*.png)") $DecodedImageData= BinDecodeString(DecodeImage($ImageToDecode)) $TextFileToSaveTo=FileSaveDialog("Where should I save the output?",@ScriptDir,"Text (*.txt)") FileWrite($TextFileToSaveTo,$DecodedImageData) Case$choice=2 Exit EndSelect ;Main code ends
;Setsu the valus of the least significant bit Func SetLSB($arg,$bit) If$bit="1"Then $results=BitOR($arg,1); 1 as LSB Else $results=BitAND($arg,254); 0 as LSB EndIf Return$results EndFunc;==>SetLSB
;Gives you the value of the least significant bit Func GetLSB($arg) ;msgbox(0,"",$arg) $results=_MathCheckDiv($arg,2) If$results=2Or$results=-1Then$results=0 ;msgbox(0,"",$results) Return$results EndFunc;==>GetLSB
;Had to use this to implement a stack, it made the code logic easier Func PopBinValue(ByRef$arg) $results=StringLeft($arg,1) $arg=StringRight($arg,StringLen($arg)-1) Return$results EndFunc;==>PopBinValue
; Turns decimal color code into a hex encoded string Func RGBIt($deccolor) ReturnHex($deccolor,6) EndFunc;==>RGBIt
;Just get the color of a pixel Func _GDIPlus_BitmapGetPixel($hBitmap,$iX,$iY) Local$tArgb,$pArgb,$aRet $tArgb=DllStructCreate("dword Argb") $pArgb=DllStructGetPtr($tArgb) $aRet=DllCall($ghGDIPDll,"int","GdipBitmapGetPixel","hwnd",$hBitmap,"int",$iX,"int",$iY,"ptr",$pArgb) ReturnHex(DllStructGetData($tArgb,"Argb"),6) EndFunc;==>_GDIPlus_BitmapGetPixel ; Vossen
;Just set the color of a pixel Func _GDIPlus_BitmapSetPixel($hBitmap,$iX,$iY,$iArgb) Local$aRet $iArgb="0xFF"&$iArgb $aRet=DllCall($ghGDIPDll,"int","GdipBitmapSetPixel","hwnd",$hBitmap,"int",$iX,"int",$iY,"dword",$iArgb) Return EndFunc;==>_GDIPlus_BitmapSetPixel ;based on a post from Malkey
;Loops though the sting, turing the Binary to ASCII Func BinDecodeString($arg) $results="" For$i=1ToStringLen($arg)Step8 $results=$results& Byte2Asc(StringMid($arg,$i,8)) Next Return$results EndFunc;==>BinDecodeString
;Loops though the sting, turing the ASCII to a series of 1s and 0s Func BinEncodeString($arg) $results="" For$i=1ToStringLen($arg) $results=$results& Asc2Byte(StringMid($arg,$i,1)) Next Return$results EndFunc;==>BinEncodeString Func Asc2Byte($arg) $tempasc=Asc($arg) Local$result="" While($tempasc>=1) $tempasc/=2 IfStringIsDigit($tempasc)Then $result&=0 Else $split=StringSplit($tempasc,".") $tempasc=$split[1] $result&=1 EndIf WEnd $result=_StringReverse($result) WhileStringLen($result)<8 $result="0"&$result WEnd Return$result EndFunc;==>Asc2Byte ;based on a post from Mpro