mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-08-31 12:19:42 +02:00
Volshell: Update to use KernelRequirement
This commit is contained in:
+34
-32
@@ -24,13 +24,14 @@ operating system mode for volshell, and the current layer available for use.
|
||||
|
||||
::
|
||||
|
||||
Volshell (Volatility 3 Framework) 1.0.1
|
||||
Volshell (Volatility 3 Framework) 2.0.2
|
||||
Readline imported successfully PDB scanning finished
|
||||
|
||||
Call help() to see available functions
|
||||
|
||||
Volshell mode: Generic
|
||||
Current Layer: primary
|
||||
Volshell mode : Generic
|
||||
Current Layer : primary
|
||||
Current Symbol Table: None
|
||||
|
||||
(primary) >>>
|
||||
|
||||
@@ -55,9 +56,9 @@ python environment, we can do the following:
|
||||
|
||||
::
|
||||
|
||||
(primary) >>> proc = ps()[0]
|
||||
(primary) >>> proc
|
||||
<EPROCESS nt_symbols1!_EPROCESS: primary @ 0x8c0bcac87040 #2624>
|
||||
(layer_name) >>> proc = ps()[0]
|
||||
(layer_name) >>> proc
|
||||
<EPROCESS symbol_table_name1!_EPROCESS: layer_name @ 0xe08ff2459040 #1968>
|
||||
|
||||
When printing a volatility structure, various information is output, in this case the `type_name`, the `layer` and
|
||||
`offset` that it's been constructed on, and the size of the structure.
|
||||
@@ -70,31 +71,31 @@ automagic).
|
||||
|
||||
::
|
||||
|
||||
(primary) >>> dt('_EPROCESS')
|
||||
nt_symbols1!_EPROCESS (2624 bytes)
|
||||
0x0 : Pcb nt_symbols1!_KPROCESS
|
||||
0x438 : ProcessLock nt_symbols1!_EX_PUSH_LOCK
|
||||
0x440 : UniqueProcessId nt_symbols1!pointer
|
||||
0x448 : ActiveProcessLinks nt_symbols1!_LIST_ENTRY
|
||||
(layer_name) >>> dt('_EPROCESS')
|
||||
symbol_table_name1!_EPROCESS (1968 bytes)
|
||||
0x0 : Pcb symbol_table_name1!_KPROCESS
|
||||
0x2d8 : ProcessLock symbol_table_name1!_EX_PUSH_LOCK
|
||||
0x2e0 : RundownProtect symbol_table_name1!_EX_RUNDOWN_REF
|
||||
0x2e8 : UniqueProcessId symbol_table_name1!pointer
|
||||
...
|
||||
|
||||
It can also be provided with an object and will interpret the data for each in the process:
|
||||
|
||||
::
|
||||
|
||||
(primary) >>> dt(proc)
|
||||
nt_symbols1!_EPROCESS (2624 bytes)
|
||||
0x0 : Pcb nt_symbols1!_KPROCESS 0x8c0bccf8d040
|
||||
0x438 : ProcessLock nt_symbols1!_EX_PUSH_LOCK 0x8c0bccf8d478
|
||||
0x440 : UniqueProcessId nt_symbols1!pointer 356
|
||||
0x448 : ActiveProcessLinks nt_symbols1!_LIST_ENTRY 0x8c0bccf8d488
|
||||
(layer_name) >>> dt(proc)
|
||||
symbol_table_name1!_EPROCESS (1968 bytes)
|
||||
0x0 : Pcb symbol_table_name1!_KPROCESS 0xe08ff2459040
|
||||
0x2d8 : ProcessLock symbol_table_name1!_EX_PUSH_LOCK 0xe08ff2459318
|
||||
0x2e0 : RundownProtect symbol_table_name1!_EX_RUNDOWN_REF 0xe08ff2459320
|
||||
0x2e8 : UniqueProcessId symbol_table_name1!pointer 4
|
||||
...
|
||||
|
||||
These values can be accessed directory as attributes
|
||||
|
||||
::
|
||||
|
||||
(primary) >>> proc.UniqueProcessId
|
||||
(layer_name) >>> proc.UniqueProcessId
|
||||
356
|
||||
|
||||
Pointer structures contain the value they point to, but attributes accessed are forwarded to the object they point to.
|
||||
@@ -102,7 +103,7 @@ This means that pointers do not need to be explicitly dereferenced to access und
|
||||
|
||||
::
|
||||
|
||||
(primary) >>> proc.Pcb.DirectoryTableBase
|
||||
(layer_name) >>> proc.Pcb.DirectoryTableBase
|
||||
4355817472
|
||||
|
||||
Running plugins
|
||||
@@ -114,26 +115,26 @@ were required:
|
||||
|
||||
::
|
||||
|
||||
(primary) >>> from volatility3.plugins.windows import pslist
|
||||
(primary) >>> display_plugin_output(pslist.PsList)
|
||||
Unable to validate the plugin requirements: ['plugins.Volshell.9QZLXJKFWESI0BAP3M1U7Y5VCT468GRN.PsList.primary', 'plugins.Volshell.9QZLXJKFWESI0BAP3M1U7Y5VCT468GRN.PsList.nt_symbols']
|
||||
(layer_name) >>> from volatility3.plugins.windows import pslist
|
||||
(layer_name) >>> display_plugin_output(pslist.PsList)
|
||||
Unable to validate the plugin requirements: ['plugins.Volshell.VH3FSA1JBG0QP9E62Z8OT5UCIMLNYKW4.PsList.kernel']
|
||||
|
||||
We can see that it's made a temporary configuration path for the plugin, and that neither `primary` nor `nt_symbols`
|
||||
was fulfilled.
|
||||
We can see that it's made a temporary configuration path for the plugin, and that the `kernel` requirement
|
||||
was not fulfilled.
|
||||
|
||||
We can see all the options that the plugin can accept by access the `get_requirements()` method of the plugin.
|
||||
This is a classmethod, so can be called on an uninstantiated copy of the plugin.
|
||||
|
||||
::
|
||||
|
||||
(primary) >>> pslist.PsList.get_requirements()
|
||||
[<TranslationLayerRequirement: primary>, <SymbolTableRequirement: nt_symbols>, <BooleanRequirement: physical>, <ListRequirement: pid>, <BooleanRequirement: dump>]
|
||||
(layer_name) >>> pslist.PsList.get_requirements()
|
||||
[<ModuleRequirement: kernel>, <BooleanRequirement: physical>, <ListRequirement: pid>, <BooleanRequirement: dump>]
|
||||
|
||||
We can provide arguments via the `dpo` method call:
|
||||
|
||||
::
|
||||
|
||||
(primary) >>> display_plugin_output(pslist.PsList, primary = self.current_layer, nt_symbols = self.config['nt_symbols'])
|
||||
(layer_name) >>> display_plugin_output(pslist.PsList, kernel = self.config['kernel'])
|
||||
|
||||
PID PPID ImageFileName Offset(V) Threads Handles SessionId Wow64 CreateTime ExitTime File output
|
||||
|
||||
@@ -142,8 +143,9 @@ We can provide arguments via the `dpo` method call:
|
||||
356 4 smss.exe 0x8c0bccf8d040 3 - N/A False 2021-03-13 17:25:33.000000 N/A Disabled
|
||||
...
|
||||
|
||||
Here's we've provided the current layer as the TranslationLayerRequirement, and used the symbol tables requirement
|
||||
requested by the volshell plugin itself. A different table could be loaded and provided instead. The context used
|
||||
Here's we've provided the kernel name that was requested by the volshell plugin itself (the generic volshell does not
|
||||
load a kernel module, and instead only has a TranslationLayerRequirement).
|
||||
A different module could be created and provided instead. The context used
|
||||
by the `dpo` method is always `context`.
|
||||
|
||||
Instead of print the results directly to screen, they can be gathered into a TreeGrid objects for direct access by
|
||||
@@ -151,8 +153,8 @@ using the `generate_treegrid` or `gt` command.
|
||||
|
||||
::
|
||||
|
||||
(primary) >>> treegrid = gt(pslist.PsList, primary = self.current_layer, nt_symbols = self.config['nt_symbols'])
|
||||
(primary) >>> treegrid.populate()
|
||||
(layer_name) >>> treegrid = gt(pslist.PsList, kernel = self.config['kernel'])
|
||||
(layer_name) >>> treegrid.populate()
|
||||
|
||||
Treegrids must be populated before the data in them can be accessed. This is where the plugin actually runs and
|
||||
produces data.
|
||||
|
||||
@@ -19,14 +19,14 @@ import os
|
||||
import sys
|
||||
import tempfile
|
||||
import traceback
|
||||
from typing import Dict, Type, Union, Any
|
||||
from typing import Any, Dict, Type, Union
|
||||
from urllib import parse, request
|
||||
|
||||
import volatility3.plugins
|
||||
import volatility3.symbols
|
||||
from volatility3 import framework
|
||||
from volatility3.cli import text_renderer, volargparse
|
||||
from volatility3.framework import automagic, constants, contexts, exceptions, interfaces, plugins, configuration
|
||||
from volatility3.framework import automagic, configuration, constants, contexts, exceptions, interfaces, plugins
|
||||
from volatility3.framework.automagic import stacker
|
||||
from volatility3.framework.configuration import requirements
|
||||
|
||||
|
||||
@@ -7,12 +7,11 @@ import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import glob
|
||||
|
||||
import volatility3.plugins
|
||||
import volatility3.symbols
|
||||
from volatility3 import cli, framework
|
||||
from volatility3.cli.volshell import generic, windows, linux, mac
|
||||
from volatility3.cli.volshell import generic, linux, mac, windows
|
||||
from volatility3.framework import automagic, constants, contexts, exceptions, interfaces, plugins
|
||||
|
||||
# Make sure we log everything
|
||||
|
||||
@@ -8,11 +8,11 @@ import random
|
||||
import string
|
||||
import struct
|
||||
import sys
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union, Type, Iterable
|
||||
from urllib import request, parse
|
||||
from typing import Any, Dict, Iterable, List, Optional, Tuple, Type, Union
|
||||
from urllib import parse, request
|
||||
|
||||
from volatility3.cli import text_renderer, volshell
|
||||
from volatility3.framework import renderers, interfaces, objects, plugins, exceptions
|
||||
from volatility3.framework import exceptions, interfaces, objects, plugins, renderers
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.layers import intel, physical, resources
|
||||
|
||||
@@ -32,6 +32,7 @@ class Volshell(interfaces.plugins.PluginInterface):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.__current_layer: Optional[str] = None
|
||||
self.__console = None
|
||||
self.__kernel = None
|
||||
|
||||
def random_string(self, length: int = 32) -> str:
|
||||
return ''.join(random.sample(string.ascii_uppercase + string.digits, length))
|
||||
@@ -57,8 +58,6 @@ class Volshell(interfaces.plugins.PluginInterface):
|
||||
Return a TreeGrid but this is always empty since the point of this plugin is to run interactively
|
||||
"""
|
||||
|
||||
self.__current_layer = self.config['primary']
|
||||
|
||||
# Try to enable tab completion
|
||||
try:
|
||||
import readline
|
||||
@@ -79,9 +78,10 @@ class Volshell(interfaces.plugins.PluginInterface):
|
||||
banner = f"""
|
||||
Call help() to see available functions
|
||||
|
||||
Volshell mode: {mode}
|
||||
Current Layer: {self.current_layer}
|
||||
"""
|
||||
Volshell mode : {mode}
|
||||
Current Layer : {self.current_layer}
|
||||
Current Symbol Table: {self.current_symbol_table}
|
||||
"""
|
||||
|
||||
sys.ps1 = f"({self.current_layer}) >>> "
|
||||
self.__console = code.InteractiveConsole(locals = self._construct_locals_dict())
|
||||
@@ -174,12 +174,23 @@ class Volshell(interfaces.plugins.PluginInterface):
|
||||
|
||||
@property
|
||||
def current_layer(self):
|
||||
if self.__current_layer is None:
|
||||
self.__current_layer = self.config['primary']
|
||||
return self.__current_layer
|
||||
|
||||
@property
|
||||
def current_symbol_table(self):
|
||||
return None
|
||||
|
||||
@property
|
||||
def kernel(self):
|
||||
"""No default kernel for generic volshell"""
|
||||
return None
|
||||
|
||||
def change_layer(self, layer_name = None):
|
||||
"""Changes the current default layer"""
|
||||
if not layer_name:
|
||||
layer_name = self.config['primary']
|
||||
layer_name = self.current_layer
|
||||
self.__current_layer = layer_name
|
||||
sys.ps1 = f"({self.current_layer}) >>> "
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
from typing import Any, List, Tuple, Union
|
||||
|
||||
from volatility3.cli.volshell import generic
|
||||
from volatility3.framework import interfaces, constants
|
||||
from volatility3.framework import constants, interfaces
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.plugins.linux import pslist
|
||||
|
||||
@@ -15,8 +15,8 @@ class Volshell(generic.Volshell):
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return (super().get_requirements() + [
|
||||
requirements.SymbolTableRequirement(name = "vmlinux", description = "Linux kernel symbols"),
|
||||
return ([
|
||||
requirements.ModuleRequirement(name = "kernel", description = "Linux kernel module"),
|
||||
requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (2, 0, 0)),
|
||||
requirements.IntRequirement(name = 'pid', description = "Process ID", optional = True)
|
||||
])
|
||||
@@ -37,14 +37,14 @@ class Volshell(generic.Volshell):
|
||||
def list_tasks(self):
|
||||
"""Returns a list of task objects from the primary layer"""
|
||||
# We always use the main kernel memory and associated symbols
|
||||
return list(pslist.PsList.list_tasks(self.context, self.config['primary'], self.config['vmlinux']))
|
||||
return list(pslist.PsList.list_tasks(self.context, self.current_layer, self.current_symbol_table))
|
||||
|
||||
def construct_locals(self) -> List[Tuple[List[str], Any]]:
|
||||
result = super().construct_locals()
|
||||
result += [
|
||||
(['ct', 'change_task', 'cp'], self.change_task),
|
||||
(['lt', 'list_tasks', 'ps'], self.list_tasks),
|
||||
(['symbols'], self.context.symbol_space[self.config['vmlinux']]),
|
||||
(['symbols'], self.context.symbol_space[self.current_symbol_table]),
|
||||
]
|
||||
if self.config.get('pid', None) is not None:
|
||||
self.change_task(self.config['pid'])
|
||||
@@ -64,3 +64,19 @@ class Volshell(generic.Volshell):
|
||||
if symbol_table is None:
|
||||
symbol_table = self.config['vmlinux']
|
||||
return super().display_symbols(symbol_table)
|
||||
|
||||
@property
|
||||
def kernel(self):
|
||||
if self.__kernel is None:
|
||||
self.__kernel = self.context.modules[self.config['kernel']]
|
||||
return self.__kernel
|
||||
|
||||
@property
|
||||
def current_symbol_table(self):
|
||||
return self.kernel.symbol_table_name
|
||||
|
||||
@property
|
||||
def current_layer(self):
|
||||
if self.__current_layer is None:
|
||||
self.__current_layer = self.kernel.layer_name
|
||||
return self.__current_layer
|
||||
|
||||
@@ -15,9 +15,9 @@ class Volshell(generic.Volshell):
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return (super().get_requirements() + [
|
||||
requirements.SymbolTableRequirement(name = "darwin", description = "Darwin kernel symbols"),
|
||||
requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (1, 0, 0)),
|
||||
return ([
|
||||
requirements.ModuleRequirement(name = "kernel", description = "Darwin kernel module"),
|
||||
requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (3, 0, 0)),
|
||||
requirements.IntRequirement(name = 'pid', description = "Process ID", optional = True)
|
||||
])
|
||||
|
||||
@@ -37,14 +37,14 @@ class Volshell(generic.Volshell):
|
||||
def list_tasks(self):
|
||||
"""Returns a list of task objects from the primary layer"""
|
||||
# We always use the main kernel memory and associated symbols
|
||||
return list(pslist.PsList.list_tasks(self.context, self.config['primary'], self.config['darwin']))
|
||||
return list(pslist.PsList.list_tasks(self.context, self.current_layer, self.current_symbol_table))
|
||||
|
||||
def construct_locals(self) -> List[Tuple[List[str], Any]]:
|
||||
result = super().construct_locals()
|
||||
result += [
|
||||
(['ct', 'change_task', 'cp'], self.change_task),
|
||||
(['lt', 'list_tasks', 'ps'], self.list_tasks),
|
||||
(['symbols'], self.context.symbol_space[self.config['darwin']]),
|
||||
(['symbols'], self.context.symbol_space[self.current_symbol_table]),
|
||||
]
|
||||
if self.config.get('pid', None) is not None:
|
||||
self.change_task(self.config['pid'])
|
||||
@@ -62,5 +62,21 @@ class Volshell(generic.Volshell):
|
||||
def display_symbols(self, symbol_table: str = None):
|
||||
"""Prints an alphabetical list of symbols for a symbol table"""
|
||||
if symbol_table is None:
|
||||
symbol_table = self.config['darwin']
|
||||
symbol_table = self.current_symbol_table
|
||||
return super().display_symbols(symbol_table)
|
||||
|
||||
@property
|
||||
def kernel(self):
|
||||
if self.__kernel is None:
|
||||
self.__kernel = self.context.modules[self.config['kernel']]
|
||||
return self.__kernel
|
||||
|
||||
@property
|
||||
def current_symbol_table(self):
|
||||
return self.kernel.symbol_table_name
|
||||
|
||||
@property
|
||||
def current_layer(self):
|
||||
if self.__current_layer is None:
|
||||
self.__current_layer = self.kernel.layer_name
|
||||
return self.__current_layer
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
from typing import Any, List, Tuple, Union
|
||||
|
||||
from volatility3.cli.volshell import generic
|
||||
from volatility3.framework import interfaces, constants
|
||||
from volatility3.framework import constants, interfaces
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.plugins.windows import pslist
|
||||
|
||||
@@ -15,8 +15,8 @@ class Volshell(generic.Volshell):
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return (super().get_requirements() + [
|
||||
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
|
||||
return ([
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel'),
|
||||
requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (2, 0, 0)),
|
||||
requirements.IntRequirement(name = 'pid', description = "Process ID", optional = True)
|
||||
])
|
||||
@@ -34,14 +34,14 @@ class Volshell(generic.Volshell):
|
||||
def list_processes(self):
|
||||
"""Returns a list of EPROCESS objects from the primary layer"""
|
||||
# We always use the main kernel memory and associated symbols
|
||||
return list(pslist.PsList.list_processes(self.context, self.config['primary'], self.config['nt_symbols']))
|
||||
return list(pslist.PsList.list_processes(self.context, self.current_layer, self.current_symbol_table))
|
||||
|
||||
def construct_locals(self) -> List[Tuple[List[str], Any]]:
|
||||
result = super().construct_locals()
|
||||
result += [
|
||||
(['cp', 'change_process'], self.change_process),
|
||||
(['lp', 'list_processes', 'ps'], self.list_processes),
|
||||
(['symbols'], self.context.symbol_space[self.config['nt_symbols']]),
|
||||
(['symbols'], self.context.symbol_space[self.current_symbol_table]),
|
||||
]
|
||||
if self.config.get('pid', None) is not None:
|
||||
self.change_process(self.config['pid'])
|
||||
@@ -53,11 +53,27 @@ class Volshell(generic.Volshell):
|
||||
"""Display Type describes the members of a particular object in alphabetical order"""
|
||||
if isinstance(object, str):
|
||||
if constants.BANG not in object:
|
||||
object = self.config['nt_symbols'] + constants.BANG + object
|
||||
object = self.current_symbol_table + constants.BANG + object
|
||||
return super().display_type(object, offset)
|
||||
|
||||
def display_symbols(self, symbol_table: str = None):
|
||||
"""Prints an alphabetical list of symbols for a symbol table"""
|
||||
if symbol_table is None:
|
||||
symbol_table = self.config['nt_symbols']
|
||||
symbol_table = self.current_symbol_table
|
||||
return super().display_symbols(symbol_table)
|
||||
|
||||
@property
|
||||
def kernel(self):
|
||||
if self.__kernel is None:
|
||||
self.__kernel = self.context.modules[self.config['kernel']]
|
||||
return self.__kernel
|
||||
|
||||
@property
|
||||
def current_symbol_table(self):
|
||||
return self.kernel.symbol_table_name
|
||||
|
||||
@property
|
||||
def current_layer(self):
|
||||
if self.__current_layer is None:
|
||||
self.__current_layer = self.kernel.layer_name
|
||||
return self.__current_layer
|
||||
|
||||
Reference in New Issue
Block a user