Enhance symbol listing and templates, add in gitignore and test rig.

This commit is contained in:
Mike Auty
2013-03-11 01:36:56 +00:00
parent f1279cae3a
commit 6105a2e4bc
6 changed files with 127 additions and 43 deletions
+2
View File
@@ -0,0 +1,2 @@
__pycache__
*.pyc
+16
View File
@@ -0,0 +1,16 @@
'''
Created on 10 Mar 2013
@author: mike
'''
from volatility.framework import xp_sp2_x86_vtypes, symbols
if __name__ == '__main__':
vtypes = xp_sp2_x86_vtypes.ntkrnlmp_types
ntkrnlmp = symbols.VTypeSymbolList('ntkrnlmp', vtypes)
sspace = symbols.SymbolSpace()
sspace.append(ntkrnlmp)
sspace.resolve('ntkrnlmp!_FXSAVE_FORMAT')
+6 -7
View File
@@ -15,19 +15,18 @@ _current = 3 # Number of releases of the library with any change
_revision = 0 # Number of changes that don't affect the interface
_age = 0 # Number of consecutive versions of the interface the current version supports
import volatility.framework.exceptions as exceptions
@property
def version():
"""Provides the so version number of the library"""
return _current - _age, _age, _revision
def require_version(*args):
"""Checks the required version of a plugin"""
if len(args):
if args[0] != version[0]:
raise exceptions.VolatilityException("Framework version " + str(version[0]) + " is incompatible with required version " + str(args[0]))
if args[0] != version()[0]:
raise Exception("Framework version " + str(version()[0]) + " is incompatible with required version " + str(args[0]))
if len(args) > 1:
if args[1] > version[1]:
raise exceptions.VolatilityException("Framework version " + ".".join([str(x) for x in version[0:1]]) + " is an older revision than the required version " + ".".join([str(x) for x in args[0:2]]))
if args[1] > version()[1]:
raise Exception("Framework version " + ".".join([str(x) for x in version()[0:1]]) + " is an older revision than the required version " + ".".join([str(x) for x in args[0:2]]))
+20 -13
View File
@@ -6,6 +6,7 @@ Created on 17 Feb 2013
import struct
import collections
import volatility.framework.templates as templates
class ObjectInterface(object):
""" A base object required to be the ancestor of every object used in volatility """
@@ -30,23 +31,25 @@ class PrimitiveObject(ObjectInterface):
class Integer(PrimitiveObject, int):
"""Primitive Object that handles standard numeric types"""
def __new__(cls, context, layer_name, offset, symbol_name, size, struct_format, **kwargs):
struct_format = context.get_primitive_struct_type("int", symbol_name)
return cls._struct_value(struct_format, context, layer_name, offset, symbol_name)
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_size = struct.calcsize(struct_format)
return cls._struct_value(struct_format, context, layer_name, offset, symbol_name, size = struct_size)
class Float(PrimitiveObject, float):
"""Primitive Object that handles double or floating point numbers"""
def __new__(cls, context, layer_name, offset, symbol_name, **kwargs):
struct_format = context.get_primitive_struct_type("float", symbol_name)
return cls._struct_value(struct_format, context, layer_name, offset, symbol_name)
def __new__(cls, context, layer_name, offset, symbol_name, size, **kwargs):
struct_format, struct_size = 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)
class Bytes(PrimitiveObject, bytes):
"""Primitive Object that handles specific series of bytes
"""
def __new__(cls, context, layer_name, offset, symbol_name, **kwargs):
return cls._struct_value(str(length) + "s", context, layer_name, offset, symbol_name)
def __new__(cls, context, layer_name, offset, symbol_name, size, **kwargs):
return cls._struct_value(str(size) + "s", context, layer_name, offset, symbol_name, size)
class String(PrimitiveObject, str):
"""Primitive Object that handles string values
@@ -54,21 +57,25 @@ class String(PrimitiveObject, str):
length: specifies the maximum possible length that the string could hold in memory
"""
def __new__(cls, context, layer_name, offset, symbol_name, length = 1):
return cls._struct_value(str(length) + "s", context, layer_name, offset, symbol_name)
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):
"""Object which can contain members that are other objects"""
def __init__(self, context, layer_name, offset, symbol_name, size = None, members = None):
super(Struct).__init__(self, context, layer_name, offset, symbol_name, size)
# Members should be an iterable mapping of symbol names to callable Object Templates
# An object template is a callable that when called with a context, offset, layer_name and symbol_name
if not isinstance(members, collections.Iterable):
raise
if struct_size is None:
raise TypeError("Struct members parameter must be iterable not " + type(members))
if not all([isinstance(members, templates.MemberTemplate)]):
raise TypeError("Struct members must be derived from MemberTemplate objects")
if size is None:
# Attempt to determine the maximum size by asking
for i in members:
pass
self._members = members
def __getattr__(self, attr):
+66 -14
View File
@@ -5,8 +5,10 @@ Created on 7 Feb 2013
'''
import volatility.framework.exceptions as exceptions
from volatility.framework import templates
from volatility.framework import obj
class SymbolSpace(dict):
class SymbolSpace(list):
"""Handles a collection of SymbolLists"""
def resolve(self, symbol):
@@ -14,11 +16,12 @@ class SymbolSpace(dict):
if len(symarr) == 2:
listname = symarr[0]
symname = symarr[1]
if listname in [value.name for value in self]:
if symname in self[listname]:
return self[listname].resolve(symname)
else:
raise exceptions.SymbolNotFoundException("Symbol " + symname + " could not be found in the " + listname + " list")
for symlist in self:
if symlist.name == listname:
if symname in symlist:
return symlist[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:
@@ -33,20 +36,69 @@ class SymbolSpace(dict):
# Consider maintaining a list of symbollist names
# A list of potentially conflicting symbols (for when no listname is provided)
class SymbolList(object):
class SymbolListInterface(object):
"""Handles a list of symbols"""
def __init__(self, name):
def __init__(self, name, *args, **kwargs):
super(SymbolListInterface).__init__(*args, **kwargs)
if not isinstance(name, str) or not name:
raise exceptions.SymbolSpaceError("Symbol lists cannot be nameless")
self.name = name
def resolve(self, symbolname):
def __len__(self):
"""Returns the number of items in the symbol list"""
def __getitem__(self, key):
"""Resolves a symbol name into an object template"""
def __contains__(self, symbol):
return symbol in self.get_symbols()
def __setitem__(self, key, value):
# TODO: Determine whether this is an appropriate design decision
"""Overrides a symbol's class from a Struct to the value"""
def get_symbols(self):
"""Returns a list of all available symbols"""
def __delitem__(self, key):
# TODO: Determine whether this is an appropriate design decision
"""Removes the class override back to a Struct"""
def __iter__(self):
"""Returns an iterator of the symbol names"""
def __contains__(self, symbol):
"""Determines whether a symbol exists in the list or not"""
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 __getitem__(self, key):
"""Resolves a symbol name into an object template"""
size, curdict = self._vtypedict[key]
for item in curdict:
relative_offset, vtypedict = curdict[item]
self._vtypedict_to_template(vtypedict)
templates.MemberTemplate(self._classdict.get(key, obj.Struct), symbol_name = item, size = None, relative_offset = relative_offset)
members = [self._vtypedict_to_template(curdict[item]) for item in curdict]
return templates.ObjectTemplate(self._classdict.get(key, obj.Struct), symbol_name = key, size = size, members = members)
def _vtypedict_to_template(self, dictionary):
"""Converts a vtypedict into an object template"""
print(repr(dictionary))
def __setitem__(self, key, value):
"""Overrides a symbol's class from a Struct to the value"""
self._classdict[key] = value
def __iter__(self):
"""Returns an iterator of the symbol names"""
return set(self._classdict.keys() + self._vtypedict.keys())
def __contains__(self, value):
"""Determines whether a symbol exists in the list or not"""
return (value in self._vtypedict or value in self._classdict)
def resolve(self, symbolname):
if symbolname not in self._vtypedict:
raise exceptions.SymbolNotFoundException
+17 -9
View File
@@ -4,8 +4,6 @@ Created on 1 Mar 2013
@author: mike
'''
import volatility.framework.obj as obj
class ObjectTemplate(object):
"""Factory class that produces objects that adhere to the Object interface on demand
@@ -15,21 +13,29 @@ class ObjectTemplate(object):
* Members, etc
etc.
"""
def __init__(self, objclass, **kwargs):
def __init__(self, objclass, symbol_name = None, size = None, **kwargs):
self._objclass = objclass
self._size = None
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
@property
def size(self):
return self._size
def __call__(self, context, symbol_name, offset, layer_name):
@property
def symbol_name(self):
"""Returns the name of the symbol if one was provided"""
return self._symbol_name
def __call__(self, context, offset, layer_name, parent = None):
"""Constructs the object
Returns: an object adhereing to the Object interface
"""
return self._objclass(context, layer_name, offset, symbol_name, self.size, **self._kwargs)
return self._objclass(context, layer_name, offset, self.symbol_name, self.size, parent, **self._kwargs)
class MemberTemplate(ObjectTemplate):
"""Factory class that produces members of Structs
@@ -37,11 +43,13 @@ class MemberTemplate(ObjectTemplate):
This is just like a normal ObjectTemplate, but contains the relative offset
fron the parent object.
"""
def __init__(self, objclass, relative_offset, **kwargs):
self._objclass = objclass
def __init__(self, objclass, symbol_name = None, size = None, relative_offset = None, *args, **kwargs):
if not isinstance(relative_offset, int):
raise TypeError("MemberTemplate relative_offset must be numeric, not " + str(type(relative_offset)))
self._reloffset = relative_offset
self._kwargs = kwargs
ObjectTemplate.__init__(self, objclass, symbol_name, size, *args, **kwargs)
@property
def relative_offset(self):
return self._reloffset