So recently I’ve been doing some SEO research for my site. This research basically consists of searching for my own pages on Google to see what’s been indexed and how the pages rank. One problem that I want to solve is Google’s penalizing of duplicate or old content. In the case of images, if I have them uploaded for a draft but I don’t post them until several days later, Google might refuse to index the images because they’re not new. One creative way I’ve thought of to get around this problem is to delete the images from my site and then upload modified versions of the images that look exactly the same visually but are not the same file.
This of course poses an interesting question: How do you change the contents of an image without changing its visual representation on the computer screen? I could borrow methods from steganography, where you decompress an image so you can access the actual pixel values, and then change the lowest-order bits in the red, green, and blue channels of each pixel, but I don’t know enough about the image formats in question to be able to do that intelligently. I could download a steganography program to do it, but I tend to want to figure out how to do those things on my own. For now, basically all I have is the compressed version of an image, and I have to alter that somehow without corrupting it and without changing its visual appearance.
The next step is obvious: Open the images up in a hex editor and start poking around. I used a method of reverse engineering that I like to call the trial-end-error method. That means figuring out how something is built by making small changes and seeing if you break anything. I used the hex editor known as FlexHex to do this.
First I opened the one JPEG that I had. I started with what I figured would be the easiest thing to find: metadata. Since metadata has no effect on the actual pixel data of the image, you can easily change it without damaging anything. In this screenshot we see metadata from both the camera that took the picture as well as GIMP as I used it to edit the image. I figured some arbitrary modifications to the date and time wouldn’t hurt.
But then there were images that didn’t have any metadata. This was true of screenshots that had never been touched by an editor. There was no junk data for me to trivially change. So I had to look for other things, partly through reverse engineering, and partly through doing some minimal research on the file formats. Since almost all of the images I used the hex editor on were PNGs, and I didn’t do anything with the JPEG beyond just changing the metadata, I will be focusing all my attention on the PNG format from now on.
Of course one quick fix for this is to just open up the image in a raster graphics editor, save it, and then the editor will write new metadata to the image for you, thus altering its contents without altering the actual image. That’s a good start, but I want to explore this idea further. I want to know the full extent of what I can change in an image file and what I can’t.
So I started by opening the file in the hex editor and just changing random digits. Almost all of these resulted in either the bottom half of the image getting chopped off or the entire image becoming unreadable. I soon realized that a large part of the problem was the nature of the compression algorithm and how changes in individual bits in the uncompressed file can be propagated through larger sections of the compressed file and vice versa, simply because of the nature of the compression. This is even more true if you’re using visual-level compression like the discrete cosine transform used to compress JPEGs, because adjacency of pixels in the image doesn’t always translate to proximity of the corresponding bytes. Hence, editing of pixel data in a hex editor is pretty much impossible.
Then I went to the end of the image. I saw an
END marker and thought “Hey, maybe it’ll just ignore everything after that.” So I tried adding a string to the end.
This in fact resulted in no change in the image. So I had another lead. Not only can you change useless metadata, but you can add stuff to the end of an image as well, at least in the case of a PNG.
But I couldn’t seem to change any other bits without the results being catastrophic. It seemed like every part of the image was vital pixel data that couldn’t be altered in any way. So I started doing some research online. I will now share what I’ve learned and talk about what you can and can’t change, using another hex editor screenshot as a visual.
The first eight bytes of the PNG file are the magic number, which is always
89 50 4E 47 0D 0A 1A 0A. Definitely don’t change this. It’s the image rendering software’s only way of knowing what kind of file it is. The four bytes that are selected in the hex editor are the
IHDR block. This marks the beginning of a chunk, which is exactly what it sounds like, a chunk of binary code that is used to generate the image. In this case there’s only one chunk, and aside from any headers and metadata, it’s all a single mass of compressed pixel data. You can’t edit this either without corrupting the file.
Now let’s look at the end of the file again.
Yeah, it’s a different file this time, but I wanted one that didn’t have the inserted string at the end. In this image I have selected eight bytes. The first four bytes are the string
IEND. This marks the end of a chunk. The last four bytes are a CRC, which is used for error checking. You definitely don’t want to change this part either, because if the error checking code is changed, the image renderer will think the image file is corrupted even if it isn’t and it will likely refuse to render it.
So basically that leaves three areas of the file that we can alter: the metadata, the end of the file (by appending), and any parts of the chunk header that are not vital. So let’s look at the chunk header.
There are only three chunk header fields that I was able to find out about from either my research or observing the actual hex output: they are the chunk length, the chunk title, and the chunk type, all four bytes in length. In the above image, the chunk length is the first column of the second row. It looks like a small number, but that’s only because it’s in little-endian order. So instead of 0x280, its value is actually 0x80020000. The chunk title in this image is in the second column of the third row, and it is
pHYs (don’t ask me what that means). The chunk type is right below the GIMP comment, and its value is
IDAT (which I assume is short for “Image DATa”).
I have selected the chunk title here for clarity. Both the chunk title and the chunk type appear to be malleable. If they are the wrong value, the image renderer can still guess what the type is in most cases. As for the title, I’m willing to bet it has no real effect on how the image data is interpreted, so it can be basically anything. In altering my images I made various modifications to this field, like changing the lowercase P to a capital P. Since the interpreter has no idea what the letters actually mean and is only focused on the bits themselves, this equates to a completely different title, but it still has no effect on the rendering of the image.
Unfortunately, it does seem to have an effect on uploading the image, probably due to byte order changing. That’s the only thing I can think of anyway. I will have to look into this further.
Not the first time I’ve used a hex editor, but it was the first time I’ve used a hex editor for something of a reverse engineering nature. Overall it’s pretty sweet, and I’m excited to be getting into this stuff. Can’t wait to do more.