mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-10 11:47:38 +02:00
Initial introduction of ObjectInformation class.
This commit is contained in:
@@ -38,6 +38,7 @@ def require_version(*args):
|
||||
|
||||
from volatility.framework import interfaces, symbols, layers
|
||||
|
||||
|
||||
class Context(interfaces.context.ContextInterface):
|
||||
"""Maintains the context within which to construct objects
|
||||
|
||||
@@ -86,7 +87,7 @@ class Context(interfaces.context.ContextInterface):
|
||||
|
||||
# ## Object Factory Functions
|
||||
|
||||
def object(self, symbol, layer_name, offset):
|
||||
def object(self, symbol, layer_name, offset, **kwargs):
|
||||
"""Object factory, takes a context, symbol, offset and optional layername
|
||||
|
||||
Looks up the layername in the context, finds the object template based on the symbol,
|
||||
@@ -96,7 +97,9 @@ class Context(interfaces.context.ContextInterface):
|
||||
:rtype: :py:class:`volatility.framework.interfaces.objects.ObjectInterface`
|
||||
"""
|
||||
object_template = self._symbol_space.get_structure(symbol)
|
||||
return object_template(self, layer_name = layer_name, offset = offset)
|
||||
return object_template(self,
|
||||
interfaces.objects.ObjectInformation(layer_name = layer_name, offset = offset),
|
||||
**kwargs)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,46 +4,76 @@ Created on 6 May 2013
|
||||
@author: mike
|
||||
"""
|
||||
|
||||
import copy
|
||||
import collections.abc
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
from volatility.framework import validity
|
||||
from volatility.framework.interfaces import context as context_module
|
||||
|
||||
|
||||
class TemplateInformation(validity.ValidityRoutines):
|
||||
def __init__(self, structure_name, size, **additional):
|
||||
self._structure_name = structure_name
|
||||
self._size = size
|
||||
self._additional = additional
|
||||
class ReadOnlyInformation(validity.ValidityRoutines, collections.abc.Mapping):
|
||||
"""A read-only mapping of various values that offer attribute access as well"""
|
||||
|
||||
def __init__(self, dict):
|
||||
self._dict = dict
|
||||
|
||||
def __getattr__(self, attr):
|
||||
"""Returns the item as an attribute"""
|
||||
if attr in self._dict:
|
||||
return self._dict[attr]
|
||||
raise AttributeError("'" + self.__class__.__name__ + "' object has no attribute '" + attr + '"')
|
||||
|
||||
def __getitem__(self, name):
|
||||
"""Returns the item requested"""
|
||||
return self._dict[name]
|
||||
|
||||
def __iter__(self):
|
||||
"""Returns an iterator of the dictionary items"""
|
||||
return self._dict.__iter__()
|
||||
|
||||
def __len__(self):
|
||||
"""Returns the length of the internal dictionary"""
|
||||
return len(self._dict)
|
||||
|
||||
|
||||
class ObjectInformation(validity.ValidityRoutines):
|
||||
class ObjectInformation(ReadOnlyInformation):
|
||||
"""Contains information useful/pertinent only to an individual object (like an instance)"""
|
||||
|
||||
def __init__(self, layer_name, offset, member_name = None, parent = None):
|
||||
self._layer_name = layer_name
|
||||
self._offset = offset
|
||||
self._member_name = member_name
|
||||
self._parent = parent
|
||||
self._type_check(offset, int)
|
||||
if parent:
|
||||
self._type_check(parent, ObjectInterface)
|
||||
ReadOnlyInformation.__init__(self, {'layer_name': layer_name,
|
||||
'offset': offset,
|
||||
'member_name': member_name,
|
||||
'parent': parent})
|
||||
|
||||
|
||||
class ObjectInterface(validity.ValidityRoutines, metaclass = ABCMeta):
|
||||
""" A base object required to be the ancestor of every object used in volatility """
|
||||
|
||||
def __init__(self, context, layer_name, offset, structure_name, size, parent = None):
|
||||
def __init__(self, context, object_info, template_info):
|
||||
# Since objects are likely to be instantiated often,
|
||||
# we're only checking that context, offset and parent
|
||||
# Everything else may be wrong, but that will get caught later on
|
||||
self._type_check(context, context_module.ContextInterface)
|
||||
self._type_check(offset, int)
|
||||
if parent:
|
||||
self._type_check(parent, ObjectInterface)
|
||||
self._type_check(template_info, ReadOnlyInformation)
|
||||
self._type_check(object_info, ObjectInformation)
|
||||
|
||||
# Add an empty dictionary at the start to allow objects to add their own data to the volinfo object
|
||||
#
|
||||
# NOTE:
|
||||
# This allows objects to MASSIVELY MESS with their own internal representation!!!
|
||||
# Changes to offset, structure_name, etc should NEVER be done
|
||||
#
|
||||
self._volinfo = collections.ChainMap({}, object_info, template_info)
|
||||
self._context = context
|
||||
self._parent = None if not parent else parent
|
||||
self._offset = offset
|
||||
self._layer_name = layer_name
|
||||
self._structure_name = structure_name
|
||||
self._size = size
|
||||
|
||||
@property
|
||||
def volinfo(self):
|
||||
"""Returns the volatility specific object information"""
|
||||
# Wrap the outgoing volinfo in a read-only proxy
|
||||
return ReadOnlyInformation(self._volinfo)
|
||||
|
||||
@abstractmethod
|
||||
def write(self, value):
|
||||
@@ -52,65 +82,58 @@ class ObjectInterface(validity.ValidityRoutines, metaclass = ABCMeta):
|
||||
def cast(self, new_structure_name):
|
||||
"""Returns a new object at the offset and from the layer that the current object inhabits"""
|
||||
object_template = self._context.symbol_space.get_structure(new_structure_name)
|
||||
return object_template(context = self._context, layer_name = self._layer_name, offset = self._offset)
|
||||
return object_template(context = self._context,
|
||||
layer_name = self.volinfo.layer_name,
|
||||
offset = self.volinfo.offset)
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def template_replace_child(cls, old_child, new_child, arguments):
|
||||
def template_replace_child(cls, template, old_child, new_child):
|
||||
"""Substitutes the old_child for the new_child"""
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def template_size(cls, arguments):
|
||||
def template_size(cls, template):
|
||||
"""Returns the size of the template object"""
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def template_children(cls, arguments):
|
||||
def template_children(cls, template):
|
||||
"""Returns the children of the template"""
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def template_relative_child_offset(cls, arguments, child):
|
||||
def template_relative_child_offset(cls, template, child):
|
||||
"""Returns the relative offset from the head of the parent data to the child member"""
|
||||
|
||||
|
||||
class Template(object):
|
||||
class Template(validity.ValidityRoutines):
|
||||
"""Class for all Factories that take offsets, and data layers and produce objects
|
||||
|
||||
This is effectively a class for currying object calls
|
||||
"""
|
||||
|
||||
def __init__(self, structure_name = None, **kwargs):
|
||||
def __init__(self, structure_name, **kwargs):
|
||||
"""Stores the keyword arguments for later use"""
|
||||
self._kwargs = kwargs
|
||||
self._structure_name = structure_name
|
||||
# Allow the updating of template arguments whilst still in template form
|
||||
self._volinfo = collections.ChainMap(kwargs, {'structure_name': structure_name})
|
||||
|
||||
@property
|
||||
def structure_name(self):
|
||||
"""Returns the name of the particular symbol"""
|
||||
return self._structure_name
|
||||
def volinfo(self):
|
||||
"""Returns a volatility information object, much like the ObjectInterface provides"""
|
||||
return ReadOnlyInformation(self._volinfo)
|
||||
|
||||
@property
|
||||
def arguments(self):
|
||||
"""Returns the keyword arguments stored earlier"""
|
||||
return copy.deepcopy(self._kwargs)
|
||||
|
||||
def update_arguments(self, **newargs):
|
||||
def update_volinfo(self, **newargs):
|
||||
"""Updates the keyword arguments"""
|
||||
self._kwargs.update(newargs)
|
||||
self._volinfo.update(newargs)
|
||||
|
||||
def __call__(self, context, layer_name, offset, parent = None):
|
||||
def __call__(self, context, object_info, **kwargs):
|
||||
"""Constructs the object
|
||||
|
||||
:type context: framework.interfaces.context.ContextInterface
|
||||
:type layer_name: str
|
||||
:type offset: int
|
||||
:type parent: ObjectInterface
|
||||
:type object_info: ObjectInformation
|
||||
:param context:
|
||||
:param layer_name:
|
||||
:param offset:
|
||||
:param parent:
|
||||
:param object_info:
|
||||
|
||||
:return O Returns: an object adhereing to the Object interface
|
||||
"""
|
||||
|
||||
@@ -15,21 +15,21 @@ class Void(interfaces.objects.ObjectInterface):
|
||||
"""Returns an object to represent void/unknown types"""
|
||||
|
||||
@classmethod
|
||||
def template_size(cls, arguments):
|
||||
def template_size(cls, template):
|
||||
"""Dummy size for Void objects"""
|
||||
return 0
|
||||
|
||||
@classmethod
|
||||
def template_children(cls, arguments):
|
||||
def template_children(cls, template):
|
||||
"""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):
|
||||
def template_replace_child(cls, template, old_child, new_child):
|
||||
"""Dummy method that does nothing for Void objects"""
|
||||
|
||||
@classmethod
|
||||
def template_relative_child_offset(cls, arguments, child):
|
||||
def template_relative_child_offset(cls, template, child):
|
||||
"""Dummy method that does nothing for Void objects"""
|
||||
|
||||
def write(self, value):
|
||||
@@ -39,132 +39,102 @@ class Void(interfaces.objects.ObjectInterface):
|
||||
|
||||
class PrimitiveObject(interfaces.objects.ObjectInterface):
|
||||
"""PrimitiveObject is an interface for any objects that should simulate a Python primitive"""
|
||||
_struct_format = '<I'
|
||||
_struct_type = int
|
||||
|
||||
def __init__(self, context, layer_name, offset, structure_name, size = None, parent = None, struct_format = '<I'):
|
||||
def __init__(self, context, object_info, template_info):
|
||||
interfaces.objects.ObjectInterface.__init__(self,
|
||||
context = context,
|
||||
layer_name = layer_name,
|
||||
offset = offset,
|
||||
structure_name = structure_name,
|
||||
size = size,
|
||||
parent = parent)
|
||||
self._struct_format = struct_format
|
||||
template_info = template_info,
|
||||
object_info = object_info)
|
||||
|
||||
def __new__(cls, context, template_info, object_info, **kwargs):
|
||||
return cls._struct_type.__new__(cls,
|
||||
cls._struct_value(context,
|
||||
object_info.layer_name,
|
||||
object_info.offset))
|
||||
|
||||
@classmethod
|
||||
def _struct_value(cls, struct_format, context, layer_name, offset, structure_name):
|
||||
length = struct.calcsize(struct_format)
|
||||
def _struct_value(cls, context, layer_name, offset):
|
||||
length = struct.calcsize(cls._struct_format)
|
||||
data = context.memory.read(layer_name, offset, length)
|
||||
(value,) = struct.unpack(struct_format, data)
|
||||
(value,) = struct.unpack(cls._struct_format, data)
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def template_size(cls, arguments):
|
||||
def template_size(cls, template):
|
||||
"""Returns the size of the templated object"""
|
||||
return struct.calcsize(arguments.get('struct_format', '<I'))
|
||||
return struct.calcsize(cls._struct_format)
|
||||
|
||||
@classmethod
|
||||
def template_children(cls, arguments):
|
||||
def template_children(cls, template):
|
||||
"""Since primitives have no children, this returns an empty list"""
|
||||
return []
|
||||
|
||||
@classmethod
|
||||
def template_replace_child(cls, old_child, new_child, arguments):
|
||||
def template_replace_child(cls, old_child, new_child, volinfo):
|
||||
"""Since this template can't ever have children, this method can be empty"""
|
||||
|
||||
@classmethod
|
||||
def template_relative_child_offset(cls, arguments, child):
|
||||
def template_relative_child_offset(cls, volinfo, child):
|
||||
"""Since this template can't ever have children, this method can be empty as well"""
|
||||
|
||||
def write(self, value):
|
||||
"""Writes the object into the layer of the context at the current offset"""
|
||||
if isinstance(value, self._struct_type):
|
||||
data = struct.pack(self._struct_format, value)
|
||||
return self._context.memory.write(self.volinfo.layer_name, self.volinfo.offset, data)
|
||||
raise TypeError(
|
||||
repr(self.__class__.__name__) + " objects require a " + repr(type(self._struct_type)) + " to be written")
|
||||
|
||||
|
||||
class Integer(PrimitiveObject, int):
|
||||
"""Primitive Object that handles standard numeric types"""
|
||||
|
||||
def __new__(cls, context, layer_name, offset, structure_name, struct_format, **kwargs):
|
||||
return int.__new__(cls, cls._struct_value(struct_format, context, layer_name, offset, structure_name))
|
||||
|
||||
def write(self, value):
|
||||
"""Writes the object into the layer of the context at the current offset"""
|
||||
if isinstance(value, int):
|
||||
data = struct.pack(self._struct_format, value)
|
||||
return self._context.memory.write(self._layer_name, self._offset, data)
|
||||
raise TypeError("Integer objects require an integer to be written")
|
||||
|
||||
|
||||
class Float(PrimitiveObject, float):
|
||||
"""Primitive Object that handles double or floating point numbers"""
|
||||
|
||||
def __new__(cls, context, layer_name, offset, structure_name, struct_format, **kwargs):
|
||||
return float.__new__(cls, cls._struct_value(struct_format, context, layer_name, offset, structure_name))
|
||||
|
||||
def write(self, value):
|
||||
"""Writes the object into the layer of the context at the current offset"""
|
||||
if isinstance(value, float):
|
||||
data = struct.pack(self._struct_format, value)
|
||||
return self._context.memory.write(self._layer_name, self._offset, data)
|
||||
raise TypeError("Float objects require a float to be written")
|
||||
_struct_format = '<f'
|
||||
_struct_type = float
|
||||
|
||||
|
||||
class Bytes(PrimitiveObject, bytes):
|
||||
"""Primitive Object that handles specific series of bytes"""
|
||||
_struct_format = '1s'
|
||||
_struct_type = bytes
|
||||
|
||||
def __init__(self, context, layer_name, offset, structure_name, size = None, parent = None, length = 1):
|
||||
bytes.__init__(self)
|
||||
PrimitiveObject.__init__(self, context, layer_name, offset, structure_name,
|
||||
size, parent, struct_format = str(length) + 's')
|
||||
self.length = length
|
||||
|
||||
def __new__(cls, context, layer_name, offset, structure_name, length = 1, **kwargs):
|
||||
return bytes.__new__(cls, cls._struct_value(str(length) + "s", context, layer_name, offset, structure_name))
|
||||
|
||||
def write(self, value):
|
||||
"""Writes the object into the layer of the context at the current offset"""
|
||||
if isinstance(value, bytes):
|
||||
data = struct.pack(self._struct_format, value)
|
||||
return self._context.memory.write(self._layer_name, self._offset, data)
|
||||
raise TypeError("Bytes objects require a bytes type to be written")
|
||||
def __init__(self, context, template_info, object_info, length = 1):
|
||||
self._struct_format = str(length) + 's'
|
||||
self._volinfo['length'] = length
|
||||
PrimitiveObject.__init__(self, context, template_info, object_info)
|
||||
|
||||
|
||||
# TODO: Fix up strings unpacking to include an encoding
|
||||
class String(PrimitiveObject, str):
|
||||
"""Primitive Object that handles string values
|
||||
|
||||
length: specifies the maximum possible length that the string could hold in memory
|
||||
"""
|
||||
_struct_format = '1s'
|
||||
_struct_type = str
|
||||
|
||||
def __init__(self, context, layer_name, offset, structure_name, size = None, parent = None, length = 1):
|
||||
str.__init__(self)
|
||||
PrimitiveObject.__init__(self, context, layer_name, offset, structure_name,
|
||||
size, parent, struct_format = str(length) + 's')
|
||||
self.length = length
|
||||
|
||||
def __new__(cls, context, layer_name, offset, structure_name, length = 1, **kwargs):
|
||||
return str.__new__(cls, cls._struct_value(str(length) + "s", context, layer_name, offset, structure_name))
|
||||
|
||||
def write(self, value):
|
||||
"""Writes the object into the layer of the context at the current offset"""
|
||||
if isinstance(value, str):
|
||||
data = struct.pack(self._struct_format, value)
|
||||
return self._context.memory.write(self._layer_name, self._offset, data)
|
||||
raise TypeError("String objects require a string to be written")
|
||||
def __init__(self, context, template_info, object_info, length = 1, encoding = 'ascii'):
|
||||
self._struct_format = str(length) + 's'
|
||||
self._volinfo['length'] = length
|
||||
PrimitiveObject.__init__(self, context, template_info, object_info)
|
||||
|
||||
|
||||
class Pointer(Integer):
|
||||
"""Pointer which points to another object"""
|
||||
_struct_format = '<I'
|
||||
|
||||
def __init__(self, context, layer_name, offset, structure_name, size = None,
|
||||
parent = None, struct_format = None, target = None):
|
||||
if not isinstance(target, templates.ObjectTemplate):
|
||||
raise TypeError("Pointer targets must be an ObjectTemplate")
|
||||
def __init__(self, context, object_info, template_info, target = None):
|
||||
self._type_check(target, templates.ObjectTemplate)
|
||||
Integer.__init__(self,
|
||||
context,
|
||||
layer_name = layer_name,
|
||||
offset = offset,
|
||||
structure_name = structure_name,
|
||||
size = size,
|
||||
parent = parent,
|
||||
struct_format = struct_format)
|
||||
self._target = target
|
||||
self._cache = None
|
||||
self._cache_layer_name = None
|
||||
object_info,
|
||||
template_info)
|
||||
self._volinfo['target'] = target
|
||||
|
||||
def dereference(self, layer_name = None):
|
||||
"""Dereferences the pointer
|
||||
@@ -174,52 +144,50 @@ class Pointer(Integer):
|
||||
"""
|
||||
if layer_name is None:
|
||||
layer_name = self._layer_name
|
||||
# Cache the target
|
||||
if self._cache is None or (self._cache_layer_name != layer_name):
|
||||
self._cache_layer_name = self._layer_name
|
||||
self._cache = self._target(context = self._context,
|
||||
layer_name = layer_name,
|
||||
offset = self,
|
||||
parent = self)
|
||||
return self._cache
|
||||
return self._target(context = self._context,
|
||||
object_info = collections.ChainMap({'layer_name': layer_name,
|
||||
'offset': self,
|
||||
'parent': self}, self.volinfo))
|
||||
|
||||
def __getattr__(self, attr):
|
||||
"""Convenience function to access unknown attributes by getting them from the target object"""
|
||||
return getattr(self.dereference(), attr)
|
||||
|
||||
@classmethod
|
||||
def template_children(cls, arguments):
|
||||
def template_children(cls, template):
|
||||
"""Returns the children of the template"""
|
||||
if 'target' in arguments:
|
||||
return [arguments['target']]
|
||||
if 'target' in template.volinfo:
|
||||
return [template.volinfo.target]
|
||||
return []
|
||||
|
||||
@classmethod
|
||||
def template_replace_child(cls, old_child, new_child, arguments):
|
||||
def template_replace_child(cls, template, old_child, new_child):
|
||||
"""Substitutes the old_child for the new_child"""
|
||||
if 'target' in arguments:
|
||||
if arguments['target'] == old_child:
|
||||
arguments['target'] = new_child
|
||||
if 'target' in template.volinfo:
|
||||
if template.volinfo.target == old_child:
|
||||
template.update_volinfo(target = new_child)
|
||||
|
||||
|
||||
class BitField(PrimitiveObject, int):
|
||||
"""Object containing a field which is made up of bits rather than whole bytes"""
|
||||
|
||||
def __new__(cls, context, layer_name, offset, structure_name, size = None,
|
||||
parent = None, target = None, start_bit = 0, end_bit = 0, **kwargs):
|
||||
def __new__(cls, context, object_info, template_info, target = None, start_bit = 0, end_bit = 0, **kwargs):
|
||||
value = target(context = context,
|
||||
layer_name = layer_name,
|
||||
offset = offset,
|
||||
structure_name = structure_name,
|
||||
size = size,
|
||||
parent = parent)
|
||||
return (value >> start_bit) & ((1 << end_bit) - 1)
|
||||
object_info = object_info,
|
||||
template_info = template_info)
|
||||
return cls._struct_type.__new__(cls, (value >> start_bit) & ((1 << end_bit) - 1))
|
||||
|
||||
def __init__(self, context, object_info, template_info, target = None, start_bit = 0, end_bit = 0):
|
||||
PrimitiveObject.__init__(self, context, object_info, template_info)
|
||||
self._volinfo['target'] = target
|
||||
self._volinfo['start_bit'] = start_bit
|
||||
self._volinfo['end_bit'] = end_bit
|
||||
|
||||
@classmethod
|
||||
def template_children(cls, arguments):
|
||||
def template_children(cls, template):
|
||||
"""Returns the target type"""
|
||||
if 'target' in arguments:
|
||||
return [arguments['target']]
|
||||
if 'target' in template.volinfo:
|
||||
return [template.volinfo.target]
|
||||
return []
|
||||
|
||||
def write(self, value):
|
||||
@@ -230,7 +198,7 @@ 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):
|
||||
def template_children(cls, volinfo):
|
||||
return []
|
||||
|
||||
def write(self, value):
|
||||
@@ -240,58 +208,53 @@ class Enumeration(interfaces.objects.ObjectInterface):
|
||||
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")
|
||||
def __init__(self, context, object_info, template_info, count = 0, target = None):
|
||||
self._type_check(target, templates.ObjectTemplate)
|
||||
interfaces.objects.ObjectInterface.__init__(self,
|
||||
context = context,
|
||||
layer_name = layer_name,
|
||||
offset = offset,
|
||||
structure_name = structure_name,
|
||||
size = size,
|
||||
parent = parent)
|
||||
self._count = self._type_check(count, int)
|
||||
self._target = target
|
||||
object_info = object_info,
|
||||
template_info = template_info)
|
||||
self._volinfo['count'] = self._type_check(count, int)
|
||||
self._volinfo['target'] = target
|
||||
|
||||
@classmethod
|
||||
def template_size(cls, arguments):
|
||||
def template_size(cls, template):
|
||||
"""Returns the size of the array, based on the count and the target"""
|
||||
if 'target' not in arguments and 'count' not in arguments:
|
||||
if 'target' not in template.volinfo and 'count' not in template.volinfo:
|
||||
raise TypeError("Array ObjectTemplate must be provided a count and target")
|
||||
return arguments.get('target', None).size * arguments.get('count', 0)
|
||||
return template.volinfo.get('target', None).size * template.volinfo.get('count', 0)
|
||||
|
||||
@classmethod
|
||||
def template_children(cls, arguments):
|
||||
def template_children(cls, template):
|
||||
"""Returns the children of the template"""
|
||||
if 'target' in arguments:
|
||||
return [arguments['target']]
|
||||
if 'target' in template.volinfo:
|
||||
return [template.volinfo.target]
|
||||
return []
|
||||
|
||||
@classmethod
|
||||
def template_replace_child(cls, old_child, new_child, arguments):
|
||||
def template_replace_child(cls, template, old_child, new_child):
|
||||
"""Substitutes the old_child for the new_child"""
|
||||
if 'target' in arguments:
|
||||
if arguments['target'] == old_child:
|
||||
arguments['target'] = new_child
|
||||
if 'target' in template.volinfo:
|
||||
if template.volinfo['target'] == old_child:
|
||||
template.update_volinfo(target = new_child)
|
||||
|
||||
@classmethod
|
||||
def template_relative_child_offset(cls, arguments, child):
|
||||
def template_relative_child_offset(cls, template, child):
|
||||
"""Returns the relative offset from the head of the parent data to the child member"""
|
||||
if 'target' in arguments and child == 'target':
|
||||
if 'target' in template and child == 'target':
|
||||
return 0
|
||||
raise IndexError("Member " + child + " not present in array template")
|
||||
|
||||
def __getitem__(self, i):
|
||||
"""Returns the i-th item from the array"""
|
||||
if i >= self._count or 0 > i:
|
||||
if i >= self.volinfo.count or 0 > i:
|
||||
raise IndexError
|
||||
return self._target(context = self._context, layer_name = self._layer_name,
|
||||
offset = self._offset + (self._target.size * i), parent = self)
|
||||
return self.volinfo.target(context = self._context, layer_name = self.volinfo.layer_name,
|
||||
offset = self.volinfo.offset + (self.volinfo.target.size * i), parent = self)
|
||||
|
||||
def __len__(self):
|
||||
"""Returns the length of the array"""
|
||||
return self._count
|
||||
return self.volinfo.count
|
||||
|
||||
def write(self, value):
|
||||
raise NotImplementedError("Writing to Arrays is not yet implemented")
|
||||
@@ -303,53 +266,53 @@ class Struct(interfaces.objects.ObjectInterface):
|
||||
Keep the number of methods in this class low or very specific, since each one could overload a valid member.
|
||||
"""
|
||||
|
||||
def __init__(self, context, layer_name, offset, structure_name, size = None, members = None, parent = None):
|
||||
def __init__(self, context, object_info, template_info):
|
||||
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
|
||||
object_info = object_info,
|
||||
template_info = template_info)
|
||||
self._check_members(template_info.members)
|
||||
self._concrete_members = {}
|
||||
|
||||
@classmethod
|
||||
def template_size(cls, arguments):
|
||||
def template_size(cls, template):
|
||||
"""Method to return the size of this structure"""
|
||||
if arguments.get('size', None) is None:
|
||||
if template.volinfo.get('size', None) is None:
|
||||
raise TypeError("Struct ObjectTemplate not provided with a size")
|
||||
return arguments['size']
|
||||
return template.volinfo['size']
|
||||
|
||||
@classmethod
|
||||
def template_children(cls, arguments):
|
||||
def template_children(cls, template):
|
||||
"""Method to list children of a template"""
|
||||
return [member for _, member in cls._template_members(arguments).values()]
|
||||
return [member for _, member in cls._template_members(template).values()]
|
||||
|
||||
@classmethod
|
||||
def template_replace_child(cls, old_child, new_child, arguments):
|
||||
def template_replace_child(cls, template, old_child, new_child):
|
||||
"""Replace a child elements within the arguments handed to the template"""
|
||||
for member in arguments.get('members', {}):
|
||||
relative_offset, member_template = arguments['members'][member]
|
||||
for member in cls._template_members(template).get('members', {}):
|
||||
relative_offset, member_template = template.volinfo.members[member]
|
||||
if member_template == old_child:
|
||||
arguments['members'][member] = (relative_offset, new_child)
|
||||
# Members will give access to the mutable members list,
|
||||
# but in case that ever changes, do the update correctly
|
||||
tmp_list = template.volinfo.members
|
||||
tmp_list[member] = (relative_offset, new_child)
|
||||
template.update_volinfo(members = tmp_list)
|
||||
|
||||
@classmethod
|
||||
def template_relative_child_offset(cls, arguments, child):
|
||||
def template_relative_child_offset(cls, template, child):
|
||||
"""Returns the relative offset of a child to its parent"""
|
||||
retlist = cls._template_members(arguments).get(child, None)
|
||||
retlist = cls._template_members(template).get(child, None)
|
||||
if retlist is None:
|
||||
raise IndexError("Member " + child + " not present in template")
|
||||
return retlist[0]
|
||||
|
||||
@classmethod
|
||||
def _template_members(cls, arguments):
|
||||
def _template_members(cls, template):
|
||||
"""Returns the dictionary of member_names to (relative_offset, member) as provided in the template arguments"""
|
||||
if 'members' not in arguments:
|
||||
if 'members' not in template.volinfo:
|
||||
raise TypeError("Members not found in template arguments")
|
||||
cls._check_members(arguments.get('members', None))
|
||||
return arguments['members']
|
||||
cls._check_members(template.volinfo.members)
|
||||
return template.volinfo.members.copy()
|
||||
|
||||
@classmethod
|
||||
def _check_members(cls, members):
|
||||
@@ -368,13 +331,16 @@ class Struct(interfaces.objects.ObjectInterface):
|
||||
"""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)
|
||||
elif attr in self.volinfo.members:
|
||||
relative_offset, member = self.volinfo.members[attr]
|
||||
member = member(context = self._context,
|
||||
object_info = interfaces.objects.ObjectInformation(layer_name = self.volinfo.layer_name,
|
||||
offset = self.volinfo.offset + relative_offset,
|
||||
member_name = attr,
|
||||
parent = self))
|
||||
self._concrete_members[attr] = member
|
||||
return member
|
||||
raise AttributeError("'" + self._structure_name + "' Struct has no attribute '" + attr + "'")
|
||||
raise AttributeError("'" + self.volinfo.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")
|
||||
|
||||
@@ -18,9 +18,11 @@ class ObjectTemplate(interfaces.objects.Template, validity.ValidityRoutines):
|
||||
"""
|
||||
|
||||
def __init__(self, object_class = None, structure_name = None, **kwargs):
|
||||
interfaces.objects.Template.__init__(self, structure_name = structure_name, **kwargs)
|
||||
interfaces.objects.Template.__init__(self,
|
||||
structure_name = structure_name,
|
||||
**kwargs)
|
||||
self._class_check(object_class, interfaces.objects.ObjectInterface)
|
||||
self.object_class = object_class
|
||||
self.update_volinfo(object_class = object_class)
|
||||
|
||||
@classmethod
|
||||
def template_children(cls, **kwargs):
|
||||
@@ -33,7 +35,7 @@ class ObjectTemplate(interfaces.objects.Template, validity.ValidityRoutines):
|
||||
@property
|
||||
def size(self):
|
||||
"""Returns the size of the template"""
|
||||
return self.object_class.template_size(self._kwargs)
|
||||
return self.volinfo.object_class.template_size(self)
|
||||
|
||||
@property
|
||||
def children(self):
|
||||
@@ -41,33 +43,33 @@ class ObjectTemplate(interfaces.objects.Template, validity.ValidityRoutines):
|
||||
|
||||
This is used to traverse the template tree
|
||||
"""
|
||||
return self.object_class.template_children(self._kwargs)
|
||||
return self.volinfo.object_class.template_children(self)
|
||||
|
||||
def relative_child_offset(self, child):
|
||||
"""A function that returns the relative offset of a child from its parent offset
|
||||
|
||||
This may throw exceptions including ChildNotFoundException and NotImplementedError
|
||||
"""
|
||||
return self.object_class.template_relative_child_offset(self._kwargs, child)
|
||||
return self.volinfo.object_class.template_relative_child_offset(self, child)
|
||||
|
||||
def replace_child(self, old_child, new_child):
|
||||
"""A function for replacing one child with another
|
||||
|
||||
We pass in the kwargs directly so they can be changed
|
||||
"""
|
||||
self.object_class.template_replace_child(old_child, new_child, self._kwargs)
|
||||
self.volinfo.object_class.template_replace_child(self, old_child, new_child)
|
||||
|
||||
def __call__(self, context, layer_name, offset, parent = None):
|
||||
def __call__(self, context, object_info, **kwargs):
|
||||
"""Constructs the object
|
||||
|
||||
Returns: an object adhereing to the Object interface
|
||||
"""
|
||||
# We always use the template size (as calculated by the object class)
|
||||
# over the one passed in by an argument
|
||||
self._kwargs['size'] = self.size
|
||||
self._kwargs['structure_name'] = self.structure_name
|
||||
return self.object_class(context = context, layer_name = layer_name, offset = offset, parent = parent,
|
||||
**self._kwargs)
|
||||
return self.volinfo.object_class(context = context,
|
||||
object_info = object_info,
|
||||
template_info = self.volinfo,
|
||||
**kwargs)
|
||||
|
||||
|
||||
class ReferenceTemplate(interfaces.objects.Template):
|
||||
@@ -77,5 +79,5 @@ class ReferenceTemplate(interfaces.objects.Template):
|
||||
"""
|
||||
|
||||
def __call__(self, context, *args, **kwargs):
|
||||
template = context.symbol_space.get_structure(self._structure_name)
|
||||
template = context.symbol_space.get_structure(self.volinfo.structure_name)
|
||||
return template(context = context, *args, **kwargs)
|
||||
|
||||
@@ -97,16 +97,16 @@ class SymbolSpace(collections.Mapping):
|
||||
if isinstance(child, objects.templates.ReferenceTemplate):
|
||||
# If we haven't seen it before, subresolve it and also add it
|
||||
# to the "symbols that still need traversing" list
|
||||
if child.structure_name not in self._resolved:
|
||||
traverse_list.append(child.structure_name)
|
||||
self._resolved[child.structure_name] = self._weak_resolve(SymbolType.STRUCTURE,
|
||||
child.structure_name)
|
||||
if child.volinfo.structure_name not in self._resolved:
|
||||
traverse_list.append(child.volinfo.structure_name)
|
||||
self._resolved[child.volinfo.structure_name] = self._weak_resolve(SymbolType.STRUCTURE,
|
||||
child.volinfo.structure_name)
|
||||
# Stash the replacement
|
||||
replacements.add((traverser, child))
|
||||
elif child.children:
|
||||
template_traverse_list.append(child)
|
||||
for (parent, child) in replacements:
|
||||
parent.replace_child(child, self._resolved[child.structure_name])
|
||||
parent.replace_child(child, self._resolved[child.volinfo.structure_name])
|
||||
return self._resolved[structure_name]
|
||||
|
||||
def get_constant(self, constant_name):
|
||||
|
||||
@@ -79,7 +79,7 @@ class VTypeSymbolTable(interfaces.symbols.SymbolTableInterface):
|
||||
elif structure_name == 'BitField':
|
||||
update = dictionary[1]
|
||||
update['target'] = self._vtypedict_to_template([update['native_type']])
|
||||
native_template.update_arguments(**update) # pylint: disable=W0142
|
||||
native_template.update_volinfo(**update) # pylint: disable=W0142
|
||||
return native_template
|
||||
|
||||
# Otherwise
|
||||
@@ -104,5 +104,7 @@ class VTypeSymbolTable(interfaces.symbols.SymbolTableInterface):
|
||||
member = (relative_offset, self._vtypedict_to_template(vtypedict))
|
||||
members[member_name] = member
|
||||
object_class = self.get_structure_class(structure_name)
|
||||
return objects.templates.ObjectTemplate(object_class = object_class, structure_name = structure_name,
|
||||
size = size, members = members)
|
||||
return objects.templates.ObjectTemplate(structure_name = structure_name,
|
||||
object_class = object_class,
|
||||
size = size,
|
||||
members = members)
|
||||
|
||||
@@ -4144,7 +4144,7 @@ ntkrnlmp_types = {
|
||||
'_IO_STATUS_BLOCK': [0x8, {
|
||||
'Status': [0x0, ['long']],
|
||||
'Pointer': [0x0, ['pointer', ['void']]],
|
||||
'Information': [0x4, ['unsigned long']],
|
||||
'ReadOnlyInformation': [0x4, ['unsigned long']],
|
||||
}],
|
||||
'_LPCP_MESSAGE': [0x30, {
|
||||
'Entry': [0x0, ['_LIST_ENTRY']],
|
||||
|
||||
Reference in New Issue
Block a user