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?
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
andcut
- 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!
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
© 2022 - 2024 — McMap. All rights reserved.