class RT_VERSION(pstruct.type): class _wType(pint.enum, word): _values_ = [ ('Binary', 0), ('Text', 1), ] def __Value(self): length, attribute = self['wValueLength'].li.int(), getattr(self, 'ValueType') if hasattr(self, 'ValueType') else None if callable(attribute): return self.ValueType(length) cls, key = self.__class__, self['szKey'].li.str() if cls is not RT_VERSION: logging.debug("{:s} : No type callback implemented for Value in {!r}. Searching for one instead.".format('.'.join([cls.__module__, cls.__name__]), key)) return RT_VERSION_ValueType.withdefault(key, type=key, length=length) def __Padding2(self): fields = ['wLength', 'wValueLength', 'wType', 'szKey', 'Padding1', 'Value'] length, cb = self['wLength'].li.int(), sum(self[fld].li.size() for fld in fields) return dyn.align(4) if cb < length else dyn.align(0) def __Children(self): fields = ['wLength', 'wValueLength', 'wType', 'szKey', 'Padding1', 'Value', 'Padding2'] length, cb = self['wLength'].li.int(), sum(self[fld].li.size() for fld in fields) if cb > length: raise AssertionError("Invalid block size returned by {!s} for child: {:d} > {:d}".format(self.instance(), cb, length)) size = max(0, length - cb) # If our class implements a .Children() method, then use that to determine the type. attribute = getattr(self, 'Children') if hasattr(self, 'Children') else None if callable(attribute): return self.Children(size) # Otherwise, use the key to lookup the type in our definition. cls, key = self.__class__, self['szKey'].li.str() if cls is not RT_VERSION: logging.debug("{:s} : No type callback implemented for Children in {!r}. Searching for one instead.".format('.'.join([cls.__module__, cls.__name__]), key)) # And then use that type to build the array of children. res = RT_VERSION_EntryType.lookup(key) return dyn.blockarray(res, size) def __Unknown(self): res, fields = self['wLength'].li.int(), ['wLength', 'wValueLength', 'wType', 'szKey', 'Padding1', 'Value', 'Padding2', 'Children'] cb = sum(self[fld].li.size() for fld in fields) return dyn.block(max(0, res - cb)) _fields_ = [ (dyn.align(4), 'alignment'), (word, 'wLength'), (word, 'wValueLength'), (_wType, 'wType'), (pstr.szwstring, 'szKey'), (dyn.align(4), 'Padding1'), (__Value, 'Value'), (__Padding2, 'Padding2'), (__Children, 'Children'), (__Unknown, 'Unknown'), ]
class StreamHdr(pstruct.type): class _Offset(ptype.rpointer_t): _value_ = pint.uint32_t def _baseobject_(self): return self.getparent(MetaDataRoot) def _object_(self): res = self.getparent(StreamHdr) cb = res['Size'].int() t = Stream.withdefault(res['Name'].str(), blocksize=lambda s, cb=cb: cb) if issubclass(t, parray.block): return dyn.clone(t, blocksize=lambda s, cb=cb: cb) return t _fields_ = [ (_Offset, 'Offset'), (pint.uint32_t, 'Size'), (pstr.szstring, 'Name'), (dyn.align(4), 'aligned(Name)'), ] def Name(self): return self['Name'].str() def Size(self): return self['Size'].int()
class UNWIND_INFO(pstruct.type): class Header(pbinary.struct): class UNW_FLAG_(pbinary.enum): width = 5 _values_ = [ ('NHANDLER', 0), ('EHANDLER', 1), ('UHANDLER', 2), ('FHANDLER', 3), ('CHAININFO', 4), ] _fields_ = [ (UNW_FLAG_, 'Flags'), (3, 'Version'), ] class Frame(pbinary.struct): _fields_ = [ (4, 'Register'), (4, 'Offset'), ] class ExceptionHandler(pstruct.type): _fields_ = [(virtualaddress(ptype.undefined, type=dword), 'Address'), (ptype.undefined, 'Data')] def __ExceptionHandler(self): h = self['Header'].l n = h.__field__('Flags') if (n.int() & (n.byname('EHANDLER') | n.byname('UHANDLER')) > 0) and (n.int() & n.byname('CHAININFO') == 0): return self.ExceptionHandler return ptype.undefined def __ChainedUnwindInfo(self): h = self['Header'].l n = h.__field__('Flags') if n.int() == n.byname('CHAININFO') > 0: return RUNTIME_FUNCTION return ptype.undefined _fields_ = [ (Header, 'Header'), (byte, 'SizeOfProlog'), (byte, 'CountOfCodes'), (Frame, 'Frame'), (lambda s: dyn.array(UNWIND_CODE, s['CountOfCodes'].li.int()), 'UnwindCode'), (dyn.align(4), 'align(ExceptionHandler)'), # FIXME: this was copied from IDA (__ExceptionHandler, 'ExceptionHandler'), (__ChainedUnwindInfo, 'ChainedUnwindInfo'), ]
class RT_VERSION(pstruct.type): def __Type(self): if callable(getattr(self, 'Type', None)): return self.Type() cls, key = self.__class__, self['szKey'].li.str() if cls != RT_VERSION: logging.debug("{:s} : No type callback implemented for Value in {!r}. Searching for one instead.".format('.'.join((cls.__module__, cls.__name__)), key)) sz = self['wValueLength'].li.int() return RT_VERSION_ValueType.withdefault(key, type=key, length=sz) def __ChildType(self): if callable(getattr(self, 'ChildType', None)): return self.ChildType() cls, key = self.__class__, self['szKey'].li.str() if self.__class__ != RT_VERSION: logging.debug("{:s} : No type callback implemented for Children in {!r}. Searching for one instead.".format('.'.join((cls.__module__, cls.__name__)), key)) return RT_VERSION_EntryType.lookup(key) #bs = self['wLength'].li.int() - self.blocksize() #return RT_VERSION_EntryType.withdefault(szkey, type=szkey, length=bs) def __Children(self): fields = ['wLength', 'wValueLength', 'wType', 'szKey', 'Alignment', 'Value'] length, cb = self['wLength'].li.int(), sum(self[fld].li.size() for fld in fields) if cb > length: raise AssertionError("Invalid block size returned for child: {:d}".format(bs)) ct = self.__ChildType() class Member(pstruct.type): _fields_ = [ (dyn.align(4), 'Alignment'), (ct, 'Child'), ] return dyn.clone(parray.block, _object_=Member, blocksize=lambda self, bs=length - cb: bs) def __Padding(self): cb = sum(self[fld].li.size() for _, fld in self._fields_[:-1]) return dyn.block(self.blocksize() - cb) _fields_ = [ (word, 'wLength'), (word, 'wValueLength'), (word, 'wType'), (pstr.szwstring, 'szKey'), (dyn.align(4), 'Alignment'), (__Type, 'Value'), (__Children, 'Children'), (__Padding, 'Padding'), ]
class IMAGE_IMPORT_HINT(pstruct.type): _fields_ = [(word, 'Hint'), (pstr.szstring, 'String'), (dyn.align(2), 'Padding')] def str(self): return self.String() def Hint(self): return self['Hint'].li.int() def String(self): return self['String'].li.str()
class MetaDataRoot(pstruct.type): class _Signature(pint.uint32_t): def properties(self): res = super(MetaDataRoot._Signature, self).properties() res['valid'] = self.valid() return res def valid(self): return self.int() == 0x424a5342 class _StreamHeaders(parray.type): _object_ = StreamHdr def Get(self, name): res = next((stream for stream in self if stream.Name() == name), None) if res is None: raise NameError(name) return res def __StreamHeaders(self): res = self['Streams'].li.int() return dyn.clone(self._StreamHeaders, length=res) def __StreamData(self): cb = self.getparent(IMAGE_DATA_DIRECTORY)['Size'].int() total = sum(self[n].li.size() for _, n in self._fields_[:-1]) res = max((0, cb - total)) return dyn.block(res) @pbinary.littleendian class StorageFlags(pbinary.flags): _fields_ = [ (15, 'Reserved'), (1, 'ExtraData'), ] _fields_ = [ (_Signature, 'Signature'), (pint.uint16_t, 'MajorVersion'), (pint.uint16_t, 'MinorVersion'), (pint.uint32_t, 'Reserved'), (pint.uint32_t, 'Length'), (lambda s: dyn.clone(pstr.string, length=s['Length'].li.int()), 'Version'), (dyn.align(4), 'aligned(Version)'), (StorageFlags, 'Flags'), (pint.uint16_t, 'Streams'), (__StreamHeaders, 'StreamHeaders'), (__StreamData, 'StreamData'), ]
class UNWIND_INFO(pstruct.type): class _Header(pbinary.struct): _fields_ = [ (UNW_FLAG_, 'Flags'), (3, 'Version'), ] class _Frame(pbinary.struct): _fields_ = [ (4, 'Offset'), (4, 'Register'), ] class _HandlerInfo(pstruct.type): _fields_ = [(virtualaddress(ptype.undefined, type=dword), 'ExceptionHandler'), (virtualaddress(FuncInfo, type=dword), 'ExceptionData')] def __HandlerInfo(self): res = self['Header'].li flags = res.item('Flags') return self._HandlerInfo if any( flags[item] for item in ['EHANDLER', 'UHANDLER', 'FHANDLER' ]) else ptype.undefined def __FunctionEntry(self): res = self['Header'].li flags = res.item('Flags') return RUNTIME_FUNCTION if flags['CHAININFO'] else ptype.undefined _fields_ = [ (_Header, 'Header'), (byte, 'SizeOfProlog'), (byte, 'CountOfCodes'), (_Frame, 'Frame'), (lambda self: dyn.blockarray(UNWIND_CODE, 2 * self['CountOfCodes'].li. int()), 'UnwindCode'), (dyn.align(4), 'align(ExceptionHandler)'), # FIXME: this was copied from IDA (__HandlerInfo, 'HandlerInfo'), (__FunctionEntry, 'FunctionEntry'), ]
class Member(pstruct.type): _fields_ = [ (dyn.align(4), 'Padding'), (ct, 'Child'), ]
class Member(pstruct.type): _fields_ = [ (dyn.align(4), 'Alignment'), (ct, 'Child'), ]
def __Padding2(self): fields = ['wLength', 'wValueLength', 'wType', 'szKey', 'Padding1', 'Value'] length, cb = self['wLength'].li.int(), sum(self[fld].li.size() for fld in fields) return dyn.align(4) if cb < length else dyn.align(0)