diff --git a/volatility/framework/layers/__init__.py b/volatility/framework/layers/__init__.py index 8f63f2ad5..54a5a5982 100644 --- a/volatility/framework/layers/__init__.py +++ b/volatility/framework/layers/__init__.py @@ -23,7 +23,7 @@ except ImportError: from volatility import framework from volatility.framework import constants, validity -from volatility.framework.layers import intel, lime, physical, segmented, vmware +from volatility.framework.layers import intel, lime, physical, segmented, vmware, crash vollog = logging.getLogger(__name__) diff --git a/volatility/framework/layers/crash.py b/volatility/framework/layers/crash.py new file mode 100644 index 000000000..5c11d100a --- /dev/null +++ b/volatility/framework/layers/crash.py @@ -0,0 +1,130 @@ +# Volatility +# Copyright (C) 2018 Volatility Foundation +# +# Authors: +# awalters@4tphi.net (AAron Walters) +# +# This file is part of Volatility 3. + +import struct +import typing +import os.path as os_path + +from volatility.framework import constants, exceptions, interfaces, validity +from volatility.framework.layers import segmented +from volatility.framework.symbols import intermed + +class WindowsCrashDump32FormatException(exceptions.LayerException): + """Thrown when an error occurs with the underlying Crash file format""" + +class WindowsCrashDump32Layer(segmented.SegmentedLayer): + """A Windows crash format TranslationLayer. This TranslationLayer supports + Microsoft complete memory dump files. It currently does not support + kernel or small memory dump files.""" + + provides = {"type": "physical"} + priority = 23 + + SIGNATURE = 0x45474150 + VALIDDUMP = 0x504d5544 + _magic_struct = struct.Struct(' None: + + # Construct these so we can use self.config + self._context = context + self._config_path = config_path + self._page_size = 0x1000 + #self._base_layer, self._meta_layer = self.config["base_layer"], self.config["meta_layer"] + self._base_layer = self.config["base_layer"] + + + # Create a custom SymbolSpace + self._crash_table_name = context.symbol_space.free_table_name("crash") + crash_path = "file://" + os_path.join(os_path.dirname(__file__), '..', \ + 'symbols', 'windows', 'crash.json') + table = intermed.IntermediateSymbolTable(context = context, + config_path = config_path, + name = self._crash_table_name, + isf_url = crash_path) + context.symbol_space.append(table) + + # Check Header + hdr_layer = self._context.memory[self._base_layer] + hdr_offset = 0 + self._check_header(hdr_layer, hdr_offset) + + # Need to create a header object + self.header = self.context.object(self._crash_table_name + constants.BANG + + "_DMP_HEADER", offset = hdr_offset, + layer_name = self._base_layer) + + # Extract the DTB + self.dtb = self.header.DirectoryTableBase + + # Verify that it is a supported format + if self.header.DumpType != 0x1: + raise WindowsCrashDump32FormatException("unsupported dump format 0x{:x}".format(self.header.DumpType)) + + # Then call the super, which will call load_segments + super().__init__(context, config_path, name) + + #self._load_segments() + + def _load_segments(self) -> None: + """Loads up the segments from the meta_layer""" + + segments = [] + + offset = self.headerpages + for x in self.header.PhysicalMemoryBlockBuffer.Run: + segments.append((x.BasePage * 0x1000, + offset * 0x1000, + x.PageCount * 0x1000)) + #print("Segments {:x} {:x} {:x}".format(x.BasePage * 0x1000, + # offset * 0x1000, + # x.PageCount * 0x1000)) + offset += x.PageCount + + if len(segments) == 0: + raise WindowsCrashDump32FormatException("No Crash segments defined in {}".format(self._base_layer)) + + self._segments = segments + + @classmethod + def _check_header(cls, + base_layer: interfaces.layers.DataLayerInterface, + offset: int = 0) -> typing.Tuple[int, int]: + + # Verify the Window's crash dump file magic + header_data = base_layer.read(offset, cls._magic_struct.size) + (signature, validdump) = cls._magic_struct.unpack(header_data) + + if signature != cls.SIGNATURE: + raise WindowsCrashDump32FormatException("bad signature 0x{:x} at file offset 0x{:x}".format(signature, offset)) + if validdump != cls.VALIDDUMP: + raise WindowsCrashDump32FormatException("invalid dump 0x{:x} at file offset 0x{:x}".format(validdump, offset)) + + return + + +class WindowsCrashDump32Stacker(interfaces.automagic.StackerLayerInterface): + stack_order = 11 + + @classmethod + def stack(cls, + context: interfaces.context.ContextInterface, + layer_name: str, + progress_callback: validity.ProgressCallback = None) \ + -> typing.Optional[interfaces.layers.DataLayerInterface]: + try: + WindowsCrashDump32Layer._check_header(context.memory[layer_name]) + except WindowsCrashDump32FormatException: + return None + new_name = context.memory.free_layer_name("WindowsCrashDump32Layer") + context.config[interfaces.configuration.path_join(new_name, "base_layer")] = layer_name + return WindowsCrashDump32Layer(context, new_name, new_name) diff --git a/volatility/framework/symbols/windows/crash.json b/volatility/framework/symbols/windows/crash.json new file mode 100644 index 000000000..9ce818997 --- /dev/null +++ b/volatility/framework/symbols/windows/crash.json @@ -0,0 +1,174 @@ +{ + "symbols": { + }, + "user_types": { + "_DMP_HEADER": { + "fields": { + "Signature": { + "offset": 0, + "type": { + "count": 4, + "kind": "array", + "subtype": { + "kind": "base", + "name": "unsigned char" + } + } + }, + "ValidDump": { + "offset": 0, + "type": { + "count": 4, + "kind": "array", + "subtype": { + "kind": "base", + "name": "unsigned char" + } + } + }, + "MajorVersion": { + "offset": 8, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "MinorVersion": { + "offset": 12, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "DirectoryTableBase": { + "offset": 16, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "PhysicalMemoryBlockBuffer": { + "offset": 100, + "type": { + "kind": "struct", + "name": "_PHYSICAL_MEMORY_DESCRIPTOR" + } + }, + "DumpType": { + "offset": 3976, + "type": { + "kind": "base", + "name": "unsigned long" + } + } + }, + "kind": "struct", + "size": 4096 + }, + "_PHYSICAL_MEMORY_DESCRIPTOR": { + "fields": { + "NumberOfPages": { + "offset": 4, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "NumberOfRuns": { + "offset": 0, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "Run": { + "offset": 8, + "type": { + "count": 1, + "kind": "array", + "subtype": { + "kind": "struct", + "name": "_PHYSICAL_MEMORY_RUN" + } + } + } + }, + "kind": "struct", + "size": 16 + }, + "_PHYSICAL_MEMORY_RUN": { + "fields": { + "BasePage": { + "offset": 0, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "PageCount": { + "offset": 4, + "type": { + "kind": "base", + "name": "unsigned long" + } + } + }, + "kind": "struct", + "size": 8 + } + }, + "enums": { + }, + "base_types": { + "unsigned char": { + "endian": "little", + "kind": "char", + "signed": false, + "size": 1 + }, + "unsigned short": { + "endian": "little", + "kind": "int", + "signed": false, + "size": 2 + }, + "long": { + "endian": "little", + "kind": "int", + "signed": true, + "size": 4 + }, + "char": { + "endian": "little", + "kind": "char", + "signed": true, + "size": 1 + }, + "unsigned long": { + "endian": "little", + "kind": "int", + "signed": false, + "size": 4 + }, + "long long": { + "endian": "little", + "kind": "int", + "signed": true, + "size": 8 + }, + "unsigned long long": { + "endian": "little", + "kind": "int", + "signed": false, + "size": 8 + } + }, + "metadata": { + "producer": { + "version": "0.0.1", + "name": "ikelos-by-hand", + "datetime": "2017-09-04T22:45:22" + }, + "format": "4.0.0" + } +}