diff --git a/volatility/framework/symbols/linux/elf.json b/volatility/framework/symbols/linux/elf.json index 26015a861..76cd8a2ec 100644 --- a/volatility/framework/symbols/linux/elf.json +++ b/volatility/framework/symbols/linux/elf.json @@ -2,6 +2,23 @@ "symbols": { }, "user_types": { + "Elf": { + "fields": { + "e_ident": { + "offset": 0, + "type": { + "count": 16, + "kind": "array", + "subtype": { + "kind": "base", + "name": "unsigned char" + } + } + } + }, + "kind": "struct", + "size": 16 + }, "Elf64_Ehdr": { "fields": { "e_ident": { @@ -18,8 +35,8 @@ "e_type": { "offset": 16, "type": { - "kind": "base", - "name": "unsigned short" + "kind": "enum", + "name": "EtypeEnum" } }, "e_machine": { @@ -247,9 +264,635 @@ }, "kind": "struct", "size": 56 + }, + "Elf64_Dyn": { + "fields": { + "d_tag": { + "offset": 0, + "type": { + "kind": "base", + "name": "long long" + } + }, + "d_ptr": { + "offset": 8, + "type": { + "kind": "base", + "name": "unsigned long long" + } + } + }, + "kind": "struct", + "size": 16 + }, + "Elf64_Note": { + "fields": { + "n_namesz": { + "offset": 0, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "n_descsz": { + "offset": 4, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "n_type": { + "offset": 8, + "type": { + "kind": "base", + "name": "unsigned long" + } + } + }, + "kind": "struct", + "size": 12 + }, + "Elf64_Sym": { + "fields": { + "st_name": { + "offset": 0, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "st_info": { + "offset": 4, + "type": { + "kind": "base", + "name": "unsigned char" + } + }, + "st_other": { + "offset": 5, + "type": { + "kind": "base", + "name": "unsigned char" + } + }, + "st_shndx": { + "offset": 6, + "type": { + "kind": "base", + "name": "unsigned short" + } + }, + "st_value": { + "offset": 8, + "type": { + "kind": "base", + "name": "unsigned long long" + } + }, + "st_size": { + "offset": 16, + "type": { + "kind": "base", + "name": "unsigned long long" + } + } + }, + "kind": "struct", + "size": 24 + }, + "Elf64_LinkMap": { + "fields": { + "l_addr": { + "offset": 0, + "type": { + "kind": "base", + "name": "unsigned long long" + } + }, + "l_name": { + "offset": 8, + "type": { + "kind": "base", + "name": "unsigned long long" + } + }, + "l_ld": { + "offset": 16, + "type": { + "kind": "base", + "name": "unsigned long long" + } + }, + "l_next": { + "offset": 24, + "type": { + "kind": "base", + "name": "unsigned long long" + } + }, + "l_prev": { + "offset": 32, + "type": { + "kind": "base", + "name": "unsigned long long" + } + } + }, + "kind": "struct", + "size": 40 + }, + "Elf64_Rel": { + "fields": { + "r_offset": { + "offset": 0, + "type": { + "kind": "base", + "name": "unsigned long long" + } + }, + "r_info": { + "offset": 8, + "type": { + "kind": "base", + "name": "unsigned long long" + } + } + }, + "kind": "struct", + "size": 16 + }, + "Elf64_Rela": { + "fields": { + "r_offset": { + "offset": 0, + "type": { + "kind": "base", + "name": "unsigned long long" + } + }, + "r_info": { + "offset": 8, + "type": { + "kind": "base", + "name": "unsigned long long" + } + }, + "r_addend": { + "offset": 16, + "type": { + "kind": "base", + "name": "long long" + } + } + }, + "kind": "struct", + "size": 24 + }, + "Elf32_Ehdr": { + "fields": { + "e_ident": { + "offset": 0, + "type": { + "count": 16, + "kind": "array", + "subtype": { + "kind": "base", + "name": "unsigned char" + } + } + }, + "e_type": { + "offset": 16, + "type": { + "kind": "enum", + "name": "EtypeEnum" + } + }, + "e_machine": { + "offset": 18, + "type": { + "kind": "base", + "name": "unsigned short" + } + }, + "e_version": { + "offset": 20, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "e_entry": { + "offset": 24, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "e_phoff": { + "offset": 28, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "e_shoff": { + "offset": 32, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "e_flags": { + "offset": 36, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "e_ehsize": { + "offset": 40, + "type": { + "kind": "base", + "name": "unsigned short" + } + }, + "e_phentsize": { + "offset": 42, + "type": { + "kind": "base", + "name": "unsigned short" + } + }, + "e_phnum": { + "offset": 44, + "type": { + "kind": "base", + "name": "unsigned short" + } + }, + "e_shentsize": { + "offset": 46, + "type": { + "kind": "base", + "name": "unsigned short" + } + }, + "e_shnum": { + "offset": 48, + "type": { + "kind": "base", + "name": "unsigned short" + } + }, + "e_shstrndx": { + "offset": 50, + "type": { + "kind": "base", + "name": "unsigned short" + } + } + }, + "kind": "struct", + "size": 52 + }, + "Elf32_Shdr": { + "fields": { + "sh_name": { + "offset": 0, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "sh_type": { + "offset": 4, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "sh_flags": { + "offset": 8, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "sh_addr": { + "offset": 12, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "sh_offset": { + "offset": 16, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "sh_size": { + "offset": 20, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "sh_link": { + "offset": 24, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "sh_info": { + "offset": 28, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "sh_addralign": { + "offset": 32, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "sh_entsize": { + "offset": 36, + "type": { + "kind": "base", + "name": "unsigned long" + } + } + }, + "kind": "struct", + "size": 40 + }, + "Elf32_Phdr": { + "fields": { + "p_type": { + "offset": 0, + "type": { + "kind": "enum", + "name": "PtypeEnum" + } + }, + "p_offset": { + "offset": 4, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "p_vaddr": { + "offset": 8, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "p_paddr": { + "offset": 12, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "p_filesz": { + "offset": 16, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "p_memsz": { + "offset": 20, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "p_flags": { + "offset": 24, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "p_align": { + "offset": 28, + "type": { + "kind": "base", + "name": "unsigned long" + } + } + }, + "kind": "struct", + "size": 32 + }, + "Elf32_Dyn": { + "fields": { + "d_tag": { + "offset": 0, + "type": { + "kind": "base", + "name": "long" + } + }, + "d_ptr": { + "offset": 4, + "type": { + "kind": "base", + "name": "unsigned long" + } + } + }, + "kind": "struct", + "size": 8 + }, + "Elf32_Note": { + "fields": { + "n_namesz": { + "offset": 0, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "n_descsz": { + "offset": 4, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "n_type": { + "offset": 8, + "type": { + "kind": "base", + "name": "unsigned long" + } + } + }, + "kind": "struct", + "size": 12 + }, + "Elf32_Sym": { + "fields": { + "st_name": { + "offset": 0, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "st_value": { + "offset": 4, + "type": { + "kind": "base", + "name": "unsigned long long" + } + }, + "st_size": { + "offset": 8, + "type": { + "kind": "base", + "name": "unsigned long long" + } + }, + "st_info": { + "offset": 12, + "type": { + "kind": "base", + "name": "unsigned char" + } + }, + "st_other": { + "offset": 13, + "type": { + "kind": "base", + "name": "unsigned char" + } + }, + "st_shndx": { + "offset": 14, + "type": { + "kind": "base", + "name": "unsigned short" + } + } + }, + "kind": "struct", + "size": 16 + }, + "Elf32_LinkMap": { + "fields": { + "l_addr": { + "offset": 0, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "l_name": { + "offset": 4, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "l_ld": { + "offset": 8, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "l_next": { + "offset": 12, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "l_prev": { + "offset": 16, + "type": { + "kind": "base", + "name": "unsigned long" + } + } + }, + "kind": "struct", + "size": 20 + }, + "Elf32_Rel": { + "fields": { + "r_offset": { + "offset": 0, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "r_info": { + "offset": 4, + "type": { + "kind": "base", + "name": "unsigned long" + } + } + }, + "kind": "struct", + "size": 8 + }, + "Elf32_Rela": { + "fields": { + "r_offset": { + "offset": 0, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "r_info": { + "offset": 4, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "r_addend": { + "offset": 8, + "type": { + "kind": "base", + "name": "long" + } + } + }, + "kind": "struct", + "size": 12 } + }, "enums": { + "EtypeEnum": { + "base": "unsigned short", + "constants": { + "ET_NONE": 0, + "ET_REL": 1, + "ET_EXEC": 2, + "ET_DYN": 3, + "ET_CORE": 4, + "ET_LOPROC": 65280, + "ET_HIPROC": 65535 + }, + "size": 2 + }, "PtypeEnum": { "base": "unsigned long", "constants": { @@ -260,6 +903,7 @@ "PT_NOTE": 4, "PT_SHLIB": 5, "PT_PHDR": 6, + "PT_TLS": 7, "PT_LOOS": 1610612736, "PT_HIOS": 1879048191, "PT_LOWPROC": 1879048192, diff --git a/volatility/framework/symbols/linux/elf.py b/volatility/framework/symbols/linux/elf.py new file mode 100644 index 000000000..015fdebab --- /dev/null +++ b/volatility/framework/symbols/linux/elf.py @@ -0,0 +1,18 @@ +# 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 volatility.framework.symbols import intermed +from volatility.framework.symbols.linux.extensions import elf + + +class ElfIntermedSymbols(intermed.IntermediateSymbolTable): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.set_type_class('Elf', elf.elf) + self.set_type_class('Elf64_Phdr', elf.elf_phdr) + self.set_type_class('Elf32_Phdr', elf.elf_phdr) + self.set_type_class('Elf32_Sym', elf.elf_sym) + self.set_type_class('Elf64_Sym', elf.elf_sym) diff --git a/volatility/framework/symbols/linux/extensions/__init__.py b/volatility/framework/symbols/linux/extensions/__init__.py index e9f736450..cc970e65b 100644 --- a/volatility/framework/symbols/linux/extensions/__init__.py +++ b/volatility/framework/symbols/linux/extensions/__init__.py @@ -7,9 +7,11 @@ import logging from typing import Generator, Iterable, Iterator, Optional, Tuple from volatility.framework import constants -from volatility.framework import exceptions, objects, interfaces +from volatility.framework import exceptions, objects, interfaces, symbols from volatility.framework.layers import linear from volatility.framework.symbols import generic, linux +from volatility.framework.objects import utility +from volatility.framework.symbols.linux.elf import ElfIntermedSymbols vollog = logging.getLogger(__name__) @@ -36,6 +38,113 @@ class module(generic.GenericIntelProcess): raise AttributeError("module -> get_core_size: Unable to determine initial size of module") + def get_module_core(self): + if self.has_member("core_layout"): + return self.core_layout.base + elif self.has_member("module_core"): + return self.module_core + + raise AttributeError("module -> get_module_core: Unable to get module core") + + def get_module_init(self): + if self.has_member("init_layout"): + return self.init_layout.base + elif self.has_member("module_init"): + return self.module_init + + raise AttributeError("module -> get_module_core: Unable to get module init") + + def get_name(self): + """ Get the name of the module as a string """ + return utility.array_to_string(self.name) + + def _get_sect_count(self, grp): + """ Try to determine the number of valid sections """ + arr = self._context.object(self.get_symbol_table().name + constants.BANG + "array", + layer_name = self.vol.layer_name, + offset = grp.attrs, + subtype = self._context.symbol_space.get_type(self.get_symbol_table().name + constants.BANG + "pointer"), + count = 25) + + idx = 0 + while arr[idx]: + idx = idx + 1 + + return idx + + def get_sections(self): + """ Get sections of the module """ + if self.sect_attrs.has_member("nsections"): + num_sects = self.sect_attrs.nsections + else: + num_sects = self._get_sect_count(self.sect_attrs.grp) + + arr = self._context.object(self.get_symbol_table().name + constants.BANG + "array", + layer_name = self.vol.layer_name, + offset = self.sect_attrs.attrs.vol.offset, + subtype = self._context.symbol_space.get_type(self.get_symbol_table().name + constants.BANG + 'module_sect_attr'), + count = num_sects) + + for attr in arr: + yield attr + + def get_symbols(self): + ret_syms = [] + + if symbols.symbol_table_is_64bit(self._context, self.get_symbol_table().name): + prefix = "Elf64_" + else: + prefix = "Elf32_" + + elf_table_name = ElfIntermedSymbols.create(self._context, "", "linux", "elf") + + syms = self._context.object(self.get_symbol_table().name + constants.BANG + "array", + layer_name = self.vol.layer_name, + offset = self.section_symtab, + subtype = self._context.symbol_space.get_type(elf_table_name + constants.BANG + prefix + "Sym"), + count = self.num_symtab + 1) + if self.section_strtab: + for sym in syms: + sym.set_cached_strtab(self.section_strtab) + yield sym + + def get_symbol(self, wanted_sym_name): + """ Get value for a given symbol name """ + for sym in self.get_symbols(): + sym_name = sym.get_name() + sym_addr = sym.st_value + if wanted_sym_name == sym_name: + return sym_addr + + @property + def section_symtab(self): + if self.has_member("kallsyms"): + return self.kallsyms.symtab + elif self.has_member("symtab"): + return self.symtab + + raise AttributeError("module -> symtab: Unable to get symtab") + + @property + def num_symtab(self): + if self.has_member("kallsyms"): + return int(self.kallsyms.num_symtab) + elif self.has_member("num_symtab"): + return int(self.num_symtab) + + raise AttributeError("module -> num_symtab: Unable to determine number of symbols") + + @property + def section_strtab(self): + #Newer kernels + if self.has_member("kallsyms"): + return self.kallsyms.strtab + #Older kernels + elif self.has_member("strtab"): + strtab = self.strtab + + raise AttributeError("module -> strtab: Unable to get strtab") + class task_struct(generic.GenericIntelProcess): @@ -387,15 +496,3 @@ class vfsmount(objects.StructType): def get_mnt_root(self): return self.mnt_root - - -class kobject(objects.StructType): - - def reference_count(self): - refcnt = self.kref.refcount - if self.has_member("counter"): - ret = refcnt.counter - else: - ret = refcnt.refs.counter - - return ret diff --git a/volatility/framework/symbols/linux/extensions/elf.py b/volatility/framework/symbols/linux/extensions/elf.py new file mode 100644 index 000000000..f21e832a9 --- /dev/null +++ b/volatility/framework/symbols/linux/extensions/elf.py @@ -0,0 +1,243 @@ +# 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 volatility.framework import exceptions, constants +from volatility.framework import objects, interfaces +from volatility.framework.objects import utility +from volatility.framework.renderers import conversion +from typing import Any, Dict, List, Optional, Tuple, Union, Type + + +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: + self.__type_prefix = None + + # 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 + + 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 get_program_headers(self): + program_headers = self._context.object(self.get_symbol_table().name + constants.BANG + "array", + layer_name = self.vol.layer_name, + offset = self.__offset + self.e_phoff, + subtype = self._context.symbol_space.get_type(self.get_symbol_table().name + constants.BANG + self.__type_prefix + "Phdr"), + count = self.e_phnum) + + for prog_header in program_headers: + prog_header.set_parent_e_type(self.e_type) + prog_header.set_parent_offset(self.__offset) + prog_header.set_type_prefix(self.__type_prefix) + yield prog_header + + def get_section_headers(self): + section_headers = self._context.object(self.get_symbol_table().name + constants.BANG + "array", + layer_name = self.vol.layer_name, + offset = self.__offset + self.e_shoff, + subtype = + self._context.symbol_space.get_type(self.get_symbol_table().name + constants.BANG + self.__type_prefix + "Shdr"), + count = self.e_shnum) + return section_headers + + 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 == None or dt_symtab == None or dt_strent == 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 = int((int(dt_strtab) - int(dt_symtab)) / dt_strent) + else: + self.cached_numsyms = 1024 + + def get_symbols(self): + if self.cached_symtab == None: + self._find_symbols() + + if self.cached_symtab == 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.set_cached_strtab(self.cached_strtab) + yield sym + + +class elf_sym(objects.StructType): + """ An elf symbol entry""" + + def set_cached_strtab(self, cached_strtab): + self.cached_strtab = cached_strtab + + 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] + else: + return None + + return name_bytes.decode('utf-8', errors='ignore') + + +class elf_phdr(objects.StructType): + """ An elf program header """ + + 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) + + self.__parent_e_type = None + self.__parent_offset = None + self.__type_prefix = None + + def set_parent_e_type(self, e_type): + self.__parent_e_type = e_type + + def set_parent_offset(self, offset): + self.__parent_offset = offset + + def set_type_prefix(self, prefix): + self.__type_prefix = prefix + + def get_vaddr(self): + offset = self.__getattr__("p_vaddr") + + if self.__parent_e_type == 3: # ET_DYN + offset = self.__parent_offset + offset + + return offset + + 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