mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-08-21 22:12:23 +02:00
Refactored the location of the progress_callback so that the UI can specify it and ensure it is used by the automagics process as well as the plugins themselves. The progress_callback function has also had an optional description parameter added, so that it can differentiated in case two scans happen simultaneously.
86 lines
2.9 KiB
Python
86 lines
2.9 KiB
Python
"""
|
|
Created on 6 Apr 2016
|
|
|
|
@author: npetroni@volexity.com
|
|
"""
|
|
|
|
import struct
|
|
|
|
from volatility.framework import exceptions, interfaces
|
|
from volatility.framework.layers import segmented
|
|
|
|
|
|
class LimeFormatException(exceptions.LayerException):
|
|
"""Thrown when an error occurs with the underlying Lime file format"""
|
|
|
|
|
|
class LimeLayer(segmented.SegmentedLayer):
|
|
"""A Lime format TranslationLayer. Lime is generally used to store
|
|
physical memory images where there are large holes in the physical
|
|
address space"""
|
|
|
|
provides = {"type": "physical"}
|
|
priority = 21
|
|
|
|
MAGIC = 0x4c694d45
|
|
VERSION = 1
|
|
|
|
# Magic[4], Version[4], Start[8], End[8], Reserved[8]
|
|
# XXX move this to a custom SymbolSpace?
|
|
_header_struct = struct.Struct('<IIQQQ')
|
|
|
|
def __init__(self, context, config_path, name):
|
|
super().__init__(context, config_path, name)
|
|
|
|
# We must run this on creation in order to get the right min/maxaddr in case scanning is our first action
|
|
self._load_segments()
|
|
|
|
def _load_segments(self):
|
|
base_layer = self._context.memory[self._base_layer]
|
|
base_maxaddr = base_layer.maximum_address
|
|
maxaddr = 0
|
|
offset = 0
|
|
header_size = self._header_struct.size
|
|
segments = []
|
|
|
|
while offset < base_maxaddr:
|
|
start, end = self._check_header(base_layer, offset)
|
|
|
|
if start < maxaddr or end < start:
|
|
raise LimeFormatException(
|
|
"bad start/end 0x{:x}/0x{:x} at file offset 0x{:x}".format(start, end, offset))
|
|
|
|
segment_length = end - start + 1
|
|
segments.append((start, offset + header_size, segment_length))
|
|
maxaddr = end
|
|
offset = offset + header_size + segment_length
|
|
|
|
if len(segments) == 0:
|
|
raise LimeFormatException("No LiME segments defined in {}".format(self._base_layer))
|
|
|
|
self._segments = segments
|
|
|
|
@classmethod
|
|
def _check_header(cls, base_layer, offset = 0):
|
|
header_data = base_layer.read(offset, cls._header_struct.size)
|
|
(magic, version, start, end, reserved) = cls._header_struct.unpack(header_data)
|
|
if magic != cls.MAGIC:
|
|
raise LimeFormatException("bad magic 0x{:x} at file offset 0x{:x}".format(magic, offset))
|
|
if version != cls.VERSION:
|
|
raise LimeFormatException("unexpected version {:d} at file offset 0x{:x}".format(version, offset))
|
|
return start, end
|
|
|
|
|
|
class LimeStacker(interfaces.automagic.StackerLayerInterface):
|
|
stack_order = 10
|
|
|
|
@classmethod
|
|
def stack(cls, context, layer_name, progress_callback = None):
|
|
try:
|
|
LimeLayer._check_header(context.memory[layer_name])
|
|
except LimeFormatException:
|
|
return
|
|
new_name = context.memory.free_layer_name("LimeLayer")
|
|
context.config[interfaces.configuration.path_join(new_name, "base_layer")] = layer_name
|
|
return LimeLayer(context, new_name, new_name)
|