mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-12 20:57:39 +02:00
Flesh out symbol system, reworking several parts. Still requires on-demand resolving of symbols.
This commit is contained in:
+14
-6
@@ -4,14 +4,22 @@ Created on 10 Mar 2013
|
||||
@author: mike
|
||||
'''
|
||||
|
||||
from volatility.framework import xp_sp2_x86_vtypes, symbols
|
||||
from volatility.framework import xp_sp2_x86_vtypes, context
|
||||
from volatility.framework.symbols import vtypes, native
|
||||
|
||||
if __name__ == '__main__':
|
||||
vtypes = xp_sp2_x86_vtypes.ntkrnlmp_types
|
||||
virtual_types = xp_sp2_x86_vtypes.ntkrnlmp_types
|
||||
|
||||
ntkrnlmp = vtypes.VTypeSymbolList('ntkrnlmp', virtual_types)
|
||||
native = native.x86NativeSymbolList
|
||||
|
||||
ctx = context.Context()
|
||||
ctx.add_symbol_list(native)
|
||||
ctx.add_symbol_list(ntkrnlmp)
|
||||
print("Symbols,", native.symbols)
|
||||
|
||||
ntkrnlmp = symbols.VTypeSymbolList('ntkrnlmp', vtypes)
|
||||
sspace = symbols.SymbolSpace()
|
||||
sspace.append(ntkrnlmp)
|
||||
for i in ntkrnlmp.symbols:
|
||||
print(sspace.resolve('ntkrnlmp!' + i))
|
||||
symbol = ctx.resolve('ntkrnlmp!' + i)
|
||||
print(symbol)
|
||||
# objthing = symbol(context, layer_name = '', offset = 0)
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ Created on 12 Feb 2013
|
||||
'''
|
||||
|
||||
import volatility.framework.symbols as symbols
|
||||
import volatility.framework.exceptions as exceptions
|
||||
|
||||
class Context(object):
|
||||
"""Maintains the context within which to construct objects"""
|
||||
@@ -18,14 +17,15 @@ class Context(object):
|
||||
|
||||
def add_symbol_list(self, symbol_list):
|
||||
"""Adds a symbol list to the symbol space used by the context"""
|
||||
if symbol_list.name in self._symbol_space:
|
||||
raise exceptions.SymbolSpaceError("Symbol list " + symbol_list.name + " already exists in this space.")
|
||||
self._symbol_space[symbol_list.name] = symbol_list
|
||||
self._symbol_space.append(symbol_list)
|
||||
|
||||
def remove_symbol_list(self, symbol_list_name):
|
||||
if not symbol_list_name in self._symbol_space:
|
||||
raise exceptions.SymbolSpaceError("No symbol list named " + symbol_list_name + " present in the symbol space.")
|
||||
del self._symbol_space[symbol_list_name]
|
||||
"""Removes a symbol list from the symbol space used by the context"""
|
||||
self._symbol_space.remove(symbol_list_name)
|
||||
|
||||
def resolve(self, symbol_name):
|
||||
"""Resolves a symbol name from the various symbol lists in the symbol space"""
|
||||
return self._symbol_space.resolve(symbol_name)
|
||||
|
||||
### Address Space Functions
|
||||
|
||||
@@ -35,7 +35,7 @@ class Context(object):
|
||||
|
||||
### Object Factory Functions
|
||||
|
||||
def object(self, symbol, offset, layername = None):
|
||||
def object(self, symbol, layer_name, offset):
|
||||
"""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,
|
||||
@@ -44,5 +44,5 @@ class Context(object):
|
||||
Returns a fully constructed object
|
||||
"""
|
||||
object_template = self._symbol_space.resolve(symbol)
|
||||
return object_template(v)
|
||||
return object_template(self, layer_name = layer_name, offset = offset)
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
'''
|
||||
Created on 12 Apr 2013
|
||||
|
||||
@author: mike
|
||||
'''
|
||||
|
||||
class ObjectInterface(object):
|
||||
""" A base object required to be the ancestor of every object used in volatility """
|
||||
def __init__(self, context, layer_name, offset, symbol_name, size, **kwargs):
|
||||
self._context = context
|
||||
self._offset = offset
|
||||
self._layer_name = layer_name
|
||||
self._symbol_name = symbol_name
|
||||
self._size = size
|
||||
|
||||
def cast(self, new_symbol_name):
|
||||
object_template = self._context.resolve()
|
||||
return object_template(context = self._context, layer_name = self._layer_name, offset = self._offset)
|
||||
+46
-14
@@ -6,18 +6,10 @@ Created on 17 Feb 2013
|
||||
|
||||
import struct
|
||||
import collections
|
||||
import volatility.framework.interfaces as interfaces
|
||||
import volatility.framework.templates as templates
|
||||
|
||||
class ObjectInterface(object):
|
||||
""" A base object required to be the ancestor of every object used in volatility """
|
||||
def __init__(self, context, layer_name, offset, symbol_name, size, **kwargs):
|
||||
self._context = context
|
||||
self._offset = offset
|
||||
self._layer_name = layer_name
|
||||
self._symbol_name = symbol_name
|
||||
self._size = size
|
||||
|
||||
class PrimitiveObject(ObjectInterface):
|
||||
class PrimitiveObject(interfaces.ObjectInterface):
|
||||
"""PrimitiveObject is an interface for any objects that should simulate a Python primitive"""
|
||||
|
||||
@classmethod
|
||||
@@ -32,7 +24,7 @@ class Integer(PrimitiveObject, int):
|
||||
"""Primitive Object that handles standard numeric types"""
|
||||
|
||||
def __new__(cls, context, layer_name, offset, symbol_name, struct_format, **kwargs):
|
||||
struct_format, struct_size = context.get_primitive_struct_type("int", symbol_name)
|
||||
struct_format = context.get_primitive_struct_type("int", symbol_name)
|
||||
struct_size = struct.calcsize(struct_format)
|
||||
return cls._struct_value(struct_format, context, layer_name, offset, symbol_name, size = struct_size)
|
||||
|
||||
@@ -40,7 +32,7 @@ class Float(PrimitiveObject, float):
|
||||
"""Primitive Object that handles double or floating point numbers"""
|
||||
|
||||
def __new__(cls, context, layer_name, offset, symbol_name, size, **kwargs):
|
||||
struct_format, struct_size = context.get_primitive_struct_type("float", symbol_name)
|
||||
struct_format = context.get_primitive_struct_type("float", symbol_name)
|
||||
struct_size = struct.calcsize(struct_format)
|
||||
return cls._struct_value(struct_format, context, layer_name, offset, symbol_name, size = struct_size)
|
||||
|
||||
@@ -60,7 +52,41 @@ class String(PrimitiveObject, str):
|
||||
def __new__(cls, context, layer_name, offset, symbol_name, size = None, length = 1):
|
||||
return cls._struct_value(str(length) + "s", context, layer_name, offset, symbol_name, size)
|
||||
|
||||
class Struct(ObjectInterface):
|
||||
class Pointer(Integer):
|
||||
"""Pointer which points to another object"""
|
||||
def __init__(self, context, layer_name, offset, symbol_name, size = None, target = None):
|
||||
if not isinstance(target, interfaces.ObjectInterface):
|
||||
raise TypeError("Pointer targets must be an ObjectInterface")
|
||||
super(Pointer, self).__init__(context, layer_name, offset, symbol_name, size)
|
||||
self._target = target
|
||||
|
||||
def derefenence(self):
|
||||
"""Dereferences the pointer"""
|
||||
# Cache the target
|
||||
if isinstance(self._target, templates.ObjectTemplate):
|
||||
self._target = self.target(context = self._context, layer_name = self._layer_name, offset = self, self = self._target.size, parent = self)
|
||||
return self._target
|
||||
|
||||
def __getattr__(self, attr):
|
||||
"""Convenience function to access unknown attributes by getting them from the target object"""
|
||||
return getattr(self.dereference(), attr)
|
||||
|
||||
class BitField(Integer):
|
||||
""""""
|
||||
def __new__(self, context, layer_name, offset, symbol_name, size = None, start_bit = 0, end_bit = 0):
|
||||
# TODO: Determine endianness of the bitfield
|
||||
struct_size = (end_bit + 7) // 8
|
||||
if struct_size == 1:
|
||||
struct_format = "c"
|
||||
elif struct_size <= 2:
|
||||
struct_format = "H"
|
||||
elif struct_size <= 4:
|
||||
struct_format = "I"
|
||||
else:
|
||||
struct_format = "Q"
|
||||
return super(BitField, self).__new__(context, layer_name, offset, symbol_name, size = None, struct_format = struct_format)
|
||||
|
||||
class Struct(interfaces.ObjectInterface):
|
||||
"""Object which can contain members that are other objects"""
|
||||
|
||||
def __init__(self, context, layer_name, offset, symbol_name, size = None, members = None):
|
||||
@@ -79,6 +105,12 @@ class Struct(ObjectInterface):
|
||||
self._members = members
|
||||
|
||||
def __getattr__(self, attr):
|
||||
"""Method for accessing members of the structure"""
|
||||
if attr in self._members:
|
||||
return self._members[attr]
|
||||
member = self._members[attr]
|
||||
# Cache the constructed object
|
||||
if isinstance(member, templates.ObjectTemplate):
|
||||
member = member(context = self.context, layer_name = self.layer_name, offset = self.offset + member.relative_offset, parent = self)
|
||||
self._members[attr] = member
|
||||
return member
|
||||
raise AttributeError("'" + self._symbol_name + "' Struct has no attribute '" + attr + "'")
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
'''
|
||||
Created on 7 Feb 2013
|
||||
|
||||
@author: mike
|
||||
'''
|
||||
|
||||
import volatility.framework.exceptions as exceptions
|
||||
from volatility.framework import templates
|
||||
from volatility.framework import obj
|
||||
|
||||
class SymbolSpace(list):
|
||||
"""Handles a collection of SymbolLists"""
|
||||
|
||||
def resolve(self, symbol):
|
||||
symarr = symbol.split("!")
|
||||
if len(symarr) == 2:
|
||||
listname = symarr[0]
|
||||
symname = symarr[1]
|
||||
for symlist in self:
|
||||
if symlist.name == listname:
|
||||
if symname in symlist:
|
||||
return symlist.resolve(symname)
|
||||
else:
|
||||
raise exceptions.SymbolNotFoundException("Symbol " + symname + " could not be found in the " + listname + " list")
|
||||
else:
|
||||
raise exceptions.SymbolNotFoundException("Symbol list " + listname + " was not present in the symbol space")
|
||||
elif len(symarr) == 1:
|
||||
for slist in self:
|
||||
if symbol in slist:
|
||||
return slist.resolve(symbol)
|
||||
else:
|
||||
raise exceptions.SymbolNotFoundException("Symbol " + symbol + " could not be found in any symbol list")
|
||||
else:
|
||||
raise exceptions.SymbolNotFoundException("Malformed symbol name")
|
||||
|
||||
# Consider maintaining a list of symbollist names
|
||||
# A list of potentially conflicting symbols (for when no listname is provided)
|
||||
|
||||
class SymbolListInterface(object):
|
||||
"""Handles a list of symbols"""
|
||||
|
||||
def __init__(self, name, *args, **kwargs):
|
||||
super(SymbolListInterface, self).__init__(*args, **kwargs)
|
||||
if not isinstance(name, str) or not name:
|
||||
raise exceptions.SymbolSpaceError("Symbol lists cannot be nameless")
|
||||
self.name = name
|
||||
|
||||
### Required Symbol List functions
|
||||
|
||||
def resolve(self, symbol):
|
||||
"""Resolves a symbol name into an object template"""
|
||||
|
||||
@property
|
||||
def symbols(self):
|
||||
"""Returns an iterator of the symbol names"""
|
||||
|
||||
def set_object_class(self, symbol, clazz):
|
||||
"""Overrides the object class for a specific symbol"""
|
||||
|
||||
def get_object_class(self, symbol):
|
||||
"""Returns the class associated with a symbol"""
|
||||
|
||||
### Helper functions that can be overridden
|
||||
|
||||
def __len__(self):
|
||||
"""Returns the number of items in the symbol list"""
|
||||
return len(self.symbols)
|
||||
|
||||
def __getitem__(self, key):
|
||||
"""Resolves a symbol name into an object template"""
|
||||
return self.resolve(key)
|
||||
|
||||
def __iter__(self):
|
||||
"""Returns an iterator of the available keys"""
|
||||
return self.symbols
|
||||
|
||||
def __contains__(self, symbol):
|
||||
"""Determines whether a symbol exists in the list or not"""
|
||||
return symbol in self.symbols
|
||||
|
||||
class VTypeSymbolList(SymbolListInterface):
|
||||
"""Symbol List that handles"""
|
||||
|
||||
def __init__(self, name, vtype_dictionary):
|
||||
super(VTypeSymbolList, self).__init__(name)
|
||||
self._vtypedict = vtype_dictionary
|
||||
self._classdict = {}
|
||||
|
||||
def _vtypedict_to_template(self, dictionary):
|
||||
"""Converts a vtypedict into an object template"""
|
||||
if not dictionary:
|
||||
raise exceptions.SymbolSpaceError("Invalid vtype dictionary: " + repr(dictionary))
|
||||
# print(repr(dictionary))
|
||||
|
||||
symbol_name = dictionary[0]
|
||||
result = {"objclass": self.get_object_class(symbol_name), "symbol_name": symbol_name, "size" : 0}
|
||||
|
||||
# Handle specific vtypes
|
||||
if symbol_name == 'array':
|
||||
result["length"] = dictionary[1]
|
||||
result["target"] = templates.ObjectTemplate(**self._vtypedict_to_template(dictionary[2]))
|
||||
result["size"] = dictionary[1] * result["target"].size
|
||||
elif symbol_name == 'pointer':
|
||||
result["target"] = templates.ObjectTemplate(**self._vtypedict_to_template(dictionary[1]))
|
||||
elif symbol_name == 'Enumeration':
|
||||
result.update(dictionary[1])
|
||||
result["target"] = templates.ObjectTemplate(**self._vtypedict_to_template([result["target"]]))
|
||||
elif symbol_name == 'BitField':
|
||||
result["fields"] = dictionary[1]
|
||||
elif len(dictionary) > 1:
|
||||
raise exceptions.SymbolSpaceError("Unknown vtype format: " + repr(dictionary))
|
||||
|
||||
# print(result)
|
||||
return result
|
||||
|
||||
def set_object_class(self, key, value):
|
||||
"""Overrides a symbol's class from a Struct to the value"""
|
||||
self._classdict[key] = value
|
||||
|
||||
def get_object_class(self, key):
|
||||
return self._classdict.get(key, obj.Struct)
|
||||
|
||||
@property
|
||||
def symbols(self):
|
||||
"""Returns an iterator of the symbol names"""
|
||||
return set(self._classdict.keys()).union(set(self._vtypedict.keys()))
|
||||
|
||||
def resolve(self, symbolname):
|
||||
if symbolname not in self._vtypedict:
|
||||
raise exceptions.SymbolNotFoundException
|
||||
size, curdict = self._vtypedict[symbolname]
|
||||
members = []
|
||||
for item in curdict:
|
||||
relative_offset, vtypedict = curdict[item]
|
||||
member = templates.MemberTemplate(relative_offset = relative_offset, **self._vtypedict_to_template(vtypedict))
|
||||
members.append(member)
|
||||
return templates.ObjectTemplate(self.get_object_class(symbolname), symbol_name = symbolname, size = size, members = members)
|
||||
@@ -0,0 +1,141 @@
|
||||
'''
|
||||
Created on 7 Feb 2013
|
||||
|
||||
@author: mike
|
||||
'''
|
||||
|
||||
import collections
|
||||
import volatility.framework.exceptions as exceptions
|
||||
from volatility.framework import obj, templates, interfaces
|
||||
from volatility.framework.exceptions import SymbolNotFoundException
|
||||
|
||||
class SymbolSpace(collections.Mapping):
|
||||
"""Handles an ordered collection of SymbolLists
|
||||
|
||||
This collection is ordered so that resolution of symbols can
|
||||
proceed down through the ranks if a namespace isn't specified.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._dict = collections.OrderedDict()
|
||||
|
||||
def __len__(self):
|
||||
return len(self._dict)
|
||||
|
||||
def __getitem__(self, i):
|
||||
return self._dict[i]
|
||||
|
||||
def __iter__(self):
|
||||
return self._dict.__iter__(self)
|
||||
|
||||
def append(self, value):
|
||||
"""Adds a symbol_list to the end of the space"""
|
||||
if not isinstance(value, SymbolListInterface):
|
||||
raise TypeError(value)
|
||||
if value.name in self._dict:
|
||||
del self._dict[value.name]
|
||||
self._dict[value.name] = value
|
||||
|
||||
def remove(self, key):
|
||||
"""Removes a named symbol_list from the space"""
|
||||
del self._dict[key]
|
||||
|
||||
def resolve(self, symbol, start_from = None):
|
||||
"""Takes a symbol name and resolves it"""
|
||||
symarr = symbol.split("!")
|
||||
if len(symarr) == 2:
|
||||
listname = symarr[0]
|
||||
symname = symarr[1]
|
||||
for symlistname in reversed(self._dict):
|
||||
if symlistname == listname:
|
||||
if symname in self[symlistname]:
|
||||
return self[symlistname].resolve(symname, self)
|
||||
else:
|
||||
raise exceptions.SymbolNotFoundException("Symbol \"" + symname + "\" could not be found in the \"" + listname + "\" list")
|
||||
else:
|
||||
raise exceptions.SymbolNotFoundException("Symbol list \"" + listname + "\" was not present in the symbol space")
|
||||
elif len(symarr) == 1:
|
||||
# Establish skipping all elements before the symbol list to start from
|
||||
skip = (start_from is not None)
|
||||
for slist in reversed(self._dict):
|
||||
if skip:
|
||||
skip = (slist.name != start_from)
|
||||
else:
|
||||
if symbol in self[slist]:
|
||||
return self[slist].resolve(symbol, self)
|
||||
else:
|
||||
if skip:
|
||||
raise exceptions.SymbolSpaceError("Symbol search for \"" + symbol + "\" failed because symbol list \"" + start_from.name + "\" is not in the search space")
|
||||
raise exceptions.SymbolNotFoundException("Symbol \"" + symbol + "\" could not be found in any symbol list")
|
||||
else:
|
||||
raise exceptions.SymbolNotFoundException("Malformed symbol name")
|
||||
raise RuntimeError("Symbol Space Resolution hit an unexpected branch!")
|
||||
|
||||
class SymbolListInterface(object):
|
||||
"""Handles a list of symbols"""
|
||||
|
||||
def __init__(self, name, symbol_space = None, *args, **kwargs):
|
||||
super(SymbolListInterface, self).__init__(*args, **kwargs)
|
||||
if not isinstance(name, str) or not name:
|
||||
raise exceptions.SymbolSpaceError("Symbol lists cannot be nameless")
|
||||
self.name = name
|
||||
self._overrides = {}
|
||||
|
||||
### Required Symbol List functions
|
||||
|
||||
def resolve(self, symbol, symbol_space = None):
|
||||
"""Resolves a symbol name into an object template
|
||||
|
||||
symbol_space is used to resolve any target symbols if they don't exist in this list
|
||||
"""
|
||||
|
||||
@property
|
||||
def symbols(self):
|
||||
"""Returns an iterator of the symbol names"""
|
||||
|
||||
### Functions for overriding classes
|
||||
|
||||
def set_symbol_class(self, symbol, clazz):
|
||||
"""Overrides the object class for a specific symbol
|
||||
|
||||
We can only override existing classes, otherwise determining the complete symbol list
|
||||
will become complicated for each subclass.
|
||||
"""
|
||||
if not symbol in self.symbols:
|
||||
raise exceptions.SymbolNotFoundException("Cannot override \"" + symbol + "\" in \"" + self.name + "\", symbol not already present")
|
||||
if not issubclass(clazz, interfaces.ObjectInterface):
|
||||
raise exceptions.SymbolSpaceError("Attempting to add an object that does not inherit from ObjectInterface as a symbol class override")
|
||||
self._overrides[symbol] = clazz
|
||||
|
||||
def has_symbol_class(self, symbol):
|
||||
"""Returns whether the symbol's class has bee overridden or not"""
|
||||
return symbol in self._overrides
|
||||
|
||||
def get_symbol_class(self, symbol):
|
||||
"""Returns the class associated with a symbol or None if there is no associated symbol
|
||||
"""
|
||||
return self._overrides[symbol]
|
||||
|
||||
def del_symbol_class(self, symbol):
|
||||
"""Removes the associated class override for a specific symbol"""
|
||||
del self._overrides[symbol]
|
||||
|
||||
### Helper functions that can be overridden
|
||||
|
||||
def __len__(self):
|
||||
"""Returns the number of items in the symbol list"""
|
||||
return len(self.symbols)
|
||||
|
||||
def __getitem__(self, key):
|
||||
"""Resolves a symbol name into an object template"""
|
||||
return self.resolve(key)
|
||||
|
||||
def __iter__(self):
|
||||
"""Returns an iterator of the available keys"""
|
||||
return self.symbols
|
||||
|
||||
def __contains__(self, symbol):
|
||||
"""Determines whether a symbol exists in the list or not"""
|
||||
return symbol in self.symbols
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
'''
|
||||
Created on 10 Apr 2013
|
||||
|
||||
@author: mike
|
||||
'''
|
||||
import copy
|
||||
import struct
|
||||
import volatility.framework.obj as obj
|
||||
import volatility.framework.symbols as symbols
|
||||
import volatility.framework.templates as templates
|
||||
import volatility.framework.exceptions as exceptions
|
||||
|
||||
class NativeSymbolList(symbols.SymbolListInterface):
|
||||
"""Symbol List that handles Native types"""
|
||||
|
||||
def __init__(self, name, native_dictionary):
|
||||
super(NativeSymbolList, self).__init__(name)
|
||||
self._native_dictionary = native_dictionary
|
||||
for item in self._native_dictionary:
|
||||
self._overrides[item] = obj.Integer
|
||||
|
||||
@property
|
||||
def symbols(self):
|
||||
return self._native_dictionary.keys()
|
||||
|
||||
def resolve(self, symbol, symbol_space = None):
|
||||
"""Resolve the native symbols by looking up their struct types in a dictionary"""
|
||||
if symbol in self._native_dictionary:
|
||||
fmt = self._native_dictionary[symbol]
|
||||
return templates.ObjectTemplate(self.get_symbol_class(symbol), symbol_name = symbol, size = struct.calcsize(fmt), format_string = fmt)
|
||||
if isinstance(symbol_space, symbols.SymbolSpace):
|
||||
return symbol_space.resolve(symbol, self.name)
|
||||
raise exceptions.SymbolNotFoundException()
|
||||
|
||||
x86_native_types = {'int' : '<i',
|
||||
'long': '<i',
|
||||
'unsigned long' : '<I',
|
||||
'unsigned int' : '<I',
|
||||
'address' : '<I',
|
||||
'char' : '<c',
|
||||
'unsigned char' : '<B',
|
||||
'unsigned short int' : '<H',
|
||||
'unsigned short' : '<H',
|
||||
'unsigned be short' : '>H',
|
||||
'short' : '<h',
|
||||
'long long' : '<q',
|
||||
'unsigned long long' : '<Q',
|
||||
'void': "<I",
|
||||
'float': "",
|
||||
'double': "d"}
|
||||
x64_native_types = copy.deepcopy(x86_native_types)
|
||||
x64_native_types['address'] = '<Q'
|
||||
|
||||
x86NativeSymbolList = NativeSymbolList("native", x86_native_types)
|
||||
x64NativeSymbolList = NativeSymbolList("native", x64_native_types)
|
||||
for ftype in ['double', 'float']:
|
||||
x86NativeSymbolList.set_symbol_class(ftype, obj.Float)
|
||||
x64NativeSymbolList.set_symbol_class(ftype, obj.Float)
|
||||
@@ -0,0 +1,98 @@
|
||||
'''
|
||||
Created on 10 Apr 2013
|
||||
|
||||
@author: mike
|
||||
'''
|
||||
|
||||
import volatility.framework.exceptions as exceptions
|
||||
import volatility.framework.symbols as symbols
|
||||
import volatility.framework.templates as templates
|
||||
import volatility.framework.obj as obj
|
||||
|
||||
### TODO
|
||||
#
|
||||
# All symbol lists should take a label to an object template
|
||||
#
|
||||
# Templates for targets etc should be looked up recursively just like anything else
|
||||
# We therefore need a way to unroll rolled-up types
|
||||
# Generate mangled names on the fly (prohibits external calling)
|
||||
#
|
||||
# Symbol list could be a dict with knowledge of its parent?
|
||||
# Class split is arbitrary, it's an extension for developers
|
||||
# Object template should contain both class and initial parameters
|
||||
|
||||
|
||||
class VTypeSymbolList(symbols.SymbolListInterface):
|
||||
"""Symbol List that handles vtype datastructures"""
|
||||
|
||||
def __init__(self, name, vtype_dictionary):
|
||||
super(VTypeSymbolList, self).__init__(name)
|
||||
self._vtypedict = vtype_dictionary
|
||||
self._default_object_class = obj.Struct
|
||||
|
||||
def _vtypedict_to_template(self, dictionary, symbol_space = None):
|
||||
"""Converts a vtypedict into an object template"""
|
||||
if not dictionary:
|
||||
raise exceptions.SymbolSpaceError("Invalid vtype dictionary: " + repr(dictionary))
|
||||
# print(repr(dictionary))
|
||||
|
||||
symbol_name = dictionary[0]
|
||||
# Establish the defaults
|
||||
result = {"object_class": self._default_object_class, "symbol_name": symbol_name, "size" : 0}
|
||||
|
||||
# Can we handle the next layer ourselves?
|
||||
if symbol_name in self.symbols:
|
||||
# Check if the class has been overridden
|
||||
if self.has_symbol_class(symbol_name):
|
||||
result["object_class"] = self.get_symbol_class(symbol_name)
|
||||
if symbol_name not in self.symbols:
|
||||
# Handle specific "well known" symbols
|
||||
if symbol_name == 'array':
|
||||
result["object_class"] = obj.Integer
|
||||
result["count"] = dictionary[1]
|
||||
result["target"] = self._vtypedict_to_template(dictionary[2], symbol_space = symbol_space)
|
||||
result["size"] = dictionary[1] * result["target"].size
|
||||
elif symbol_name == 'pointer':
|
||||
result["object_class"] = obj.Pointer
|
||||
result["target"] = self._vtypedict_to_template(dictionary[1], symbol_space = symbol_space)
|
||||
elif symbol_name == 'Enumeration':
|
||||
result["object_class"] = obj.Integer
|
||||
result.update(dictionary[1])
|
||||
result["target"] = self._vtypedict_to_template([result["target"]], symbol_space = symbol_space)
|
||||
elif symbol_name == 'BitField':
|
||||
result["object_class"] = obj.Pointer
|
||||
result["fields"] = dictionary[1]
|
||||
elif symbol_name == 'void':
|
||||
result["object_class"] = obj.Integer
|
||||
elif len(dictionary) > 1:
|
||||
raise exceptions.SymbolSpaceError("Unknown vtype format: " + repr(dictionary))
|
||||
elif isinstance(symbol_space, symbols.SymbolSpace):
|
||||
# Resolve the object class for this
|
||||
return symbol_space.resolve(symbol_name)
|
||||
else:
|
||||
raise exceptions.SymbolNotFoundException("Unable to resolve \"" + symbol_name + "\" in \"" + self.name + "\", no symbol space to rescurse through")
|
||||
elif self.has_symbol_class(symbol_name):
|
||||
result["object_class"] = self.get_symbol_class(symbol_name)
|
||||
|
||||
print(result)
|
||||
return templates.ObjectTemplate(**result) #pylint: disable-msg=W0142
|
||||
|
||||
@property
|
||||
def symbols(self):
|
||||
"""Returns an iterator of the symbol names"""
|
||||
return self._vtypedict.keys()
|
||||
|
||||
def resolve(self, symbol_name, symbol_space = None):
|
||||
"""Resolves an individual symbol"""
|
||||
if symbol_name not in self._vtypedict:
|
||||
raise exceptions.SymbolNotFoundException
|
||||
size, curdict = self._vtypedict[symbol_name]
|
||||
members = {}
|
||||
for member_name in curdict:
|
||||
relative_offset, vtypedict = curdict[member_name]
|
||||
member = templates.member_from_object_template(relative_offset = relative_offset, object_template = self._vtypedict_to_template(vtypedict, symbol_space))
|
||||
members[member_name] = member
|
||||
object_class = self._default_object_class
|
||||
if self.has_symbol_class(symbol_name):
|
||||
object_class = self.get_symbol_class(symbol_name)
|
||||
return templates.ObjectTemplate(object_class = object_class, symbol_name = symbol_name, size = size, members = members)
|
||||
@@ -4,6 +4,9 @@ Created on 1 Mar 2013
|
||||
@author: mike
|
||||
'''
|
||||
|
||||
import copy
|
||||
import volatility.framework.interfaces as interfaces
|
||||
|
||||
class ObjectTemplate(object):
|
||||
"""Factory class that produces objects that adhere to the Object interface on demand
|
||||
|
||||
@@ -13,13 +16,19 @@ class ObjectTemplate(object):
|
||||
* Members, etc
|
||||
etc.
|
||||
"""
|
||||
def __init__(self, objclass, symbol_name = None, size = None, **kwargs):
|
||||
self._objclass = objclass
|
||||
def __init__(self, object_class = None, symbol_name = None, size = None, **kwargs):
|
||||
if not issubclass(object_class, interfaces.ObjectInterface):
|
||||
raise TypeError("ObjectTemplate object_class must be a class, not " + str(type(object_class)))
|
||||
if not isinstance(size, int):
|
||||
raise TypeError("ObjectTemplate size must be numeric, not " + str(type(size)))
|
||||
self._size = size
|
||||
self._symbol_name = symbol_name
|
||||
self._kwargs = kwargs
|
||||
self._object_class = object_class
|
||||
|
||||
@property
|
||||
def object_class(self):
|
||||
return self._object_class
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
@@ -30,12 +39,26 @@ class ObjectTemplate(object):
|
||||
"""Returns the name of the symbol if one was provided"""
|
||||
return self._symbol_name
|
||||
|
||||
def __call__(self, context, offset, layer_name, parent = None):
|
||||
@property
|
||||
def kwargs(self):
|
||||
return copy.deepcopy(self._kwargs)
|
||||
|
||||
def __call__(self, context, layer_name, offset, parent = None):
|
||||
"""Constructs the object
|
||||
|
||||
Returns: an object adhereing to the Object interface
|
||||
"""
|
||||
return self._objclass(context, layer_name, offset, self.symbol_name, self.size, parent, **self._kwargs)
|
||||
return self._object_class(context = context, layer_name = layer_name, offset = offset, symbol_name = self.symbol_name, size = self.size, parent = parent, **self._kwargs)
|
||||
|
||||
def member_from_object_template(relative_offset, object_template):
|
||||
"""Returns a MemberTemplate based upon an existing ObjectTemplate"""
|
||||
if not isinstance(object_template, ObjectTemplate):
|
||||
raise TypeError("object_template must be an ObjectTemplate, not " + str(type(object_template)))
|
||||
return MemberTemplate(relative_offset = relative_offset,
|
||||
object_class = object_template.object_class,
|
||||
symbol_name = object_template.symbol_name,
|
||||
size = object_template.size,
|
||||
**object_template.kwargs)
|
||||
|
||||
class MemberTemplate(ObjectTemplate):
|
||||
"""Factory class that produces members of Structs
|
||||
@@ -43,13 +66,12 @@ class MemberTemplate(ObjectTemplate):
|
||||
This is just like a normal ObjectTemplate, but contains the relative offset
|
||||
fron the parent object.
|
||||
"""
|
||||
def __init__(self, objclass, symbol_name = None, size = None, relative_offset = None, *args, **kwargs):
|
||||
def __init__(self, relative_offset, **kwargs):
|
||||
super(MemberTemplate, self).__init__(**kwargs)
|
||||
if not isinstance(relative_offset, int):
|
||||
raise TypeError("MemberTemplate relative_offset must be numeric, not " + str(type(relative_offset)))
|
||||
self._reloffset = relative_offset
|
||||
ObjectTemplate.__init__(self, objclass, symbol_name, size, *args, **kwargs)
|
||||
self._relative_offset = relative_offset
|
||||
|
||||
@property
|
||||
def relative_offset(self):
|
||||
return self._reloffset
|
||||
|
||||
return self._relative_offset
|
||||
|
||||
@@ -4261,7 +4261,6 @@ ntkrnlmp_types = {
|
||||
'DeviceObject' : [ 0x4, ['pointer', ['_DEVICE_OBJECT']]],
|
||||
} ],
|
||||
'__unnamed_17fb' : [ 0x4, {
|
||||
'Srb' : [ 0x0, ['pointer', ['_SCSI_REQUEST_BLOCK']]],
|
||||
} ],
|
||||
'__unnamed_17ff' : [ 0x10, {
|
||||
'Length' : [ 0x0, ['unsigned long']],
|
||||
@@ -5014,7 +5013,6 @@ ntkrnlmp_types = {
|
||||
'OpenRoutine' : [ 0x2c, ['pointer', ['void']]],
|
||||
'WriteRoutine' : [ 0x30, ['pointer', ['void']]],
|
||||
'FinishRoutine' : [ 0x34, ['pointer', ['void']]],
|
||||
'AdapterObject' : [ 0x38, ['pointer', ['_ADAPTER_OBJECT']]],
|
||||
'MappedRegisterBase' : [ 0x3c, ['pointer', ['void']]],
|
||||
'PortConfiguration' : [ 0x40, ['pointer', ['void']]],
|
||||
'CrashDump' : [ 0x44, ['unsigned char']],
|
||||
|
||||
Reference in New Issue
Block a user