December 06, 2022, 10:23:14 AM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Hidding text in images

Started by sapero, June 12, 2007, 05:34:15 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

sapero

June 12, 2007, 05:34:15 AM Last Edit: June 12, 2007, 05:42:35 AM by sapero
In this example we will hide any string in a png image (steganography). Not only png can be used for this, just any image format with lossless compression will be accepted here. I've choosen 24-bit color depth, so in one pixel we can store three bytes of data.
I've also attached the "protected" source code as image, ready to decode :)



#include "windows.inc"
#include "gdiplus.inc"
#include "shlwapi.inc"

//gdiplus is required to run this example

sub main()
{
// load this source code into memory
dstring path[MAX_PATH];
GetModuleFileName(0, path, MAX_PATH); // this exe full path
PathRenameExtension(path, ".src");    // rename exe to src
string *pFileString = LoadStringFromFile(path);

// step 1: embed text in image (every pixel has three characters)
if (!CreateImage("cimg2.png", pFileString))
MessageBox(0, "failed to save image", "")
else
ShellExecute(0, "open", "cimg2.png", NULL, NULL, SW_SHOW);

delete pFileString;

// step 2: extract text from existing image
string *lpsz = DecodeImage("cimg2.png");
if (lpsz)
{
// press CTRL+C to copy messagebox text
MessageBox(0, *lpsz, "extracted text");
delete lpsz;
}

return 0;
}


// helper function to load string from file
sub LoadStringFromFile(string path),string *
{
HANDLE hFile  = OpenFile(path, MODE_READ);
DWORD filelen = GetFileSize(hFile);

string* pFileString = new(byte, filelen + 1);
if (pFileString)
Read(hFile, pFileString, filelen);

CloseFile(hFile);

return pFileString;
}


//---------------------------------

class CFileStream
{
IStream *stream;

declare CFileStream() {
stream = 0;
}
declare GetStream(),IStream * {
return stream;
}
declare Close() {
if (stream) stream->Release();
stream = 0;
}
declare Create(string path),BOOL {
Close(); return !SHCreateStreamOnFile(path, STGM_WRITE | STGM_CREATE, &stream);
}
declare Open(string path),BOOL {
Close(); return !SHCreateStreamOnFile(path, STGM_READ, &stream);
}
declare _CFileStream() {
Close();
}
}



class CGdiplusImage
{
ULONG_PTR token;
GpImage  *image;
BitmapData ImageData;

declare CGdiplusImage() {
token = 0;
image = 0;
ImageData.Scan0 = 0;
GdiplusStartupInput gs;
ZeroMemory(&gs, sizeof(gs));
gs.GdiplusVersion = 1;
GdiplusStartup(&token, &gs, NULL);
}
declare Unlock() {
if (ImageData.Scan0) GdipBitmapUnlockBits(image, &ImageData);
ImageData.Scan0 = 0;
}
declare Dispose() {
Unlock();
if (image) GdipDisposeImage(image);
image = 0;
}
declare LoadFromStream(CFileStream *stream),BOOL {
Dispose();
return !GdipLoadImageFromStream(stream->GetStream(), &image);
}
declare Create(int width, int height),BOOL {
Dispose();
return !GdipCreateBitmapFromScan0(width, height, 0/*stride*/, PixelFormat24bppRGB, 0, &image);
}
declare GetPixelFormat(),PixelFormat {
PixelFormat fmt = 0;
if (image) GdipGetImagePixelFormat(image, &fmt);
return fmt;
}
declare GetWidth(),UINT {
UINT width = 0;
if (image) GdipGetImageWidth(image, &width);
return width;
}
declare GetHeight(),UINT {
UINT height = 0;
if (image) GdipGetImageHeight(image, &height);
return height;
}
declare Lock(),pointer {
if (!ImageData.Scan0) {
RECT rc;
SetRect(&rc, 0,0,GetWidth(), GetHeight());
if (image) {
if (GdipBitmapLockBits(image, &rc, 0, PixelFormat24bppRGB, &ImageData))
ImageData.Scan0 = NULL;
}
}
return ImageData.Scan0;
}
declare SaveToStream(CFileStream *stream, CLSID *encoder),BOOL {
EncoderParameters prms;
prms.Count = 1;
prms.Parameter[0].Guid = EncoderSaveFlag;
prms.Parameter[0].NumberOfValues = 0;
Unlock();
return !GdipSaveImageToStream(image, stream->GetStream(), encoder, &prms);
}
declare _CGdiplusImage() {
Dispose();
if (token) GdiplusShutdown(token);
}
}



sub DecodeImage(string path),string *
{
CFileStream   FileStream;
CGdiplusImage image;

string   *lpText = NULL;
UINT      width, height;

while (1)
{
// use stream to skip additional unicode page coding
if (!FileStream.Open(path)) break;
if (!image.LoadFromStream(FileStream)) break;

// validate image format - 24bit
if (image.GetPixelFormat() != PixelFormat24bppRGB) break;

width = image.GetWidth();
height = image.GetHeight();

// allocate memory for text
UINT pixels = width * height;
UINT TextLength = pixels * 3;       // maximum

if (image.Lock())
{
lpText = new(byte, TextLength + 1); // always null terminated
if (lpText)
CopyMemory(lpText, image.Lock(), TextLength);

image.Unlock();
}
break;
}
return lpText;
}


sub CreateImage(string path, UCHAR *lpText),BOOL
{
CGdiplusImage image;
CFileStream FileStream;
UINT width, height;
RECT rc;
BOOL bOk = false;
UINT TextLength = strlen(lpText) + 1;
UINT pixels = (TextLength+3) /3;

while (1)
{
// no empty strings
if (TextLength < 2) break;

// create rectangular image as possible
width = sqrt(pixels);
int div = 8;
if (width % div) width += (div - (width % div));
height = pixels / width;
if ((height * width) < pixels) height++;

// create image
if (!image.Create(width, height) || !image.Lock()) break;

// copy our text
CopyMemory(image.Lock(), lpText, TextLength);
ZeroMemory(image.Lock() + TextLength, (width * height * 3) - TextLength);

// missing guid definition in GdiPlusImaging.inc
declare _ImageEncoderPng();

if (FileStream.Create(path))
// supported save formats: ImageEncoder* Bmp, Jpeg, Gif, Tiff, Png
bOk = image.SaveToStream(FileStream, &_ImageEncoderPng);

break;
}

return bOk;
}

// missing GUID
#emit align 16
#emit _ImageEncoderPng dd 0x557CF406, 0x11D31A04, 0x739A, 0x2EF31EF8

pistol350

Regards,

Peter B.

kryton9