leverage the existing Array facility

This commit is contained in:
Abyss Watcher
2025-11-20 13:20:18 +01:00
parent 6e67674c20
commit a5cc616d53
+31 -34
View File
@@ -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
)