From ce5bc3ccd89a443b50e9c2f55bccf135a41bf827 Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Sun, 26 Sep 2021 01:33:48 +0100 Subject: [PATCH] Layers: Improve non-linear segmented layers --- volatility3/framework/interfaces/layers.py | 3 ++- volatility3/framework/layers/qemu.py | 9 ++++++--- volatility3/framework/layers/segmented.py | 5 ++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/volatility3/framework/interfaces/layers.py b/volatility3/framework/interfaces/layers.py index 28c452f90..79b8902e3 100644 --- a/volatility3/framework/interfaces/layers.py +++ b/volatility3/framework/interfaces/layers.py @@ -441,7 +441,8 @@ class TranslationLayerInterface(DataLayerInterface, metaclass = ABCMeta): unprocessed_data = self._context.layers.read(layer, mapped_offset, mapped_length, pad) processed_data = self._decode_data(unprocessed_data, mapped_offset, layer_offset, sublength) if len(processed_data) != sublength: - raise ValueError("ProcessedData length does not match expected length of chunk") + raise ValueError( + f"ProcessedData length {len(processed_data)} does not match expected length of chunk {sublength}") output += processed_data current_offset += sublength return output + (b"\x00" * (length - len(output))) diff --git a/volatility3/framework/layers/qemu.py b/volatility3/framework/layers/qemu.py index ff0644dbc..b56dbe272 100644 --- a/volatility3/framework/layers/qemu.py +++ b/volatility3/framework/layers/qemu.py @@ -1,6 +1,7 @@ # This file is Copyright 2020 Volatility Foundation and licensed under the Volatility Software License 1.0 # which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 # +import bisect import functools import json import math @@ -211,9 +212,11 @@ class QemuSuspendLayer(segmented.NonLinearlySegmentedLayer): return index def _decode_data(self, data: bytes, mapped_offset: int, offset: int, output_length: int) -> bytes: - if mapped_offset in self._compressed: - return (data * 0x1000)[:output_length] - return data + start_offset, _, _, _ = self._segments[bisect.bisect_right(self._segments, (offset, 0xffffffffffffff,)) - 1] + if offset in self._compressed: + data = (data * 0x1000) + result = data[offset - start_offset:output_length + offset - start_offset] + return result @functools.lru_cache(maxsize = 512) def read(self, offset: int, length: int, pad: bool = False) -> bytes: diff --git a/volatility3/framework/layers/segmented.py b/volatility3/framework/layers/segmented.py index 80c89723a..e4a58e983 100644 --- a/volatility3/framework/layers/segmented.py +++ b/volatility3/framework/layers/segmented.py @@ -35,7 +35,7 @@ class NonLinearlySegmentedLayer(interfaces.layers.TranslationLayerInterface, met def _load_segments(self) -> None: """Populates the _segments variable. - Segments must be (address, mapped address, length) and must be + Segments must be (address, mapped address, length, mapped_length) and must be sorted by address when this method exits """ @@ -85,7 +85,6 @@ class NonLinearlySegmentedLayer(interfaces.layers.TranslationLayerInterface, met if current_offset > logical_offset: difference = current_offset - logical_offset logical_offset += difference - mapped_offset += difference size -= difference except exceptions.InvalidAddressException: if not ignore_errors: @@ -103,7 +102,7 @@ class NonLinearlySegmentedLayer(interfaces.layers.TranslationLayerInterface, met return # Crop it to the amount we need left chunk_size = min(size, length + offset - logical_offset) - yield logical_offset, chunk_size, mapped_offset, chunk_size, self._base_layer + yield logical_offset, chunk_size, mapped_offset, mapped_size, self._base_layer current_offset += chunk_size # Terminate if we've gone (or reached) our required limit if current_offset >= offset + length: