volatilityfoundation / volatility3

Volatility 3.0 development
http://volatilityfoundation.org/
Other
2.61k stars 447 forks source link

plugin windows.pslist matches multiple plugins #872

Closed ShellCode33 closed 1 year ago

ShellCode33 commented 1 year ago

Hey, when I create a plugin under volatility3/plugins/windows/ which has the following imports and requirements :

from typing import Callable, Iterable, List
from volatility3.framework.configuration import requirements
from volatility3.framework import interfaces, renderers
from volatility3.framework.plugins.windows.pslist import PsList
from volatility3.framework.plugins.windows.psscan import PsScan
from volatility3.framework.renderers import format_hints

class MyPlugin(interfaces.plugins.PluginInterface):

    _required_framework_version = (2, 0, 0)
    _version = (0, 0, 1)

    @classmethod
    def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
        return [
            requirements.ModuleRequirement(name = 'kernel',
                                           architectures = ["Intel32", "Intel64"]),
            requirements.ListRequirement(name = 'pid',
                                         description = 'Filter on specific process IDs',
                                         element_type = int,
                                         optional = True),
            requirements.PluginRequirement(name = 'pslist',
                                           plugin = PsList,
                                           version = (2, 0, 0)),
            requirements.PluginRequirement(name = 'psscan',
                                           plugin = PsScan,
                                           version = (2, 0, 0)),
        ]

If I try to use one of the original plugin my own plugin depend upon (windows.pslist in this case), I get the following error :

$ python vol.py -f windows10.dmp windows.pslist
Volatility 3 Framework 2.4.1
usage: volatility [-h] [-c CONFIG] [--parallelism [{processes,threads,off}]] [-e EXTEND] [-p PLUGIN_DIRS] [-s SYMBOL_DIRS] [-v] [-l LOG] [-o OUTPUT_DIR] [-q] [-r RENDERER] [-f FILE]
                  [--write-config] [--save-config SAVE_CONFIG] [--clear-cache] [--cache-path CACHE_PATH] [--offline] [--single-location SINGLE_LOCATION] [--stackers [STACKERS ...]]
                  [--single-swap-locations [SINGLE_SWAP_LOCATIONS ...]]
                  plugin ...
volatility: error: argument plugin: plugin windows.pslist matches multiple plugins (volatility3.framework.plugins.windows.pslist.PsList, windows.pslist.PsList)

My guess is that Volatility tries to load plugins recursively, pslist being imported in the namespace of my plugin, Volatility tries to load it twice (from my plugin, and from volatility3.framework.plugins.windows). I don't know how plugins discovery works in Volatility, but I guess it should not try to load plugins recursively ?

I even tried to put my plugin at another location and pass -p to Volatility, same result.

I've installed Volatility like so :

$ git clone https://github.com/volatilityfoundation/volatility3
$ cd volatility3
$ python3 -m venv venv
$ . venv/bin/activate
$ pip install -r requirements.txt
ShellCode33 commented 1 year ago

I found the following comment in volatility3/__init__.py :

# We point the volatility3.plugins __path__ variable at BOTH
#   volatility3/plugins
#   volatility3/framework/plugins
# in that order.
#
# This will allow our users to override any component of any plugin without monkey patching,
# but it also allows us to clear out the plugins directory to get back to proper functionality.
# This offered the greatest flexibility for users whilst allowing us to keep the core separate and clean.
#
# This means that all plugins should be imported as volatility3.plugins (otherwise they'll be imported twice,
# once as volatility3.plugins.NAME and once as volatility3.framework.plugins.NAME).  We therefore throw an error
# if anyone tries to import anything under the volatility3.framework.plugins.* namespace
#
# The remediation is to only ever import form volatility3.plugins instead.

Maybe it should be added to the readthedocs ?

Indeed, when I use from volatility3.plugins instead of from volatility3.framework.plugins the error disappears. However, pyright is not happy at all with it, and therefore I'm unable to jump to definitions because of that. I think we should keep that in mind and find a way to load plugins in a way that allows linters to understand what's going on.

image

ikelos commented 1 year ago

That's quite strange, we actually have code explicitly to warn you if you try importing from volatility.framework.plugins.

It's very difficult to make a system that's flexible enough for users to allow overload/overriding the use of core plugins without overwriting the core plugins themselves. We felt it was a suitable trade off to allow this particularly with the warning which should have fired when the offending import was made.

I'm happy to add the warning to the documentation, the question is where? We kind of glance over the issue at https://volatility3.readthedocs.io/en/stable/using-as-a-library.html?highlight=__path__#determine-what-plugins-are-available and it does get added to https://volatility3.readthedocs.io/en/stable/volatility3.framework.plugins.html?highlight=volatility3.framework.plugins#module-volatility3.framework.plugins, but it's really difficult to inform developers "you think you know what you're doing, but we need you to do things this way". People usually don't read it, which is why we included the custom code to hook the importer and make sure that volatility3.framework.plugins was never imported...

github-actions[bot] commented 1 year ago

This issue is stale because it has been open for 200 days with no activity.

github-actions[bot] commented 1 year ago

This issue was closed because it has been inactive for 60 days since being marked as stale.