""" Created on 17 Feb 2013 @author: mike """ import struct import collections from volatility.framework import interfaces from volatility.framework.objects import templates class Void(interfaces.objects.ObjectInterface): """Returns an object to represent void/unknown types""" @classmethod def template_size(cls, arguments): """Dummy size for Void objects""" return 0 @classmethod def template_children(cls, arguments): """Returns an empty list for Void objects since they can't have children""" return [] @classmethod def template_replace_child(cls, old_child, new_child, arguments): """Dummy method that does nothing for Void objects""" class PrimitiveObject(interfaces.objects.ObjectInterface): """PrimitiveObject is an interface for any objects that should simulate a Python primitive""" def __init__(self, context, layer_name, offset, structure_name, size = None, parent = None, struct_format = '> start_bit) & ((1 << end_bit) - 1) @classmethod def template_children(cls, arguments): """Returns the target type""" if 'target' in arguments: return [arguments['target']] return [] def write(self, value): raise NotImplementedError("Writing to BitFields is not yet implemented") class Enumeration(interfaces.objects.ObjectInterface): """Returns an object made up of choices""" # FIXME: Add in body for the enumeration object @classmethod def template_children(cls, arguments): return [] def write(self, value): raise NotImplementedError("Writing to Enumerations is not yet implemented") class Array(interfaces.objects.ObjectInterface, collections.Sequence): """Object which can contain a fixed number of an object type""" def __init__(self, context, layer_name, offset, structure_name, size = None, parent = None, count = 0, target = None): if not isinstance(target, templates.ObjectTemplate): raise TypeError("Array target must be an ObjectTemplate") interfaces.objects.ObjectInterface.__init__(self, context = context, layer_name = layer_name, offset = offset, structure_name = structure_name, size = size, parent = parent) self._count = count self._target = target @classmethod def template_size(cls, arguments): """Returns the size of the array, based on the count and the target""" if 'target' not in arguments and 'count' not in arguments: raise TypeError("Array ObjectTemplate must be provided a count and target") return arguments.get('target', None).size * arguments.get('count', 0) @classmethod def template_children(cls, arguments): """Returns the children of the template""" if 'target' in arguments: return [arguments['target']] return [] @classmethod def template_replace_child(cls, old_child, new_child, arguments): """Substitutes the old_child for the new_child""" if 'target' in arguments: if arguments['target'] == old_child: arguments['target'] = new_child def __getitem__(self, i): """Returns the i-th item from the array""" return self._target(context = self._context, layer_name = self._layer_name, offset = self._offset + (self._target.size * i), parent = self) def __len__(self): """Returns the length of the array""" return self._count def write(self, value): raise NotImplementedError("Writing to Arrays is not yet implemented") class Struct(interfaces.objects.ObjectInterface): """Object which can contain members that are other objects""" def __init__(self, context, layer_name, offset, structure_name, size = None, members = None, parent = None): interfaces.objects.ObjectInterface.__init__(self, context = context, layer_name = layer_name, offset = offset, structure_name = structure_name, size = size, parent = parent) self.check_members(members) self._members = members self._concrete_members = {} @classmethod def template_children(cls, arguments): """Method to list children of a template""" cls.check_members(arguments.get('members', None)) return [member for _, member in arguments['members'].values()] @classmethod def template_size(cls, arguments): """Method to return the size of this structure""" if arguments.get('size', None) is None: raise TypeError("Struct ObjectTemplate not provided with a size") return arguments['size'] @classmethod def template_replace_child(cls, old_child, new_child, arguments): """Replace a child elements within the arguments handed to the template""" for member in arguments.get('members', {}): relative_offset, member_template = arguments['members'][member] if member_template == old_child: arguments['members'][member] = (relative_offset, new_child) @classmethod def check_members(cls, members): # Members should be an iterable mapping of symbol names to tuples of (relative_offset, ObjectTemplate) # An object template is a callable that when called with a context, offset, layer_name and structure_name if not isinstance(members, collections.Mapping): raise TypeError("Struct members parameter must be a mapping not " + type(members)) if not all([(isinstance(member, tuple) and len(member) == 2) for member in members.values()]): raise TypeError("Struct members must be a tuple of relative_offsets and templates") def __getattr__(self, attr): """Method for accessing members of the structure""" if attr in self._concrete_members: return self._concrete_members[attr] elif attr in self._members: relative_offset, member = self._members[attr] member = member(context = self._context, layer_name = self._layer_name, offset = self._offset + relative_offset, parent = self) self._concrete_members[attr] = member return member raise AttributeError("'" + self._structure_name + "' Struct has no attribute '" + attr + "'") def write(self, value): raise TypeError("Structs cannot be written to directly, individual members must be written instead")