Files
volatility3/volatility/framework/__init__.py
T
Mike Auty 8625343792 Add the ability to create 'hidden' classes.
These will not be returned as part of the subclasses of
their descendents when listed using the classes_subclasses function.
They can be inherited from and their descendents will be listed unless
they also specify the hidden property and mark it as True
(ideally, using the class decorator hide_from_subclasses).
2017-07-01 22:19:50 +01:00

108 lines
4.2 KiB
Python

"""Volatility 3 framework"""
import inspect
import logging
import os
import sys
# ##
#
# Libtool version scheme
#
# Current - The number of the current interface exported by the library
# Revision - The implementation number of the most recent interface exported by this library
# Age - The number of previous additional interfaces supported by this library
#
# 1. If the source changes, increment the revision
# 2. If the interface has changed, increment current, set revision to 0
# 3. If only additions to the interface have been made, increment age
# 4. If changes or removals of the interface have been made, set age to 0
# We use the libtool library versioning
CURRENT = 0 # 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
def interface_version():
"""Provides the so version number of the library"""
return CURRENT - AGE, AGE, REVISION
vollog = logging.getLogger(__name__)
def require_interface_version(*args):
"""Checks the required version of a plugin"""
if len(args):
if args[0] != interface_version()[0]:
raise RuntimeError(
"Framework interface version {} is incompatible with required version {}".format(interface_version()[0],
args[0]))
if len(args) > 1:
if args[1] > interface_version()[1]:
raise RuntimeError(
"Framework interface version {} is an older revision than the required version {}".format(
".".join([str(x) for x in interface_version()[0:1]]),
".".join([str(x) for x in args[0:2]])))
class noninheritable(object):
def __init__(self, f, cls):
self.f = f
self.cls = cls
def __get__(self, obj, type = None):
if type == self.cls:
if hasattr(self.f, '__get__'):
return self.f.__get__(obj, type)
return self.f
raise AttributeError
def hide_from_subclasses(cls):
cls.hidden = noninheritable(True, cls)
return cls
def class_subclasses(cls):
"""Returns all the (recursive) subclasses of a given class"""
if not inspect.isclass(cls):
raise TypeError("class_subclasses parameter not a valid class: {}".format(cls))
for clazz in cls.__subclasses__():
if not hasattr(clazz, 'hidden') or not clazz.hidden:
yield clazz
for return_value in class_subclasses(clazz):
yield return_value
def import_files(base_module):
"""Imports all plugins present under plugins path"""
if not isinstance(base_module.__path__, list):
raise TypeError("[base_module].__path__ must be a list of paths")
for path in base_module.__path__:
for root, _, files in os.walk(path, followlinks = True):
# TODO: Figure out how to import pycache files
if root.endswith("__pycache__"):
continue
for f in files:
if (f.endswith(".py") or f.endswith(".pyc") or f.endswith(".pyo")) and not f.startswith("__"):
modpath = os.path.join(root[len(path) + len(os.path.sep):], f[:f.rfind(".")])
module = modpath.replace(os.path.sep, ".")
if module not in sys.modules:
try:
vollog.debug("Importing module: {}.{}".format(base_module.__name__, module))
__import__(base_module.__name__ + "." + module)
except ImportError as e:
vollog.debug(str(e))
vollog.warning("Failed to import module {} based on file: {}".format(module, modpath))
raise
else:
vollog.info("Skipping existing module: {}".format(module))
# Check the python version to ensure it's suitable
required_python_version = (3, 4)
if sys.version_info.major != required_python_version[0] or sys.version_info.minor < required_python_version[1]:
raise RuntimeError("Volatility framework requires python version {}.{} or greater".format(*required_python_version))