Skip to content

Instantly share code, notes, and snippets.

@wting
Forked from briandeheus/punk.py
Last active April 12, 2017 21:01
Show Gist options
  • Save wting/39b0f4c42fef828c5ef525a272ecf558 to your computer and use it in GitHub Desktop.
Save wting/39b0f4c42fef828c5ef525a272ecf558 to your computer and use it in GitHub Desktop.

Revisions

  1. wting revised this gist Jul 28, 2016. 1 changed file with 17 additions and 15 deletions.
    32 changes: 17 additions & 15 deletions punk.py
    Original file line number Diff line number Diff line change
    @@ -11,11 +11,15 @@ class Punk(object):
    from punk import Punk
    # First param is file name, 2nd param is bytes you want to inject.
    Punk.encode('png_out.png', file('doge.jpg').read())
    # First param is the file name, 2nd param is output file name.
    Punk.decode('png_out.png', 'doge.jpg')
    Punk.encode(
    injected_file='meme.png',
    payload=file('doge.gif').read(),
    )
    Punk.decode(
    injected_file='meme.png',
    payload='doge.gif',
    )
    """

    _END_CHUNK_TYPE = 'IEND'
    @@ -24,30 +28,28 @@ class Punk(object):
    _chunks = dict()

    def __init__(self):

    self._mode = None
    self._file = None
    self._output = None
    self._bytes_to_hide = None

    self._bytes_read = 0

    def decode(self, input_file, output_file):
    self._mode = 'decode'
    self._file = open(input_file, 'rb+')
    self._output = open(output_file, 'wb+')
    def encode(self, injected_file, payload):
    self._mode = 'encode'
    self._file = open(injected_file, 'rb+')
    self._bytes_to_hide = payload

    # First move cursor past the signature
    self._read_bytes(8)

    # Start reading chunks
    self._read_next_chunk()

    def encode(self, input_file, bytes_to_hide):

    self._mode = 'encode'
    self._file = open(input_file, 'rb+')
    self._bytes_to_hide = bytes_to_hide
    def decode(self, injected_file, hidden_bytes):
    self._mode = 'decode'
    self._file = open(injected_file, 'rb+')
    self._output = open(hidden_bytes, 'wb+')

    # First move cursor past the signature
    self._read_bytes(8)
  2. wting revised this gist Jul 28, 2016. 1 changed file with 15 additions and 1 deletion.
    16 changes: 15 additions & 1 deletion punk.py
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,20 @@

    class Punk(object):

    """Full blog post about hiding data within PNG files here:
    http://blog.brian.jp/python/png/2016/07/07/file-fun-with-pyhon.html
    Example use case:
    from punk import Punk
    # First param is file name, 2nd param is bytes you want to inject.
    Punk.encode('png_out.png', file('doge.jpg').read())
    # First param is the file name, 2nd param is output file name.
    Punk.decode('png_out.png', 'doge.jpg')
    """

    _END_CHUNK_TYPE = 'IEND'
    _PUNK_CHUNK_TYPE = 'puNk'
    _MAX_BYTES = 2147483647
    @@ -131,4 +145,4 @@ def _read_next_chunk(self):

    return

    self._read_next_chunk()
    self._read_next_chunk()
  3. @briandeheus briandeheus revised this gist Jul 9, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion punk.py
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@
    class Punk(object):

    _END_CHUNK_TYPE = 'IEND'
    _PUNK_CHUNK_TYPE = 'puNK'
    _PUNK_CHUNK_TYPE = 'puNk'
    _MAX_BYTES = 2147483647
    _chunks = dict()

  4. @briandeheus briandeheus created this gist Jul 8, 2016.
    134 changes: 134 additions & 0 deletions punk.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,134 @@
    import binascii
    import struct


    class Punk(object):

    _END_CHUNK_TYPE = 'IEND'
    _PUNK_CHUNK_TYPE = 'puNK'
    _MAX_BYTES = 2147483647
    _chunks = dict()

    def __init__(self):

    self._mode = None
    self._file = None
    self._output = None
    self._bytes_to_hide = None

    self._bytes_read = 0

    def decode(self, input_file, output_file):
    self._mode = 'decode'
    self._file = open(input_file, 'rb+')
    self._output = open(output_file, 'wb+')

    # First move cursor past the signature
    self._read_bytes(8)

    # Start reading chunks
    self._read_next_chunk()

    def encode(self, input_file, bytes_to_hide):

    self._mode = 'encode'
    self._file = open(input_file, 'rb+')
    self._bytes_to_hide = bytes_to_hide

    # First move cursor past the signature
    self._read_bytes(8)

    # Start reading chunks
    self._read_next_chunk()

    def _read_bytes_as_hex(self, position):

    return self._read_bytes(position).encode('hex')

    def _read_bytes_as_ascii(self, position):

    return self._read_bytes(position).encode('ascii')

    def _read_bytes_as_int(self, position):

    return int(self._read_bytes_as_hex(position), 16)

    def _read_bytes(self, byte_count):

    self._bytes_read += byte_count
    return self._file.read(byte_count)

    def _rewind_bytes(self, byte_count):

    self._bytes_read -= byte_count
    self._file.seek(self._bytes_read)

    def _inject_punk_chunk(self):

    # Move back 8 bytes.
    self._rewind_bytes(8)

    chunk_size = len(self._bytes_to_hide)
    print 'Hiding', (chunk_size / 1024), 'kB (', chunk_size, 'bytes)'

    # Create a temporary byte array for the CRC check.
    tmp_bytes = bytearray()

    # First write the chunk type
    tmp_bytes.extend(bytearray(self._PUNK_CHUNK_TYPE))

    # Now write the bytes of whatever we're trying to hide
    tmp_bytes.extend(self._bytes_to_hide)

    print 'Injecting punk chunk'

    # Write the chunk size
    self._file.write(bytearray(struct.pack('!i', chunk_size)))

    # And the type
    self._file.write(bytearray(self._PUNK_CHUNK_TYPE))

    self._file.write(self._bytes_to_hide)

    crc = binascii.crc32(tmp_bytes)
    self._file.write(bytearray(struct.pack('!i', crc)))

    # Write the end chunk. Start with the size.
    self._file.write(bytearray(struct.pack('!i', 0)))
    # Then the chunk type.
    self._file.write(bytearray(self._END_CHUNK_TYPE))

    print 'Punk chunk injected'

    def _read_next_chunk(self):

    chunk_size = self._read_bytes_as_int(4)
    print 'Chunk size:', chunk_size

    chunk_type = self._read_bytes_as_ascii(4)
    print 'Chunk type:', chunk_type

    if self._mode == 'encode' and chunk_type == self._END_CHUNK_TYPE:

    self._inject_punk_chunk()

    print 'Reached EOF'
    self._file.close()

    return

    content = self._read_bytes(chunk_size)

    crc = self._read_bytes_as_hex(4)
    print 'CRC:', crc

    if self._mode == 'decode' and chunk_type == self._PUNK_CHUNK_TYPE:

    print "Found a punk chunk", len(content), "bytes. Writing to file"
    self._output.write(bytearray(content))
    self._output.close()
    self._file.close()

    return

    self._read_next_chunk()