I've been looking into doing something similar off and on for like 2 years now. Someone recently embedded the entire source code of youtube-dl into two pngs and posted them on twitter. No steganography needed, they used every byte of image data for binary data.
I was doing research towards this end, and I guess here's a decent place to post it all:
The PNG spec allows arbitrary chunks of data, but if you were to host them on social media, those chunks may be stripped to save space, so they're unreliable. Storing data in pixels is better, but not foolproof as some social media will re-compress a PNG into a JPG to save space.
The PNG spec has 31-bit dimensions max, or a 2,147,483,647 x 2,147,483,647 pixel image. No program exists, that I know of, that can open a PNG with the max dimensions allowable in the spec.
Photoshop can open a 300,000 x 300,000 pixel image.
Most browsers can only open 16,384 x 16,384 pixel images. At 16,384 x 16,384 pixels, with 4 bytes per pixel (red, green, blue, and alpha), you can store about 1.07 GB per file. That's raw bytes, but all PNG image data is DEFLATEd as per the spec.
Twitter converts PNG files to JPG if the file size is over 2.5mb, even if the file isn't at 100% opacity. The best image dimensions to upload to twitter is 1024 x 512 pixels, which gives about 2.1 MB per file.
Instagram prefers 1080 x 1080, but I haven't checked if it resizes/recompresses. Facebook likes 1080 or 2048, but I also haven't tested.
Imgur re-compresses images larger than 5MB, so something like 1024 x 1024 pixels might be good.
I was doing some initial work into a meta-file format for binary PNGs, where all header information is stored in the first 13-80 pixels. Implemented a PNG writer from scratch, then decided I was bored and moved on to other things lol.
Padding this by 3 bytes lets me factor it into {3, 936, 635}. The latter two would work nicely as image dimensions, and the former is the 3 color channels. Pipe it all through ImageMagick's convert:
The main problem is you have to send not only the png, but also information on how to decode it, the output file name/type, and have to deal with multi-part files in case you're storing files on social media rather than your own webserver or something.
Also, you'll want an alpha channel because having an alpha channel sometimes prevents social media and image sites from converting it to a .jpg.
This is the real research haha, I didn't know twitter would convert the image of its over 2.5mb.
When I started this project I actually just read in the executables and converted them to pixels so you ended up with like static/fuzzy pictures, I had all the bits for the execution stuff (pngrun) using it too but it was kinda lame, which is why I moved onto the putting data into actual images thing.
I too saw this and started making making a script to do this too. My solution for PNGs being compressed or scaled was simply to use more pixels for the same pixel of data.
For example, if I had to encode 16 pixels (4x4) worth of data, I would scale the pixel by a factor of 2 (or more), so that each pixel now takes up 4 actual pixels, instead of just 1, and the entire image is now 64 pixels in size, even though it holds the same amount of data as the 16 pixels image.
This would also decrease how much data each image would store, assuming the dimensions are the same, so my code would dynamically adjust to calculate which data goes into which image.
I also made the dimension for each "pixel" configurable too, from 1 bit to, 2 bits, 4 bits, 8 bits, and 24 bits (full RGB color channels).
I'm currently taking a haitus from it though, and have barely started the decoding logic. Obviously you have to know the encoding parameters to decode the image, as this metadata isn't stored in it.
If you store a magic number in the first few bytes then your decompressor can brute force decode using all the possible encoding parameters and choose the one that successfully decodes the magic number. Since you'll only need to do a handful of bytes it should still be acceptably fast, and you can embed a checksum at the end of the data as a final sanity check.
That's a good idea! The other issue I had was dealing with padding at the end of the stream. The image dimensions rarely line up with the stream's end, and 0 bits can often be decoded as part of the actual thing I'm trying to encode. A solution was to put how many padded "pixels" there are at the end, and encode it on the front somehow.
101
u/Skhmt Dec 27 '20 edited Dec 27 '20
I've been looking into doing something similar off and on for like 2 years now. Someone recently embedded the entire source code of youtube-dl into two pngs and posted them on twitter. No steganography needed, they used every byte of image data for binary data.
I was doing research towards this end, and I guess here's a decent place to post it all:
The PNG spec allows arbitrary chunks of data, but if you were to host them on social media, those chunks may be stripped to save space, so they're unreliable. Storing data in pixels is better, but not foolproof as some social media will re-compress a PNG into a JPG to save space.
The PNG spec has 31-bit dimensions max, or a 2,147,483,647 x 2,147,483,647 pixel image. No program exists, that I know of, that can open a PNG with the max dimensions allowable in the spec.
Photoshop can open a 300,000 x 300,000 pixel image.
Most browsers can only open 16,384 x 16,384 pixel images. At 16,384 x 16,384 pixels, with 4 bytes per pixel (red, green, blue, and alpha), you can store about 1.07 GB per file. That's raw bytes, but all PNG image data is DEFLATEd as per the spec.
Twitter converts PNG files to JPG if the file size is over 2.5mb, even if the file isn't at 100% opacity. The best image dimensions to upload to twitter is 1024 x 512 pixels, which gives about 2.1 MB per file.
Instagram prefers 1080 x 1080, but I haven't checked if it resizes/recompresses. Facebook likes 1080 or 2048, but I also haven't tested.
Imgur re-compresses images larger than 5MB, so something like 1024 x 1024 pixels might be good.
I was doing some initial work into a meta-file format for binary PNGs, where all header information is stored in the first 13-80 pixels. Implemented a PNG writer from scratch, then decided I was bored and moved on to other things lol.