From a5cc616d53f2db0d20e1dfff81e9d26ed2672b78 Mon Sep 17 00:00:00 2001 From: Abyss Watcher Date: Thu, 8 May 2025 12:49:56 +0200 Subject: [PATCH] leverage the existing Array facility --- volatility3/framework/objects/utility.py | 65 +++++++++++------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/volatility3/framework/objects/utility.py b/volatility3/framework/objects/utility.py index afea99b0c..be57f9ad7 100644 --- a/volatility3/framework/objects/utility.py +++ b/volatility3/framework/objects/utility.py @@ -3,11 +3,13 @@ # import re - -from typing import List, Optional, Union +import logging +from typing import Optional, Union from volatility3.framework import interfaces, objects, constants, exceptions +vollog = logging.getLogger(__name__) + def rol(value: int, count: int, max_bits: int = 64) -> int: """A rotate-left instruction in Python""" @@ -254,51 +256,46 @@ def array_of_pointers( def dynamically_sized_array_of_pointers( context: interfaces.context.ContextInterface, - layer_name: str, - symbol_table_name: str, - array_offset: int, + array: interfaces.objects.ObjectInterface, + iterator_guard_value: int, + subtype: Union[str, interfaces.objects.Template], stop_value: int = 0, - iterator_guard_value: int = None, stop_on_invalid_pointers: bool = True, -) -> List[interfaces.objects.ObjectInterface]: +) -> interfaces.objects.ObjectInterface: """Iterates over a dynamically sized array of pointers (e.g. NULL-terminated). + Array iteration should always be performed with an arbitrary guard value as maximum size, + to prevent running forever in case something unexpected happens. Args: context: The context on which to operate. - layer_name: The layer on which the array should be constructed. - symbol_table_name: The symbol table to use to construct object types. - array_offset: The array offset within the layer, from which to start iterating. - stop_value: Stop value used to determine when to terminate iteration once it is encountered. Defaults to 0 (NULL-terminated arrays). + array: The object to cast to an array. iterator_guard_value: Stop iterating when the iterator index is greater than this value. This is an extra-safety against smearing. + subtype: The subtype of the array's pointers. + stop_value: Stop value used to determine when to terminate iteration once it is encountered. Defaults to 0 (NULL-terminated arrays). stop_on_invalid_pointers: Determines whether to stop iterating or not when an invalid pointer is encountered. This can be useful for arrays that are known to have smeared entries before the end. Returns: An array of pointer objects """ - pointer_type = context.symbol_space.get_type( - symbol_table_name + constants.BANG + "pointer" - ) - entry = context.object( - pointer_type, - layer_name=layer_name, - offset=array_offset, - ) - i = 0 - array = [] - # entry and entry.vol.offset aren't the same thing, as - # - entry is naturally represented by the address that the pointer refers to; - # - entry.vol.offset is the offset at which the pointer lives. - while entry != stop_value: - if (not entry.is_readable() and stop_on_invalid_pointers) or ( - iterator_guard_value is not None and i >= iterator_guard_value + new_count = 0 + for entry in array_of_pointers( + array=array, count=iterator_guard_value, subtype=subtype, context=context + ): + # "entry" is naturally represented by the address that the pointer refers to + if (entry == stop_value) or ( + not entry.is_readable() and stop_on_invalid_pointers ): break - array.append(entry) - entry = context.object( - pointer_type, - layer_name=layer_name, - offset=entry.vol.offset + pointer_type.size, + new_count += 1 + else: + vollog.log( + constants.LOGLEVEL_V, + f"""Iterator guard value {iterator_guard_value} reached while iterating over array at offset {array.vol.offset:#x}.\ + This means that there is a bug (e.g. smearing) with this array, or that it may contain valid entries past the iterator guard value.""", ) - i += 1 - return array + + # Leverage the "Array" object instead of returning a Python list + return array_of_pointers( + array=array, count=new_count, subtype=subtype, context=context + )