mirror of
https://github.com/cea-sec/miasm
synced 2026-06-21 13:48:18 +00:00
155 lines
4.0 KiB
Python
155 lines
4.0 KiB
Python
#! /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
|
|
)
|