Go Back!

bmpuzzle

[Source Code]

Embed files within the padding of bitmap images.

Contents

Preface
Usage

Preface

A bitmap image (.bmp) is a type of digital image file that represents an image as a grid of individual pixels, each with a defined color. It stores data in a straightforward, uncompressed format, which can lead to large file sizes, especially for high-resolution images. Bitmap images are widely supported across various software and operating systems, but they lack the compression and advanced features of other formats like JPEG or PNG.

For instance, the data representing a line made up of two red pixels in a 24-bit bitmap image would appear like this:

[00 00 FF] [00 00 FF] 00 00

The data for each pixel has been enclosed in brackets for better clarity.

RGB values are stored in reverse order, i.e., BGR. In a 24-bit bitmap, each color is represented by a 3-byte triplet, with each byte corresponding to the red, green, and blue components, with values ranging from hexadecimal 00 (decimal 0) to hexadecimal FF (decimal 255). In this example, the blue and green values are set to 0, while the red value is set to FF (decimal 255, the maximum value an 8-bit integer can represent).

However, you may have noticed something: in the example I provided, there are two "extra" or "unused" bytes at the end of the line. This isn't a mistake on my part—each scan line is padded to the nearest 4-byte boundary. If the line length isn't divisible by four, like in the case of 6 bytes, there will be 2 bytes of padding added to the end of every scan line.

This padding is typically zero-padded (filled with zeroes), but it doesn't have to be. We can embed hidden data within the bitmap without altering the actual image data by placing it inside the padding (that is, as long as our bitmap file has padding; remember, if the line length is divisible by 4 then there would be no padding).

Usage

With bmpuzzle, inserting and extracting files into bitmap padding is trivial.

Below are the hexadecimal values for a bitmap image. For simplicity, the image consists of a single white line, where the FF values correspond to the pixel color data (white being #FFFFFF), and the 00 values represent padding.

Inserting

By using the following command, we can insert any* file (in this case, an image named "hidden.jpeg") into the bitmap:

bmpuzzle -i original_image.bmp hidden.jpeg

*as long as it fits inside the padding.

Now, if we open the bitmap in a hex editor, we will observe that the padding has been replaced with the data from our image.

Extracting

To extract hidden data from an image, we can use the following command:

bmpuzzle -e image_with_hidden_data.bmp extracted_data.jpeg

This will extract the hidden data from image_with_hidden_data.bmp and save it as extracted_data.jpeg.

Notes

To get the most padding, you should:

  • Make sure each line has 3 bytes of padding, which is the maximum amount of padding a line could have.[*]
  • Reduce the image width. Since padding is added at the end of each horizontal scan line, making the width smaller will result in a "better" padding/image data ratio (by "better" I mean we'll have more useless padding instead of image data). We need less width, more height.

[*]Take the image width and multiply it by the number of bytes per pixel (for a 24-bit bitmap, that’s 3 bytes). Then divide the result by 4. If the result ends in .25, you'll have 3 bytes of padding for every scan line.