mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-23 18:14:51 +02:00
Merge branch 'volatilityfoundation:develop' into library
This commit is contained in:
@@ -27,7 +27,7 @@ To create a symbol table please refer to :ref:`symbol-tables:Mac or Linux symbol
|
||||
Listing plugins
|
||||
---------------
|
||||
|
||||
The following is a sample of the linux plugins available for volatility3, it is not complete and more more plugins may
|
||||
The following is a sample of the linux plugins available for volatility3, it is not complete and more plugins may
|
||||
be added. For a complete reference, please see the volatility 3 :doc:`list of plugins <volatility3.plugins>`.
|
||||
For plugin requests, please create an issue with a description of the requested plugin.
|
||||
|
||||
@@ -40,7 +40,7 @@ For plugin requests, please create an issue with a description of the requested
|
||||
linux.check_creds.Check_creds
|
||||
linux.check_idt.Check_idt
|
||||
|
||||
.. note:: Here the the command is piped to grep and head in-order to provide the start of the list of linux plugins.
|
||||
.. note:: Here the the command is piped to grep and head to provide the start of the list of linux plugins.
|
||||
|
||||
|
||||
Using plugins
|
||||
@@ -80,9 +80,9 @@ Thanks go to `stuxnet <https://github.com/stuxnet999/>`_ for providing this memo
|
||||
|
||||
|
||||
The above command helps us to find the memory dump's kernel version and the distribution version. Now using the above banner we can search for the needed ISF file from the ISF server.
|
||||
If ISF file cannot be found then, follow the instructions on :ref:`getting-started-linux-tutorial:Procedure to create symbol tables for linux`. After that, place the ISF file under the ``volatility3/symbols/linux`` directory.
|
||||
If an ISF file cannot be found then, follow the instructions on :ref:`getting-started-linux-tutorial:Procedure to create symbol tables for linux`. After that, place the ISF file under the ``volatility3/symbols/linux`` directory.
|
||||
|
||||
.. tip:: Use the banner text which is most repeated to search from ISF Server.
|
||||
.. tip:: Use the banner text which is most repeated to search on the ISF Server.
|
||||
|
||||
linux.pslist
|
||||
~~~~~~~~~~~~
|
||||
@@ -157,7 +157,7 @@ linux.pstree
|
||||
***** 1548 1266 gsd-keyboard
|
||||
***** 1550 1266 gsd-media-keys
|
||||
|
||||
``linux.pstree`` helps us to display the parent child relationships between processes.
|
||||
``linux.pstree`` helps us to display the parent-child relationships between processes.
|
||||
|
||||
linux.bash
|
||||
~~~~~~~~~~
|
||||
|
||||
@@ -37,7 +37,7 @@ For plugin requests, please create an issue with a description of the requested
|
||||
mac.check_sysctl.Check_sysctl
|
||||
mac.check_trap_table.Check_trap_table
|
||||
|
||||
.. note:: Here the the command is piped to grep and head in-order to provide the start of the list of macOS plugins.
|
||||
.. note:: Here the the command is piped to grep and head to provide the start of the list of macOS plugins.
|
||||
|
||||
|
||||
Using plugins
|
||||
@@ -78,7 +78,7 @@ Thanks go to `stuxnet <https://github.com/stuxnet999/>`_ for providing this memo
|
||||
|
||||
|
||||
The above command helps us to find the memory dump's Darwin kernel version. Now using the above banner we can search for the needed ISF file.
|
||||
If ISF file cannot be found then, follow the instructions on :ref:`getting-started-mac-tutorial:Procedure to create symbol tables for macOS`. After that, place the ISF file under the ``volatility3/symbols`` directory.
|
||||
If an ISF file cannot be found then, follow the instructions on :ref:`getting-started-mac-tutorial:Procedure to create symbol tables for macOS`. After that, place the ISF file under the ``volatility3/symbols`` directory.
|
||||
|
||||
mac.pslist
|
||||
~~~~~~~~~~
|
||||
@@ -125,7 +125,7 @@ mac.pstree
|
||||
337 1 system_installd
|
||||
* 455 337 update_dyld_shar
|
||||
|
||||
``mac.pstree`` helps us to display the parent child relationships between processes.
|
||||
``mac.pstree`` helps us to display the parent-child relationships between processes.
|
||||
|
||||
mac.ifconfig
|
||||
~~~~~~~~~~~~
|
||||
@@ -150,4 +150,4 @@ mac.ifconfig
|
||||
utun0 False
|
||||
utun0 fe80:5::2a95:bb15:87e3:977c False
|
||||
|
||||
we can use the ``mac.ifconfig`` plugin to get information about the configuration of the network interfaces of the host under investigation.
|
||||
We can use the ``mac.ifconfig`` plugin to get information about the configuration of the network interfaces of the host under investigation.
|
||||
|
||||
@@ -15,19 +15,19 @@ Memory can be acquired using a number of tools, below are some examples but othe
|
||||
Listing Plugins
|
||||
---------------
|
||||
|
||||
The following is a sample of the windows plugins available for volatility3, it is not complete and more more plugins may
|
||||
The following is a sample of the windows plugins available for volatility3, it is not complete and more plugins may
|
||||
be added. For a complete reference, please see the volatility 3 :doc:`list of plugins <volatility3.plugins>`.
|
||||
For plugin requests, please create an issue with a description of the requested plugin.
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
$ python3 vol.py --help | grep windows | head -n 5
|
||||
$ python3 vol.py --help | grep windows | head -n 4
|
||||
windows.bigpools.BigPools
|
||||
windows.cmdline.CmdLine
|
||||
windows.crashinfo.Crashinfo
|
||||
windows.dlllist.DllList
|
||||
|
||||
.. note:: Here the the command is piped to grep and head in-order to provide the start of a list of the available windows plugins.
|
||||
.. note:: Here the the command is piped to grep and head to provide the start of a list of the available windows plugins.
|
||||
|
||||
Using plugins
|
||||
-------------
|
||||
@@ -95,9 +95,9 @@ windows.pstree
|
||||
** 616 504 svchost.exe 0xfa8002b86ab0 13 314 0 False 2022-02-07 16:32:16.000000 N/A
|
||||
** 624 504 svchost.exe 0xfa8002410630 10 350 0 False 2022-02-07 16:30:14.000000 N/A
|
||||
|
||||
``windows.pstree`` helps to display the parent child relationships between processes.
|
||||
``windows.pstree`` helps to display the parent-child relationships between processes.
|
||||
|
||||
.. note:: Here the the command is piped to head in-order to provide smaller output, here listing only the first 20.
|
||||
.. note:: Here the the command is piped to head to provide smaller output, here listing only the first 20.
|
||||
|
||||
windows.hashdump
|
||||
~~~~~~~~~~~~~~~~
|
||||
@@ -116,9 +116,3 @@ windows.hashdump
|
||||
Dennis 1003 aad3b435b51404eeaad3b435b51404ee cf96684bbc7877920adaa9663698bf54
|
||||
|
||||
``windows.hashdump`` helps to list the hashes of the users in the system.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ Options
|
||||
EXTEND. Extensions must be of the form **configuration.item.name=value**
|
||||
|
||||
-p PLUGIN_DIRS, --plugin-dirs PLUGIN_DIRS
|
||||
Specified a semi-colon separated list of paths that contain directories
|
||||
Specified as a semi-colon separated list of paths that contain directories
|
||||
where plugins may be found. These paths are searched before the default
|
||||
paths when loading python files for plugins. This can therefore be used
|
||||
to override built-in plugins. NOTE: All python code within this directory
|
||||
@@ -67,12 +67,12 @@ Options
|
||||
-s SYMBOL_DIRS, --symbol-dirs SYMBOL_DIRS
|
||||
SYMBOL_DIRS is a semi-colon separated list of paths that contain symbol
|
||||
files or symbol zip packs. Symbols must be within a particular directory
|
||||
structure if they depending on the operating system of the symbols,
|
||||
structure if they depend on the operating system of the symbols,
|
||||
whilst symbol packs must be in the root of the directory and named after
|
||||
the after the operating system to which they apply.
|
||||
the operating system to which they apply.
|
||||
|
||||
-v, --verbose
|
||||
A flag which can be used multiple times, each time increasing the level of
|
||||
A flag which can be used multiple times (up to six, -vvvvvv), each time increasing the level of
|
||||
detail in the logs produced.
|
||||
|
||||
-l LOG, --log LOG
|
||||
@@ -87,7 +87,7 @@ Options
|
||||
-q, --quiet
|
||||
When present, this flag mutes the progress feedback for operations. This
|
||||
can be beneficial when piping the output directly to a file or another
|
||||
tool. This also removes the
|
||||
tool.
|
||||
|
||||
-r RENDERER, --renderer RENDERER
|
||||
Specifies the output format in which to display results. The default is
|
||||
@@ -120,9 +120,7 @@ Options
|
||||
Change the default path used to store the cache.
|
||||
|
||||
--offline
|
||||
Do not search online for additional JSON files.
|
||||
Run offline mode (defaults to false) and for
|
||||
remote windows symbol tables, linux/mac banner repositories.
|
||||
Run offline mode (defaults to false). Do not search online for additional JSON files, remote windows symbol tables, nor linux/mac banner repositories.
|
||||
|
||||
--single-location SINGLE_LOCATION
|
||||
This specifies a URL which will be downloaded if necessary, and built
|
||||
@@ -152,7 +150,7 @@ but can be overridden by creating a JSON file (`%APPDATA%/volatility3/vol.json`
|
||||
systems, or `~/.config/volatility3/vol.json` or `volshell.json` for all others).
|
||||
|
||||
The format of this file is a JSON dictionary, containing the options above and their value.
|
||||
It should be noted that the ordering is (`<` means is overridden by):
|
||||
It should be noted that the ordering is (`x < y` means `x` is overridden by `y`):
|
||||
|
||||
`in-built default value < config file value < command line parameter`
|
||||
|
||||
|
||||
@@ -632,6 +632,26 @@ def test_linux_vmayarascan_yara_string(image, volatility, python):
|
||||
assert rc == 0
|
||||
|
||||
|
||||
def test_linux_page_cache_files(image, volatility, python):
|
||||
rc, out, _err = runvol_plugin(
|
||||
"linux.pagecache.Files",
|
||||
image,
|
||||
volatility,
|
||||
python,
|
||||
pluginargs=["--find", "/etc/passwd"],
|
||||
)
|
||||
out = out.lower()
|
||||
|
||||
assert out.count(b"\n") > 4
|
||||
|
||||
# inode_num inode_addr ... file_path
|
||||
assert re.search(
|
||||
rb"146829\s0x88001ab5c270.*?/etc/passwd",
|
||||
out,
|
||||
)
|
||||
assert rc == 0
|
||||
|
||||
|
||||
# MAC
|
||||
|
||||
|
||||
|
||||
@@ -49,12 +49,12 @@ def hex_bytes_as_text(value: bytes, width: int = 16) -> str:
|
||||
output += "\n"
|
||||
printables = ""
|
||||
|
||||
# Handle leftovers when the lenght is not mutiple of width
|
||||
# Handle leftovers when the length is not mutiple of width
|
||||
if printables:
|
||||
padding = width - len(printables)
|
||||
output += " " * (padding)
|
||||
output += " " * padding
|
||||
output += printables
|
||||
output += " " * (padding)
|
||||
output += " " * padding
|
||||
|
||||
return output
|
||||
|
||||
@@ -132,7 +132,7 @@ def display_disassembly(disasm: interfaces.renderers.Disassembly) -> str:
|
||||
for i in disasm_types[disasm.architecture].disasm(
|
||||
disasm.data, disasm.offset
|
||||
):
|
||||
output += f"\n0x{i.address:x}:\t{i.mnemonic}\t{i.op_str}"
|
||||
output += f"\n{i.address:#x}:\t{i.mnemonic}\t{i.op_str}"
|
||||
return output
|
||||
return QuickTextRenderer._type_renderers[bytes](disasm.data)
|
||||
|
||||
@@ -342,7 +342,7 @@ class PrettyTextRenderer(CLIRenderer):
|
||||
column_separator = " | "
|
||||
|
||||
tree_indent_column = "".join(
|
||||
random.choice(string.ascii_uppercase + string.digits) for _ in range(20)
|
||||
random.choices(string.ascii_uppercase + string.digits, k=20)
|
||||
)
|
||||
max_column_widths = dict(
|
||||
[(column.name, len(column.name)) for column in grid.columns]
|
||||
|
||||
@@ -143,6 +143,18 @@ class LinuxIntelStacker(interfaces.automagic.StackerLayerInterface):
|
||||
and init_task.state.cast("unsigned int") != 0
|
||||
):
|
||||
continue
|
||||
elif init_task.active_mm.cast("long unsigned int") == module.get_symbol(
|
||||
"init_mm"
|
||||
).address and init_task.tasks.next.cast(
|
||||
"long unsigned int"
|
||||
) == init_task.tasks.prev.cast(
|
||||
"long unsigned int"
|
||||
):
|
||||
# The idle task steals `mm` from previously running task, i.e.,
|
||||
# `init_mm` is only used as long as no CPU has ever been idle.
|
||||
# This catches cases where we found a fragment of the
|
||||
# unrelocated ELF file instead of the running kernel.
|
||||
continue
|
||||
|
||||
# This we get for free
|
||||
aslr_shift = (
|
||||
|
||||
@@ -529,6 +529,8 @@ class VersionRequirement(interfaces.configuration.RequirementInterface):
|
||||
component: Type[interfaces.configuration.VersionableInterface] = None,
|
||||
version: Optional[Tuple[int, ...]] = None,
|
||||
) -> None:
|
||||
if version is None:
|
||||
raise TypeError("Version cannot be None")
|
||||
if description is None:
|
||||
description = f"Version {'.'.join([str(x) for x in version])} dependency on {component.__module__}.{component.__name__} unmet"
|
||||
super().__init__(
|
||||
@@ -537,8 +539,6 @@ class VersionRequirement(interfaces.configuration.RequirementInterface):
|
||||
if component is None:
|
||||
raise TypeError("Component cannot be None")
|
||||
self._component: Type[interfaces.configuration.VersionableInterface] = component
|
||||
if version is None:
|
||||
raise TypeError("Version cannot be None")
|
||||
self._version = version
|
||||
|
||||
def unsatisfied(
|
||||
|
||||
@@ -73,9 +73,7 @@ class Intel(linear.LinearlyMappedLayer):
|
||||
)
|
||||
|
||||
# These can vary depending on the type of space
|
||||
self._index_shift = int(
|
||||
math.ceil(math.log2(struct.calcsize(self._entry_format)))
|
||||
)
|
||||
self._index_shift = math.ceil(math.log2(struct.calcsize(self._entry_format)))
|
||||
|
||||
@classproperty
|
||||
@functools.lru_cache()
|
||||
@@ -125,7 +123,6 @@ class Intel(linear.LinearlyMappedLayer):
|
||||
high_mask = (1 << (high_bit + 1)) - 1
|
||||
low_mask = (1 << low_bit) - 1
|
||||
mask = high_mask ^ low_mask
|
||||
# print(high_bit, low_bit, bin(mask), bin(value))
|
||||
return value & mask
|
||||
|
||||
@staticmethod
|
||||
@@ -147,7 +144,7 @@ class Intel(linear.LinearlyMappedLayer):
|
||||
return self._mask(addr, self._maxvirtaddr, 0) + self._canonical_prefix
|
||||
|
||||
def decanonicalize(self, addr: int) -> int:
|
||||
"""Removes canonicalization to ensure an adress fits within the correct range if it has been canonicalized
|
||||
"""Removes canonicalization to ensure an address fits within the correct range if it has been canonicalized
|
||||
|
||||
This will produce an address outside the range if the canonicalization is incorrect
|
||||
"""
|
||||
|
||||
@@ -389,7 +389,7 @@ class InodePages(plugins.PluginInterface):
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
|
||||
_version = (1, 0, 1)
|
||||
_version = (2, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
@@ -412,9 +412,10 @@ class InodePages(plugins.PluginInterface):
|
||||
description="Inode address",
|
||||
optional=True,
|
||||
),
|
||||
requirements.StringRequirement(
|
||||
requirements.BooleanRequirement(
|
||||
name="dump",
|
||||
description="Output file path",
|
||||
description="Extract inode content",
|
||||
default=False,
|
||||
optional=True,
|
||||
),
|
||||
]
|
||||
@@ -436,7 +437,7 @@ class InodePages(plugins.PluginInterface):
|
||||
"""
|
||||
if not inode.is_reg:
|
||||
vollog.error("The inode is not a regular file")
|
||||
return
|
||||
return None
|
||||
|
||||
# By using truncate/seek, provided the filesystem supports it, a sparse file will be
|
||||
# created, saving both disk space and I/O time.
|
||||
@@ -471,7 +472,7 @@ class InodePages(plugins.PluginInterface):
|
||||
|
||||
if self.config["inode"] and self.config["find"]:
|
||||
vollog.error("Cannot use --inode and --find simultaneously")
|
||||
return
|
||||
return None
|
||||
|
||||
if self.config["find"]:
|
||||
inodes_iter = Files.get_inodes(
|
||||
@@ -487,15 +488,15 @@ class InodePages(plugins.PluginInterface):
|
||||
inode = vmlinux.object("inode", self.config["inode"], absolute=True)
|
||||
else:
|
||||
vollog.error("You must use either --inode or --find")
|
||||
return
|
||||
return None
|
||||
|
||||
if not inode.is_valid():
|
||||
vollog.error("Invalid inode at 0x%x", inode.vol.offset)
|
||||
return
|
||||
return None
|
||||
|
||||
if not inode.is_reg:
|
||||
vollog.error("The inode is not a regular file")
|
||||
return
|
||||
return None
|
||||
|
||||
inode_size = inode.i_size
|
||||
for page_obj in inode.get_pages():
|
||||
@@ -519,9 +520,13 @@ class InodePages(plugins.PluginInterface):
|
||||
yield 0, fields
|
||||
|
||||
if self.config["dump"]:
|
||||
filename = self.config["dump"]
|
||||
vollog.info("[*] Writing inode at 0x%x to '%s'", inode.vol.offset, filename)
|
||||
self.write_inode_content_to_file(inode, filename, self.open, vmlinux_layer)
|
||||
open_method = self.open
|
||||
inode_address = inode.vol.offset
|
||||
filename = open_method.sanitize_filename(f"inode_0x{inode_address:x}.dmp")
|
||||
vollog.info("[*] Writing inode at 0x%x to '%s'", inode_address, filename)
|
||||
self.write_inode_content_to_file(
|
||||
inode, filename, open_method, vmlinux_layer
|
||||
)
|
||||
|
||||
def run(self):
|
||||
headers = [
|
||||
|
||||
@@ -48,7 +48,7 @@ class Callbacks(interfaces.plugins.PluginInterface):
|
||||
name="driverirp", plugin=driverirp.DriverIrp, version=(1, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="handles", plugin=handles.Handles, version=(1, 0, 0)
|
||||
name="handles", plugin=handles.Handles, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ class DumpFiles(interfaces.plugins.PluginInterface):
|
||||
name="pslist", component=pslist.PsList, version=(2, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="handles", component=handles.Handles, version=(1, 0, 0)
|
||||
name="handles", component=handles.Handles, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
#
|
||||
|
||||
import logging
|
||||
from typing import List, Optional, Dict
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from volatility3.framework import constants, exceptions, renderers, interfaces, symbols
|
||||
from volatility3.framework import constants, exceptions, interfaces, renderers, symbols
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.objects import utility
|
||||
from volatility3.framework.renderers import format_hints
|
||||
@@ -13,23 +13,15 @@ from volatility3.plugins.windows import pslist, psscan
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import capstone
|
||||
|
||||
has_capstone = True
|
||||
except ImportError:
|
||||
has_capstone = False
|
||||
|
||||
|
||||
class Handles(interfaces.plugins.PluginInterface):
|
||||
"""Lists process open handles."""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
_version = (1, 0, 2)
|
||||
_version = (2, 0, 0)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._sar_value = None
|
||||
self._type_map = None
|
||||
self._cookie = None
|
||||
self._level_mask = 7
|
||||
@@ -62,21 +54,6 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
),
|
||||
]
|
||||
|
||||
def _decode_pointer(self, value, magic):
|
||||
"""Windows encodes pointers to objects and decodes them on the fly
|
||||
before using them.
|
||||
|
||||
This function mimics the decoding routine so we can generate the
|
||||
proper pointer values as well.
|
||||
"""
|
||||
|
||||
value = value & 0xFFFFFFFFFFFFFFF8
|
||||
value = value >> magic
|
||||
# if (value & (1 << 47)):
|
||||
# value = value | 0xFFFF000000000000
|
||||
|
||||
return value
|
||||
|
||||
def _get_item(self, handle_table_entry, handle_value):
|
||||
"""Given a handle table entry (_HANDLE_TABLE_ENTRY) structure from a
|
||||
process' handle table, determine where the corresponding object's
|
||||
@@ -100,24 +77,11 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
)
|
||||
|
||||
if is_64bit:
|
||||
if handle_table_entry.LowValue == 0:
|
||||
if handle_table_entry.ObjectPointerBits == 0:
|
||||
return None
|
||||
|
||||
magic = self.find_sar_value()
|
||||
offset = handle_table_entry.ObjectPointerBits << 4
|
||||
|
||||
# is this the right thing to raise here?
|
||||
if magic is None:
|
||||
if has_capstone:
|
||||
raise AttributeError(
|
||||
"Unable to find the SAR value for decoding handle table pointers"
|
||||
)
|
||||
else:
|
||||
raise exceptions.MissingModuleException(
|
||||
"capstone",
|
||||
"Requires capstone to find the SAR value for decoding handle table pointers",
|
||||
)
|
||||
|
||||
offset = self._decode_pointer(handle_table_entry.LowValue, magic)
|
||||
else:
|
||||
if handle_table_entry.InfoTable == 0:
|
||||
return None
|
||||
@@ -135,78 +99,6 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
object_header.HandleValue = handle_value
|
||||
return object_header
|
||||
|
||||
def find_sar_value(self):
|
||||
"""Locate ObpCaptureHandleInformationEx if it exists in the sample.
|
||||
|
||||
Once found, parse it for the SAR value that we need to decode
|
||||
pointers in the _HANDLE_TABLE_ENTRY which allows us to find the
|
||||
associated _OBJECT_HEADER.
|
||||
"""
|
||||
DEFAULT_SAR_VALUE = 0x10 # to be used only when decoding fails
|
||||
|
||||
if self._sar_value is None:
|
||||
if not has_capstone:
|
||||
vollog.debug(
|
||||
"capstone module is missing, unable to create disassembly of ObpCaptureHandleInformationEx"
|
||||
)
|
||||
return None
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
|
||||
virtual_layer_name = kernel.layer_name
|
||||
kvo = self.context.layers[virtual_layer_name].config[
|
||||
"kernel_virtual_offset"
|
||||
]
|
||||
ntkrnlmp = self.context.module(
|
||||
kernel.symbol_table_name, layer_name=virtual_layer_name, offset=kvo
|
||||
)
|
||||
|
||||
try:
|
||||
func_addr = ntkrnlmp.get_symbol("ObpCaptureHandleInformationEx").address
|
||||
except exceptions.SymbolError:
|
||||
vollog.debug("Unable to locate ObpCaptureHandleInformationEx symbol")
|
||||
return None
|
||||
|
||||
try:
|
||||
func_addr_to_read = kvo + func_addr
|
||||
num_bytes_to_read = 0x200
|
||||
vollog.debug(
|
||||
f"ObpCaptureHandleInformationEx symbol located at {hex(func_addr_to_read)}"
|
||||
)
|
||||
data = self.context.layers.read(
|
||||
virtual_layer_name, func_addr_to_read, num_bytes_to_read
|
||||
)
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.warning(
|
||||
f"Failed to read {hex(num_bytes_to_read)} bytes at symbol {hex(func_addr_to_read)}. Unable to decode SAR value. Failing back to a common value of {hex(DEFAULT_SAR_VALUE)}"
|
||||
)
|
||||
self._sar_value = DEFAULT_SAR_VALUE
|
||||
return self._sar_value
|
||||
|
||||
md = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_64)
|
||||
|
||||
instruction_count = 0
|
||||
for address, size, mnemonic, op_str in md.disasm_lite(
|
||||
data, kvo + func_addr
|
||||
):
|
||||
# print("{} {} {} {}".format(address, size, mnemonic, op_str))
|
||||
instruction_count += 1
|
||||
if mnemonic.startswith("sar"):
|
||||
# if we don't want to parse op strings, we can disasm the
|
||||
# single sar instruction again, but we use disasm_lite for speed
|
||||
self._sar_value = int(op_str.split(",")[1].strip(), 16)
|
||||
vollog.debug(
|
||||
f"SAR located at {hex(address)} with value of {hex(self._sar_value)}"
|
||||
)
|
||||
break
|
||||
|
||||
if self._sar_value is None:
|
||||
vollog.warning(
|
||||
f"Failed to to locate SAR value having parsed {instruction_count} instructions, failing back to a common value of {hex(DEFAULT_SAR_VALUE)}"
|
||||
)
|
||||
self._sar_value = DEFAULT_SAR_VALUE
|
||||
|
||||
return self._sar_value
|
||||
|
||||
@classmethod
|
||||
def get_type_map(
|
||||
cls,
|
||||
|
||||
@@ -73,7 +73,7 @@ class IndirectSystemCalls(direct_system_calls.DirectSystemCalls):
|
||||
|
||||
@staticmethod
|
||||
def _indirect_syscall_block_target(
|
||||
proc_layer: interfaces.layers.DataLayerInterface, inst: capstone._cs_insn
|
||||
proc_layer: interfaces.layers.DataLayerInterface, inst
|
||||
) -> Optional[int]:
|
||||
"""
|
||||
This function determines the address of a jmp in the following form:
|
||||
|
||||
@@ -139,7 +139,7 @@ class PoolScanner(plugins.PluginInterface):
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="handles", plugin=handles.Handles, version=(1, 0, 0)
|
||||
name="handles", plugin=handles.Handles, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ class PsXView(plugins.PluginInterface):
|
||||
name="thrdscan", component=thrdscan.ThrdScan, version=(1, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="handles", component=handles.Handles, version=(1, 0, 0)
|
||||
name="handles", component=handles.Handles, version=(2, 0, 0)
|
||||
),
|
||||
requirements.BooleanRequirement(
|
||||
name="physical-offsets",
|
||||
|
||||
@@ -1107,9 +1107,16 @@ class dentry(objects.StructType):
|
||||
walk_member = "d_sib"
|
||||
list_head_member = self.d_children
|
||||
elif self.has_member("d_child") and self.has_member("d_subdirs"):
|
||||
# 2.5.0 <= kernels < 6.8
|
||||
# 3.19.0 <= kernels < 6.8
|
||||
walk_member = "d_child"
|
||||
list_head_member = self.d_subdirs
|
||||
elif self.has_member("d_u") and self.has_member("d_subdirs"):
|
||||
# kernels < 3.19
|
||||
|
||||
# Actually, 'd_u.d_child' but to_list() doesn't support something like that.
|
||||
# Since, it's an union, everything is at the same offset than 'd_u'.
|
||||
walk_member = "d_u"
|
||||
list_head_member = self.d_subdirs
|
||||
else:
|
||||
raise exceptions.VolatilityException("Unsupported dentry type")
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ class ProducerMetadata(interfaces.symbols.MetadataInterface):
|
||||
@property
|
||||
def version(self) -> Optional[Tuple[int]]:
|
||||
"""Returns the version of the ISF file producer"""
|
||||
version = self.version_string()
|
||||
version = self.version_string
|
||||
if not version:
|
||||
return None
|
||||
if all(x in "0123456789." for x in version):
|
||||
|
||||
Reference in New Issue
Block a user