mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-20 08:37:39 +02:00
Layers: Add in Xen CoreDump format support
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
import logging
|
||||
import struct
|
||||
from typing import Optional
|
||||
|
||||
from volatility3.framework import constants, interfaces, exceptions
|
||||
from volatility3.framework.layers import elf
|
||||
from volatility3.framework.symbols import intermed
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class XenCoreDumpLayer(elf.Elf64Layer):
|
||||
"""A layer that supports the Xen Dump-Core format as documented at: https://xenbits.xen.org/docs/4.6-testing/misc/dump-core-format.txt"""
|
||||
|
||||
_header_struct = struct.Struct("<IBBB")
|
||||
MAGIC = 0x464C457F # "\x7fELF"
|
||||
ELF_CLASS = 2
|
||||
|
||||
def __init__(
|
||||
self, context: interfaces.context.ContextInterface, config_path: str, name: str
|
||||
) -> None:
|
||||
# Create a custom SymbolSpace
|
||||
self._elf_table_name = intermed.IntermediateSymbolTable.create(
|
||||
context, config_path, "linux", "elf"
|
||||
)
|
||||
self._xen_table_name = intermed.IntermediateSymbolTable.create(
|
||||
context, config_path, "linux", "xen"
|
||||
)
|
||||
|
||||
super().__init__(context, config_path, name)
|
||||
|
||||
def _load_segments(self) -> None:
|
||||
"""Load the segments from based on the PT_LOAD segments of the Elf64 format"""
|
||||
ehdr = self.context.object(
|
||||
self._elf_table_name + constants.BANG + "Elf64_Ehdr",
|
||||
layer_name=self._base_layer,
|
||||
offset=0,
|
||||
)
|
||||
|
||||
segments = []
|
||||
segment_headers = []
|
||||
|
||||
for sindex in range(ehdr.e_shnum):
|
||||
shdr = self.context.object(
|
||||
self._elf_table_name + constants.BANG + "Elf64_Shdr",
|
||||
layer_name=self._base_layer,
|
||||
offset=ehdr.e_shoff + (sindex * ehdr.e_shentsize),
|
||||
)
|
||||
|
||||
segment_headers.append(shdr)
|
||||
|
||||
if sindex == ehdr.e_shstrndx:
|
||||
segment_names = self.context.layers[self._base_layer].read(
|
||||
shdr.sh_offset, shdr.sh_size
|
||||
)
|
||||
segment_names = segment_names.split(b"\x00")
|
||||
|
||||
if not segment_names:
|
||||
raise elf.ElfFormatException("No segment names, not a Xen Core Dump")
|
||||
|
||||
p2m_data = None
|
||||
pfn_data = None
|
||||
|
||||
for varname, pattern, outvar in [
|
||||
("xen_p2m", b".xen_p2m", p2m_data),
|
||||
("xen_pfn", b".xen_pfn", pfn_data),
|
||||
]:
|
||||
if pattern in segment_names:
|
||||
hdr = segment_headers[segment_names.index(pattern)]
|
||||
result = self.context.object(
|
||||
self._xen_table_name + constants.BANG + varname,
|
||||
layer_name=self._base_layer,
|
||||
offset=hdr.sh_offset,
|
||||
size=hdr.sh_size,
|
||||
)
|
||||
result.entries.count = hdr.sh_size // result.entries.vol.subtype.size
|
||||
outvar = result
|
||||
|
||||
pages_hdr = segment_headers[segment_names.index(b".xen_pages")]
|
||||
page_size = 0x1000
|
||||
|
||||
if pfn_data and not p2m_data:
|
||||
for entry_index in range(len(pfn_data.entries)):
|
||||
entry = pfn_data.entries[entry_index]
|
||||
# TODO: Don't hardcode the maximum value here
|
||||
if entry and entry != 0xFFFFFFFF:
|
||||
segments.append(
|
||||
(
|
||||
entry * page_size,
|
||||
pages_hdr.sh_offset + (entry_index * page_size),
|
||||
page_size,
|
||||
page_size,
|
||||
)
|
||||
)
|
||||
elif p2m_data and not pfn_data:
|
||||
for entry_index in range(len(p2m_data.entries)):
|
||||
entry = p2m_data.entries[entry_index]
|
||||
# TODO: Don't hardcode the maximum value here
|
||||
if entry.pfn != 0xFFFFFFFF:
|
||||
segments.append(
|
||||
(
|
||||
entry.pfn * page_size,
|
||||
pages_hdr.sh_offset + (entry_index * page_size),
|
||||
page_size,
|
||||
page_size,
|
||||
)
|
||||
)
|
||||
elif p2m_data and pfn_data:
|
||||
raise elf.ElfFormatException(
|
||||
self.name, f"Both P2M and PFN in Xen Core Dump"
|
||||
)
|
||||
else:
|
||||
raise elf.ElfFormatException(
|
||||
self.name, f"Neither P2M nor PFN in Xen Core Dump"
|
||||
)
|
||||
|
||||
if len(segments) == 0:
|
||||
raise elf.ElfFormatException(
|
||||
self.name, f"No ELF segments defined in {self._base_layer}"
|
||||
)
|
||||
|
||||
self._segments = segments
|
||||
|
||||
@classmethod
|
||||
def _check_header(
|
||||
cls, base_layer: interfaces.layers.DataLayerInterface, offset: int = 0
|
||||
) -> bool:
|
||||
try:
|
||||
header_data = base_layer.read(offset, cls._header_struct.size)
|
||||
except exceptions.InvalidAddressException:
|
||||
raise elf.ElfFormatException(
|
||||
base_layer.name,
|
||||
f"Offset 0x{offset:0x} does not exist within the base layer",
|
||||
)
|
||||
(magic, elf_class, elf_data_encoding, elf_version) = cls._header_struct.unpack(
|
||||
header_data
|
||||
)
|
||||
if magic != cls.MAGIC:
|
||||
raise elf.ElfFormatException(
|
||||
base_layer.name, f"Bad magic 0x{magic:x} at file offset 0x{offset:x}"
|
||||
)
|
||||
if elf_class != cls.ELF_CLASS:
|
||||
raise elf.ElfFormatException(
|
||||
base_layer.name, f"ELF class is not 64-bit (2): {elf_class:d}"
|
||||
)
|
||||
# Virtualbox uses an ELF version of 0, which isn't to specification, but is ok to deal with
|
||||
return True
|
||||
|
||||
|
||||
class XenCoreDumpStacker(elf.Elf64Stacker):
|
||||
stack_order = 10
|
||||
|
||||
@classmethod
|
||||
def stack(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
layer_name: str,
|
||||
progress_callback: constants.ProgressCallback = None,
|
||||
) -> Optional[interfaces.layers.DataLayerInterface]:
|
||||
try:
|
||||
if not XenCoreDumpLayer._check_header(context.layers[layer_name]):
|
||||
return None
|
||||
except elf.ElfFormatException as excp:
|
||||
vollog.log(constants.LOGLEVEL_VVVV, f"Exception: {excp}")
|
||||
return None
|
||||
new_name = context.layers.free_layer_name("XenCoreDumpLayer")
|
||||
context.config[
|
||||
interfaces.configuration.path_join(new_name, "base_layer")
|
||||
] = layer_name
|
||||
|
||||
return XenCoreDumpLayer(context, new_name, new_name)
|
||||
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"symbols": {
|
||||
},
|
||||
"user_types": {
|
||||
"xen_p2m": {
|
||||
"fields":{
|
||||
"entries": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"count": 1,
|
||||
"kind": "array",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"xen_pfn":{
|
||||
"fields":{
|
||||
"entries": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"count": 1,
|
||||
"kind": "array",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 16
|
||||
},
|
||||
"xen_pfn_entry":{
|
||||
"fields":{
|
||||
"pfn":{
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
}
|
||||
},
|
||||
"gmfn":{
|
||||
"offset": 8,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 16
|
||||
|
||||
}
|
||||
},
|
||||
"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": "2023-01-09T00:51:00"
|
||||
},
|
||||
"format": "6.1.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user