From c77ed912432f66c4de63116438f23f705e5479a6 Mon Sep 17 00:00:00 2001 From: Gustavo Moreira Date: Thu, 19 Dec 2024 10:53:38 +1100 Subject: [PATCH 1/2] windows: crashdump: fix potential uninitialzed variable #1438 --- volatility3/framework/layers/crash.py | 1 + 1 file changed, 1 insertion(+) diff --git a/volatility3/framework/layers/crash.py b/volatility3/framework/layers/crash.py index a5b25d178b..c789129a30 100644 --- a/volatility3/framework/layers/crash.py +++ b/volatility3/framework/layers/crash.py @@ -129,6 +129,7 @@ def _load_segments(self) -> None: elif self.dump_type == 0x05: summary_header = self.get_summary_header() + last_bit_seen = 0 # Most recent bit processed seg_first_bit = None # First bit in a run seg_first_offset = 0 # File offset of first bit offset = ( From 446f9696463d6c6164283a60588ef31771eb8044 Mon Sep 17 00:00:00 2001 From: Gustavo Moreira Date: Thu, 19 Dec 2024 11:23:04 +1100 Subject: [PATCH 2/2] windows: crashdump: Refactor _load_segments() by improving docstrings, removing hardcoded values, and cleaning up the code for better readability and maintainability --- volatility3/framework/layers/crash.py | 232 ++++++++++++++------------ 1 file changed, 127 insertions(+), 105 deletions(-) diff --git a/volatility3/framework/layers/crash.py b/volatility3/framework/layers/crash.py index c789129a30..5aad7d3d95 100644 --- a/volatility3/framework/layers/crash.py +++ b/volatility3/framework/layers/crash.py @@ -3,7 +3,7 @@ # import logging import struct -from typing import Tuple, Optional +from typing import Tuple, Optional, List from volatility3.framework import constants, exceptions, interfaces from volatility3.framework.layers import segmented @@ -28,6 +28,9 @@ class WindowsCrashDump32Layer(segmented.SegmentedLayer): SIGNATURE = 0x45474150 VALIDDUMP = 0x504D5544 + DUMP_TYPE_FULL = 1 + DUMP_TYPE_BITMAP_FULL = 5 + crashdump_json = "crash" supported_dumptypes = [0x01, 0x05] # we need 0x5 for 32-bit bitmaps dump_header_name = "_DUMP_HEADER" @@ -99,109 +102,128 @@ def get_summary_header(self) -> interfaces.objects.ObjectInterface: layer_name=self._base_layer, ) - def _load_segments(self) -> None: - """Loads up the segments from the meta_layer. - A segment is a set of contiguous memory pages.""" + def _get_segments_from_dump_type_full(self) -> List[Tuple[int, int, int, int]]: + """Returns the segments contained in a full dump. + Returns: + A list of segment tuples (offset, mapped_offset, length, mapped_length) + """ segments = [] + header = self.context.object( + self._crash_table_name + constants.BANG + self.dump_header_name, + offset=0, + layer_name=self._base_layer, + ) - if self.dump_type == 0x1: - header = self.context.object( - self._crash_table_name + constants.BANG + self.dump_header_name, - offset=0, - layer_name=self._base_layer, + offset = self.headerpages + header.PhysicalMemoryBlockBuffer.Run.count = ( + header.PhysicalMemoryBlockBuffer.NumberOfRuns + ) + for run in header.PhysicalMemoryBlockBuffer.Run: + segments.append( + ( + run.BasePage * self._page_size, + offset * self._page_size, + run.PageCount * self._page_size, + run.PageCount * self._page_size, + ) ) + offset += run.PageCount - offset = self.headerpages - header.PhysicalMemoryBlockBuffer.Run.count = ( - header.PhysicalMemoryBlockBuffer.NumberOfRuns - ) - for run in header.PhysicalMemoryBlockBuffer.Run: - segments.append( - ( - run.BasePage * self._page_size, - offset * self._page_size, - run.PageCount * self._page_size, - run.PageCount * self._page_size, - ) - ) - offset += run.PageCount - - elif self.dump_type == 0x05: - summary_header = self.get_summary_header() - last_bit_seen = 0 # Most recent bit processed - seg_first_bit = None # First bit in a run - seg_first_offset = 0 # File offset of first bit - offset = ( - summary_header.HeaderSize - ) # Offset to the start of actual memory dump - ulong_bitmap_array = summary_header.get_buffer_long() - # outer_index points to a 32 bits array inside a list of arrays, - # each bit indicating a page mapping state - for outer_index in range(ulong_bitmap_array.vol.count): - ulong_bitmap = ulong_bitmap_array[outer_index] - # All pages in this 32 bits array are mapped (speedup iteration process) - if ulong_bitmap == 0xFFFFFFFF: - # New segment - if seg_first_bit is None: - seg_first_offset = offset - seg_first_bit = outer_index * 32 - offset += 32 * self._page_size - # No pages in this 32 bits array are mapped (speedup iteration process) - elif ulong_bitmap == 0: - # End of segment - if seg_first_bit is not None: - last_bit = (outer_index - 1) * 32 + 31 - segment_length = ( - last_bit - seg_first_bit + 1 - ) * self._page_size - segments.append( - ( - seg_first_bit * self._page_size, - seg_first_offset, - segment_length, - segment_length, - ) + return segments + + def _get_segments_from_dump_type_bitmap_full( + self, + ) -> List[Tuple[int, int, int, int]]: + """Returns the segments contained in a bitmap full dump. + + Returns: + A list of segment tuples (offset, mapped_offset, length, mapped_length) + """ + segments = [] + summary_header = self.get_summary_header() + last_bit_seen = 0 # Most recent bit processed + seg_first_bit = None # First bit in a run + seg_first_offset = 0 # File offset of first bit + offset = summary_header.HeaderSize # Offset to the start of actual memory dump + ulong_bitmap_array = summary_header.get_buffer_long() + # outer_index points to a 32 bits array inside a list of arrays, + # each bit indicating a page mapping state + for outer_index in range(ulong_bitmap_array.vol.count): + ulong_bitmap = ulong_bitmap_array[outer_index] + # All pages in this 32 bits array are mapped (speedup iteration process) + if ulong_bitmap == 0xFFFFFFFF: + # New segment + if seg_first_bit is None: + seg_first_offset = offset + seg_first_bit = outer_index * 32 + offset += 32 * self._page_size + # No pages in this 32 bits array are mapped (speedup iteration process) + elif ulong_bitmap == 0: + # End of segment + if seg_first_bit is not None: + last_bit = (outer_index - 1) * 32 + 31 + segment_length = (last_bit - seg_first_bit + 1) * self._page_size + segments.append( + ( + seg_first_bit * self._page_size, + seg_first_offset, + segment_length, + segment_length, ) - seg_first_bit = None - # Some pages in this 32 bits array are mapped and some aren't - else: - for inner_bit_position in range(32): - current_bit = outer_index * 32 + inner_bit_position - page_mapped = ulong_bitmap & (1 << inner_bit_position) - if page_mapped: - # New segment - if seg_first_bit is None: - seg_first_offset = offset - seg_first_bit = current_bit - offset += self._page_size - else: - # End of segment - if seg_first_bit is not None: - segment_length = ( - current_bit - 1 - seg_first_bit + 1 - ) * self._page_size - segments.append( - ( - seg_first_bit * self._page_size, - seg_first_offset, - segment_length, - segment_length, - ) - ) - seg_first_bit = None - last_bit_seen = outer_index * 32 + 31 - - if seg_first_bit is not None: - segment_length = (last_bit_seen - seg_first_bit + 1) * self._page_size - segments.append( - ( - seg_first_bit * self._page_size, - seg_first_offset, - segment_length, - segment_length, ) + seg_first_bit = None + # Some pages in this 32 bits array are mapped and some aren't + else: + for inner_bit_position in range(32): + current_bit = outer_index * 32 + inner_bit_position + page_mapped = ulong_bitmap & (1 << inner_bit_position) + if page_mapped: + # New segment + if seg_first_bit is None: + seg_first_offset = offset + seg_first_bit = current_bit + offset += self._page_size + else: + # End of segment + if seg_first_bit is not None: + segment_length = ( + current_bit - 1 - seg_first_bit + 1 + ) * self._page_size + segments.append( + ( + seg_first_bit * self._page_size, + seg_first_offset, + segment_length, + segment_length, + ) + ) + seg_first_bit = None + last_bit_seen = outer_index * 32 + 31 + + if seg_first_bit is not None: + segment_length = (last_bit_seen - seg_first_bit + 1) * self._page_size + segments.append( + ( + seg_first_bit * self._page_size, + seg_first_offset, + segment_length, + segment_length, ) + ) + + return segments + + def _load_segments(self) -> None: + """Loads up the segments from the meta_layer. + A segment is a set of contiguous memory pages.""" + + segments = [] + + if self.dump_type == self.DUMP_TYPE_FULL: + segments = self._get_segments_from_dump_type_full() + elif self.dump_type == self.DUMP_TYPE_BITMAP_FULL: + segments = self._get_segments_from_dump_type_bitmap_full() else: vollog.log( constants.LOGLEVEL_VVVV, f"unsupported dump format 0x{self.dump_type:x}" @@ -210,18 +232,18 @@ def _load_segments(self) -> None: self.name, f"unsupported dump format 0x{self.dump_type:x}" ) - if len(segments) == 0: + if not segments: raise WindowsCrashDumpFormatException( self.name, f"No Crash segments defined in {self._base_layer}" ) - else: - # report the segments for debugging. this is valuable for dev/troubleshooting but - # not important enough for a dedicated plugin. - for idx, (start_position, mapped_offset, length, _) in enumerate(segments): - vollog.log( - constants.LOGLEVEL_VVVV, - f"Segment {idx}: Position {start_position:#x} Offset {mapped_offset:#x} Length {length:#x}", - ) + + # report the segments for debugging. this is valuable for dev/troubleshooting but + # not important enough for a dedicated plugin. + for idx, (start_position, mapped_offset, length, _) in enumerate(segments): + vollog.log( + constants.LOGLEVEL_VVVV, + f"Segment {idx}: Position {start_position:#x} Offset {mapped_offset:#x} Length {length:#x}", + ) self._segments = segments