# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#
from typing import Dict, Tuple
from volatility3.framework import constants
from volatility3.framework import objects, interfaces
[docs]class elf(objects.StructType):
'''
Class used to create elf objects. It overrides the typename to `Elf32_` or `Elf64_`,
depending on the corresponding value on e_ident
'''
def __init__(self, context: interfaces.context.ContextInterface, type_name: str,
object_info: interfaces.objects.ObjectInformation, size: int,
members: Dict[str, Tuple[int, interfaces.objects.Template]]) -> None:
super().__init__(context = context,
type_name = type_name,
object_info = object_info,
size = size,
members = members)
layer_name = self.vol.layer_name
symbol_table_name = self.get_symbol_table_name()
# We read the MAGIC: (0x0 to 0x4) 0x7f 0x45 0x4c 0x46
magic = self._context.object(symbol_table_name + constants.BANG + "unsigned long",
layer_name = layer_name,
offset = object_info.offset)
# Check validity
if magic != 0x464c457f:
return None
# We need to read the EI_CLASS (0x4 offset)
ei_class = self._context.object(symbol_table_name + constants.BANG + "unsigned char",
layer_name = layer_name,
offset = object_info.offset + 0x4)
if ei_class == 1:
self._type_prefix = "Elf32_"
elif ei_class == 2:
self._type_prefix = "Elf64_"
else:
raise ValueError(f"Unsupported ei_class value {ei_class}")
# Construct the full header
self._hdr = self._context.object(symbol_table_name + constants.BANG + self._type_prefix + "Ehdr",
layer_name = layer_name,
offset = object_info.offset)
self._offset = object_info.offset
self._cached_symtab = None
self._cached_strtab = None
[docs] def is_valid(self):
'''
Determine whether it is a valid object
'''
return self._type_prefix is not None and self._hdr is not None
def __getattr__(self, name):
# Just redirect to the corresponding header
if name[0:2] == "e_" and name in dir(self._hdr):
return self._hdr.__getattr__(name)
else:
return self.__getattribute__(name)
def __dir__(self):
return self._hdr.__dir__() + [
"get_program_headers", "is_valid", "get_section_headers", "get_symbols", "__dir__"
]
def _find_symbols(self):
dt_strtab = None
dt_symtab = None
dt_strent = None
for phdr in self.get_program_headers():
try:
# Find PT_DYNAMIC segment
if str(phdr.p_type.description) != 'PT_DYNAMIC':
continue
except ValueError:
# If the p_type value is outside the ones declared in the enumeration, an
# exception is raised
return None
# This section contains pointers to the strtab, symtab, and strent sections
for dsec in phdr.dynamic_sections():
if dsec.d_tag == 5:
dt_strtab = dsec.d_ptr
elif dsec.d_tag == 6:
dt_symtab = dsec.d_ptr
elif dsec.d_tag == 11:
# Size of the symtab symbol entry
dt_strent = dsec.d_ptr
break
if dt_strtab is None or dt_symtab is None or dt_strent is None:
return None
self._cached_symtab = dt_symtab
self._cached_strtab = dt_strtab
# Calculate number of symbol entries assuming that strtab follows symtab
if dt_symtab < dt_strtab:
self._cached_numsyms = (dt_strtab - dt_symtab) // dt_strent
else:
self._cached_numsyms = 1024
[docs] def get_symbols(self):
if self._cached_symtab is None:
self._find_symbols()
if self._cached_symtab is None:
return
symtab_arr = self._context.object(
self.get_symbol_table_name() + constants.BANG + "array",
layer_name = self.vol.layer_name,
offset = self._cached_symtab,
subtype = self._context.symbol_space.get_type(self.get_symbol_table_name() + constants.BANG +
self._type_prefix + "Sym"),
count = self._cached_numsyms)
for sym in symtab_arr:
sym.cached_strtab = self._cached_strtab
yield sym
[docs]class elf_sym(objects.StructType):
""" An elf symbol entry"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._cached_strtab = None
@property
def cached_strtab(self):
return self._cached_strtab
@cached_strtab.setter
def cached_strtab(self, cached_strtab):
self._cached_strtab = cached_strtab
[docs] def get_name(self):
addr = self._cached_strtab + self.st_name
# Just get the first 255 characters, it should be enough for a symbol name
name_bytes = self._context.layers[self.vol.layer_name].read(addr, 255, pad = True)
if name_bytes:
idx = name_bytes.find(b"\x00")
if idx != -1:
name_bytes = name_bytes[:idx]
return name_bytes.decode('utf-8', errors = 'ignore')
else:
# If we cannot read the name from the address space,
# we return None.
return None
[docs]class elf_phdr(objects.StructType):
""" An elf program header """
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._parent_e_type = None
self._parent_offset = None
self._type_prefix = None
@property
def parent_e_type(self):
return self._parent_e_type
@parent_e_type.setter
def parent_e_type(self, e_type):
self._parent_e_type = e_type
@property
def parent_offset(self):
return self._parent_offset
@parent_offset.setter
def parent_offset(self, offset):
self._parent_offset = offset
@property
def type_prefix(self):
return self._type_prefix
@type_prefix.setter
def type_prefix(self, prefix):
self._type_prefix = prefix
[docs] def get_vaddr(self):
offset = self.__getattr__("p_vaddr")
if self._parent_e_type == 3: # ET_DYN
offset = self._parent_offset + offset
return offset
[docs] def dynamic_sections(self):
# sanity check
try:
if str(self.p_type.description) != 'PT_DYNAMIC':
return None
except ValueError:
# If the value is outside the ones declared in the enumeration, an
# exception is raised
return None
# the buffer of array starts at elf_base + our virtual address ( offset )
arr_start = self.get_vaddr()
symbol_table_name = self.get_symbol_table_name()
rtsize = self._context.symbol_space.get_type(symbol_table_name + \
constants.BANG + \
self._type_prefix + "Dyn").size
for i in range(256):
# use the real size
idx = i * rtsize
dyn = self._context.object(symbol_table_name + constants.BANG + self._type_prefix + "Dyn",
layer_name = self.vol.layer_name,
offset = arr_start + idx)
yield dyn
if dyn.d_tag == 0:
break
class_types = {'Elf': elf, 'Elf64_Phdr': elf_phdr, 'Elf32_Phdr': elf_phdr, 'Elf32_Sym': elf_sym, 'Elf64_Sym': elf_sym}