miasm/loader/cstruct.py
#! /usr/bin/env python
from __future__ import print_function
from builtins import zip
from functools import reduce
import struct
from future.utils import PY3
type_size = {}
size2type = {}
for t in 'B', 'H', 'I', 'Q':
s = struct.calcsize(t)
type_size[t] = s * 8
size2type[s * 8] = t
type_size['u08'] = size2type[8]
type_size['u16'] = size2type[16]
type_size['u32'] = size2type[32]
type_size['u64'] = size2type[64]
def fix_size(fields, wsize):
out = []
for name, v in fields:
if v.endswith("s"):
pass
elif v == "ptr":
v = size2type[wsize]
elif not v in type_size:
raise ValueError("unknown Cstruct type", v)
else:
v = type_size[v]
out.append((name, v))
fields = out
return fields
class Cstruct_Metaclass(type):
def __new__(cls, name, bases, dct):
o = super(Cstruct_Metaclass, cls).__new__(cls, name, bases, dct)
o._packstring = o._packformat + \
"".join(x[1] for x in o._fields)
o._size = struct.calcsize(o._packstring)
return o
class CStruct(object):
#__metaclass__ = Cstruct_Metaclass
_packformat = ""
_fields = []
@classmethod
def _from_file(cls, f):
return cls(f.read(cls._size))
def __init__(self, sex, wsize, *args, **kargs):
if sex == 1:
sex = '<'
else:
sex = '>'
# packformat enforce sex
if self._packformat:
sex = ""
pstr = fix_size(self._fields, wsize)
self._packstring = sex + self._packformat + \
"".join(x[1] for x in pstr)
self._size = struct.calcsize(self._packstring)
self._names = [x[0] for x in self._fields]
if kargs:
self.__dict__.update(kargs)
else:
if args:
s = args[0]
else:
s = b""
s += b"\x00" * self._size
s = s[:self._size]
self._unpack(s)
def _unpack(self, s):
disas = struct.unpack(self._packstring, s)
for n, v in zip(self._names, disas):
setattr(self, n, v)
def _pack(self):
return struct.pack(self._packstring,
*(getattr(self, x) for x in self._names))
def _spack(self, superstruct, shift=0):
attr = []
for name in self._names:
s = getattr(self, name)
if isinstance(s, CStruct):
if s in superstruct:
s = reduce(lambda x, y: x + len(y),
superstruct[:superstruct.index(s)],
0)
s += shift
else:
raise Exception("%r is not a superstructure" % s)
attr.append(s)
return struct.pack(self._packstring, *attr)
def _copy(self):
return self.__class__(**self.__dict__)
def __len__(self):
return self._size
def __str__(self):
if PY3:
return repr(self)
return self.__bytes__()
def __bytes__(self):
return self._pack()
def __repr__(self):
return "<%s=%s>" % (self.__class__.__name__, "/".join(repr(
getattr(self, x[0])) for x in self._fields
))
def __getitem__(self, item): # to work with format strings
return getattr(self, item)
def _show(self):
print("##%s:" % self.__class__.__name__)
fmt = "%%-%is = %%r" % max(len(x[0]) for x in self._fields)
for fn, ft in self._fields:
print(fmt % (fn, getattr(self, fn)))
class CStructStruct(object):
def __init__(self, lst, shift=0):
self._lst = lst
self._shift = shift
def __getattr__(self, attr):
return getattr(self._lst, attr)
def __str__(self):
if PY3:
return repr(self)
return self.__bytes__()
def __bytes__(self):
return b"".join(
a if isinstance(a, bytes) else a._spack(self._lst, self._shift)
for a in self._lst
)