How to extract binary data appended to a png file?
Asked Answered
A

2

6

It seems that if I append binary data to the end of a png file, the png file is still viewable. So the png file is still a valid file. Is there a way to automatically extract such trailing data from a png file whose original file size is not recorded?

Astragalus answered 2/5, 2020 at 15:38 Comment(5)
I have no idea how to do so on the command line (and you may want to ask on superuser.com, since this is a request for a tool rather than a specific programming problem) but the specification is detailed enough.Superstar
Is there a way to migrate the question to superuser?Astragalus
It's faster if you just delete it here and post a-new over there.Superstar
I don't understand from the spec how to determine how many chunks there are or how to determine the original file size. Could you show me where it says this info?Astragalus
It doesn't matter how many chunks there are; "IEND [...] Shall be last" (Table 5.3). The size of each chunk is defined in itself.Superstar
E
7

PNGs end with an "IEND" chunk. The last 12 bytes always look the same. So you could perhaps use:

dd if=appended.png of=extracted.png bs=1 count=$((($(od -t x1 appended.png | awk '{$1=""}1' | tr -d \\n | sed "s/00 00 00 00 49 45 4e 44 ae 42 60 82/XMATCHX/" | tr X \\n  | grep -b MATCH | cut -f1 -d:)-2)/3+12))

The above is a little longer than it needs be to work on macos, which handles grep -b differently than GNU grep.

The gist of it is:

  • Use dd to extract count bytes from the beginning of the appended.png
  • Determine the count by:
    • convert file to hex string of space separated bytes on one line using od/awk/tr
    • search for IEND pattern and replace with MATCH using sed/tr
    • get offset of MATCH using grep -b and cut
    • calc actual file length (subtract extra space/CR, divide by 3 hex chars/space per byte, add 12 for IEND len)

Note: it is unlikely, if not impossible, that the 12 byte IEND chunk can occur within the PNG, but the above does not check for it.

That was a fun coronaviral exercise - thanks!

Emulsifier answered 3/5, 2020 at 16:27 Comment(0)
R
3

You can run pngcheck -v YOURFILE.png and it will tell you if there are extra bytes at the end and exit with error status 2.

It will also tell you where the actual end-of-file is:

# Generate legitimate PNG with ImageMagick
convert -size 300x400 gradient:yellow-red orig.png

# Check its size
ls -l orig.png
-rw-r--r--  1 mark  staff  2509  3 May 17:47 orig.png

# Check it with `pngcheck` - exit status = 0, i.e. all ok
    File: orig.png (2509 bytes)
  chunk IHDR at offset 0x0000c, length 13
    300 x 400 image, 48-bit RGB, non-interlaced
  chunk gAMA at offset 0x00025, length 4: 0.45455
  chunk cHRM at offset 0x00035, length 32
    White x = 0.3127 y = 0.329,  Red x = 0.64 y = 0.33
    Green x = 0.3 y = 0.6,  Blue x = 0.15 y = 0.06
  chunk bKGD at offset 0x00061, length 6
    red = 0xffff, green = 0xffff, blue = 0xffff
  chunk IDAT at offset 0x00073, length 2276
    zlib: deflated, 32K window, maximum compression
  chunk tEXt at offset 0x00963, length 37, keyword: date:create
  chunk tEXt at offset 0x00994, length 37, keyword: date:modify
  chunk IEND at offset 0x009c5, length 0
No errors detected in orig.png (8 chunks, 99.7% compression).

Now append some rubbish to the end:

ls -l >> orig.png

# Check the size again
ls -l orig.png
-rw-r--r--  1 mark  staff  8398  3 May 17:53 orig.png

# And check again - exit status =2
pngcheck -v orig.png
File: orig.png (8398 bytes)
  chunk IHDR at offset 0x0000c, length 13
    300 x 400 image, 48-bit RGB, non-interlaced
  chunk gAMA at offset 0x00025, length 4: 0.45455
  chunk cHRM at offset 0x00035, length 32
    White x = 0.3127 y = 0.329,  Red x = 0.64 y = 0.33
    Green x = 0.3 y = 0.6,  Blue x = 0.15 y = 0.06
  chunk bKGD at offset 0x00061, length 6
    red = 0xffff, green = 0xffff, blue = 0xffff
  chunk IDAT at offset 0x00073, length 2276
    zlib: deflated, 32K window, maximum compression
  chunk tEXt at offset 0x00963, length 37, keyword: date:create
  chunk tEXt at offset 0x00994, length 37, keyword: date:modify
  chunk IEND at offset 0x009c5, length 0
  additional data after IEND chunk
ERRORS DETECTED in orig.png

It also tells you where the real end of the file is in the 3rd to last line, i.e. at 0x009c5. You will need to add 8 to that to allow for the size of the IEND itself.


By the way, if on macOS, you can install pngcheck with homebrew using:

brew install pngcheck
Rattray answered 3/5, 2020 at 16:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.