Source code for pwnypack.packing

import pwnypack.target
import struct


__all__ = [
    'pack',
    'unpack',
    'pack_size',
    'P',
    'p',
    'U',
    'u',
]


[docs]def pack(fmt, *args, **kwargs): """pack(fmt, v1, v2, ..., endian=None, target=None) Return a string containing the values v1, v2, ... packed according to the given format. The actual packing is performed by ``struct.pack`` but the byte order will be set according to the given `endian`, `target` or byte order of the global target. Args: fmt(str): The format string. v1,v2,...: The values to pack. endian(:class:`~pwnypack.target.Target.Endian`): Override the default byte order. If ``None``, it will look at the byte order of the ``target`` argument. target(:class:`~pwnypack.target.Target`): Override the default byte order. If ``None``, it will look at the byte order of the global :data:`~pwnypack.target.target`. Returns: bytes: The provided values packed according to the format. """ endian, target = kwargs.get('endian'), kwargs.get('target') endian = endian if endian is not None else target.endian if target is not None else pwnypack.target.target.endian if fmt and fmt[0] not in '@=<>!': if endian is pwnypack.target.Target.Endian.little: fmt = '<' + fmt elif endian is pwnypack.target.Target.Endian.big: fmt = '>' + fmt else: raise NotImplementedError('Unsupported endianness: %s' % endian) return struct.pack(fmt, *args)
[docs]def unpack(fmt, data, endian=None, target=None): """ Unpack the string (presumably packed by pack(fmt, ...)) according to the given format. The actual unpacking is performed by ``struct.unpack`` but the byte order will be set according to the given `endian`, `target` or byte order of the global target. Args: fmt(str): The format string. data(bytes): The data to unpack. endian(:class:`~pwnypack.target.Target.Endian`): Override the default byte order. If ``None``, it will look at the byte order of the ``target`` argument. target(:class:`~pwnypack.target.Target`): Override the default byte order. If ``None``, it will look at the byte order of the global :data:`~pwnypack.target.target`. Returns: list: The unpacked values according to the format. """ endian = endian if endian is not None else target.endian if target is not None else pwnypack.target.target.endian if fmt and fmt[0] not in '@=<>!': if endian is pwnypack.target.Target.Endian.little: fmt = '<' + fmt elif endian is pwnypack.target.Target.Endian.big: fmt = '>' + fmt else: raise NotImplementedError('Unsupported endianness: %s' % endian) return struct.unpack(fmt, data)
[docs]def pack_size(fmt, endian=None, target=None): endian = endian if endian is not None else target.endian if target is not None else pwnypack.target.target.endian if fmt and fmt[0] not in '@=<>!': if endian is pwnypack.target.Target.Endian.little: fmt = '<' + fmt elif endian is pwnypack.target.Target.Endian.big: fmt = '>' + fmt else: raise NotImplementedError('Unsupported endianness: %s' % endian) return struct.calcsize(fmt)
def _pack_closure(fmt): return lambda value, endian=None, target=None: pack(fmt, value, endian=endian, target=target) def _unpack_closure(fmt): return lambda data, endian=None, target=None: unpack(fmt, data, endian=endian, target=target)[0] for _w, _f in ((8, 'b'), (16, 'h'), (32, 'l'), (64, 'q')): locals().update({ 'p%d' % _w: _pack_closure(_f), 'P%d' % _w: _pack_closure(_f.upper()), 'u%d' % _w: _unpack_closure(_f), 'U%d' % _w: _unpack_closure(_f.upper()), }) locals()['p%d' % _w].__doc__ = '''Pack signed %d bit integer. Alias for ``pack('%s', ...)``.''' % (_w, _f) locals()['P%d' % _w].__doc__ = '''Pack unsigned %d bit integer. Alias for ``pack('%s', ...)``.''' % (_w, _f.upper()) locals()['u%d' % _w].__doc__ = '''Unpack signed %d bit integer. Alias for ``unpack('%s', ...)``.''' % (_w, _f) locals()['U%d' % _w].__doc__ = '''Unpack unsigned %d bit integer. Alias for ``unpack('%s', ...)``.''' % \ (_w, _f.upper()) __all__.extend([ 'p%d' % _w, 'P%d' % _w, 'u%d' % _w, 'U%d' % _w, ]) del _w, _f, _pack_closure, _unpack_closure def _get_bits(bits=None, target=None): """ Determine the number of bits to pack/unpack. """ if bits is not None: bits = int(bits) if bits in (8, 16, 32, 64): return bits else: raise ValueError('bits needs to be 8, 16, 32 or 64') else: return int((target if target is not None else pwnypack.target.target).bits)
[docs]def P(value, bits=None, endian=None, target=None): """ Pack an unsigned pointer for a given target. Args: value(int): The value to pack. bits(:class:`~pwnypack.target.Target.Bits`): Override the default word size. If ``None`` it will look at the word size of ``target``. endian(:class:`~pwnypack.target.Target.Endian`): Override the default byte order. If ``None``, it will look at the byte order of the ``target`` argument. target(:class:`~pwnypack.target.Target`): Override the default byte order. If ``None``, it will look at the byte order of the global :data:`~pwnypack.target.target`. """ return globals()['P%d' % _get_bits(bits, target)](value, endian=endian, target=target)
[docs]def p(value, bits=None, endian=None, target=None): """ Pack a signed pointer for a given target. Args: value(int): The value to pack. bits(:class:`pwnypack.target.Target.Bits`): Override the default word size. If ``None`` it will look at the word size of ``target``. endian(:class:`~pwnypack.target.Target.Endian`): Override the default byte order. If ``None``, it will look at the byte order of the ``target`` argument. target(:class:`~pwnypack.target.Target`): Override the default byte order. If ``None``, it will look at the byte order of the global :data:`~pwnypack.target.target`. """ return globals()['p%d' % _get_bits(bits, target)](value, endian=endian, target=target)
[docs]def U(data, bits=None, endian=None, target=None): """ Unpack an unsigned pointer for a given target. Args: data(bytes): The data to unpack. bits(:class:`pwnypack.target.Target.Bits`): Override the default word size. If ``None`` it will look at the word size of ``target``. endian(:class:`~pwnypack.target.Target.Endian`): Override the default byte order. If ``None``, it will look at the byte order of the ``target`` argument. target(:class:`~pwnypack.target.Target`): Override the default byte order. If ``None``, it will look at the byte order of the global :data:`~pwnypack.target.target`. Returns: int: The pointer value. """ return globals()['U%d' % _get_bits(bits, target)](data, endian=endian, target=target)
[docs]def u(data, bits=None, endian=None, target=None): """ Unpack a signed pointer for a given target. Args: data(bytes): The data to unpack. bits(:class:`pwnypack.target.Target.Bits`): Override the default word size. If ``None`` it will look at the word size of ``target``. endian(:class:`~pwnypack.target.Target.Endian`): Override the default byte order. If ``None``, it will look at the byte order of the ``target`` argument. target(:class:`~pwnypack.target.Target`): Override the default byte order. If ``None``, it will look at the byte order of the global :data:`~pwnypack.target.target`. Returns: int: The pointer value. """ return globals()['u%d' % _get_bits(bits, target)](data, endian=endian, target=target)