mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-22 01:24:51 +02:00
linux: module symbols: Fixes and improve code.
- Fixed an issue causing the generation of an invalid, extra symbol. - Reuse ELF sym API instead of reimplemented it - Updated the function to return the symbol index, enabling the use of additional module tables. - Ensured the ELF symbol object has `cached_strtab` set, allowing retrieval of critical symbol information like names. - Added typing hints
This commit is contained in:
@@ -352,3 +352,6 @@ NSEC_PER_SEC = 1e9
|
||||
MODULE_MAXIMUM_CORE_SIZE = 20000000
|
||||
MODULE_MAXIMUM_CORE_TEXT_SIZE = 20000000
|
||||
MODULE_MINIMUM_SIZE = 4096
|
||||
|
||||
# Kallsyms
|
||||
KSYM_NAME_LEN = 512
|
||||
|
||||
@@ -213,30 +213,37 @@ class module(generic.GenericIntelProcess):
|
||||
)
|
||||
return elf_table_name
|
||||
|
||||
def get_symbols(self):
|
||||
def get_symbols(
|
||||
self,
|
||||
) -> Iterable[Tuple[int, interfaces.objects.ObjectInterface]]:
|
||||
"""Get symbols of the module
|
||||
|
||||
Yields:
|
||||
A symbol object
|
||||
A tuple containing the ELF symbol index and the corresponding ELF symbol object
|
||||
"""
|
||||
|
||||
if not hasattr(self, "_elf_table_name"):
|
||||
self._elf_table_name = self.get_elf_table_name()
|
||||
if symbols.symbol_table_is_64bit(self._context, self.get_symbol_table_name()):
|
||||
prefix = "Elf64_"
|
||||
else:
|
||||
prefix = "Elf32_"
|
||||
syms = self._context.object(
|
||||
self.get_symbol_table_name() + constants.BANG + "array",
|
||||
if not self.section_strtab or self.num_symtab < 1:
|
||||
return None
|
||||
|
||||
elf_table_name = self.get_elf_table_name()
|
||||
symbol_table_name = self.get_symbol_table_name()
|
||||
|
||||
is_64bit = symbols.symbol_table_is_64bit(self._context, symbol_table_name)
|
||||
sym_name = "Elf64_Sym" if is_64bit else "Elf32_Sym"
|
||||
sym_type = self._context.symbol_space.get_type(
|
||||
elf_table_name + constants.BANG + sym_name
|
||||
)
|
||||
elf_syms = self._context.object(
|
||||
symbol_table_name + constants.BANG + "array",
|
||||
layer_name=self.vol.layer_name,
|
||||
offset=self.section_symtab,
|
||||
subtype=self._context.symbol_space.get_type(
|
||||
self._elf_table_name + constants.BANG + prefix + "Sym"
|
||||
),
|
||||
count=self.num_symtab + 1,
|
||||
subtype=sym_type,
|
||||
count=self.num_symtab,
|
||||
)
|
||||
if self.section_strtab:
|
||||
yield from syms
|
||||
for elf_sym_num, elf_sym_obj in enumerate(elf_syms):
|
||||
# Prepare the symbol object for methods like get_name()
|
||||
elf_sym_obj.cached_strtab = self.section_strtab
|
||||
yield elf_sym_num, elf_sym_obj
|
||||
|
||||
def get_symbols_names_and_addresses(self) -> Iterable[Tuple[str, int]]:
|
||||
"""Get names and addresses for each symbol of the module
|
||||
@@ -244,34 +251,25 @@ class module(generic.GenericIntelProcess):
|
||||
Yields:
|
||||
A tuple for each symbol containing the symbol name and its corresponding value
|
||||
"""
|
||||
|
||||
for sym in self.get_symbols():
|
||||
sym_arr = self._context.object(
|
||||
self.get_symbol_table_name() + constants.BANG + "array",
|
||||
layer_name=self.vol.native_layer_name,
|
||||
offset=self.section_strtab + sym.st_name,
|
||||
)
|
||||
try:
|
||||
sym_name = utility.array_to_string(
|
||||
sym_arr, 512
|
||||
) # 512 is the value of KSYM_NAME_LEN kernel constant
|
||||
except exceptions.InvalidAddressException:
|
||||
layer = self._context.layers[self.vol.layer_name]
|
||||
for _sym_num, sym in self.get_symbols():
|
||||
sym_name = sym.get_name()
|
||||
if not sym_name:
|
||||
continue
|
||||
if sym_name != "":
|
||||
# Normalize sym.st_value offset, which is an address pointing to the symbol value
|
||||
mask = self._context.layers[self.vol.layer_name].address_mask
|
||||
sym_address = sym.st_value & mask
|
||||
yield (sym_name, sym_address)
|
||||
|
||||
def get_symbol(self, wanted_sym_name):
|
||||
"""Get symbol value for a given symbol name"""
|
||||
# Normalize sym.st_value offset, which is an address pointing to the symbol value
|
||||
sym_address = sym.st_value & layer.address_mask
|
||||
yield (sym_name, sym_address)
|
||||
|
||||
def get_symbol(self, wanted_sym_name) -> Optional[int]:
|
||||
"""Get symbol address for a given symbol name"""
|
||||
for sym_name, sym_address in self.get_symbols_names_and_addresses():
|
||||
if wanted_sym_name == sym_name:
|
||||
return sym_address
|
||||
|
||||
return None
|
||||
|
||||
def get_symbol_by_address(self, wanted_sym_address):
|
||||
def get_symbol_by_address(self, wanted_sym_address) -> Optional[str]:
|
||||
"""Get symbol name for a given symbol address"""
|
||||
for sym_name, sym_address in self.get_symbols_names_and_addresses():
|
||||
if wanted_sym_address == sym_address:
|
||||
@@ -285,6 +283,7 @@ class module(generic.GenericIntelProcess):
|
||||
return self.kallsyms.symtab
|
||||
elif self.has_member("symtab"):
|
||||
return self.symtab
|
||||
|
||||
raise AttributeError("Unable to get symtab")
|
||||
|
||||
@property
|
||||
@@ -293,6 +292,7 @@ class module(generic.GenericIntelProcess):
|
||||
return int(self.kallsyms.num_symtab)
|
||||
elif self.has_member("num_symtab"):
|
||||
return int(self.member("num_symtab"))
|
||||
|
||||
raise AttributeError("Unable to determine number of symbols")
|
||||
|
||||
@property
|
||||
@@ -303,6 +303,7 @@ class module(generic.GenericIntelProcess):
|
||||
# Older kernels
|
||||
elif self.has_member("strtab"):
|
||||
return self.strtab
|
||||
|
||||
raise AttributeError("Unable to get strtab")
|
||||
|
||||
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
|
||||
from typing import Dict, Tuple
|
||||
from typing import Dict, Tuple, Optional
|
||||
import logging
|
||||
|
||||
from volatility3.framework import constants
|
||||
from volatility3.framework.constants.linux import (
|
||||
ELF_IDENT,
|
||||
ELF_CLASS,
|
||||
KSYM_NAME_LEN,
|
||||
)
|
||||
from volatility3.framework import objects, interfaces, exceptions
|
||||
|
||||
@@ -328,22 +329,29 @@ class elf_sym(objects.StructType):
|
||||
def cached_strtab(self, cached_strtab):
|
||||
self._cached_strtab = cached_strtab
|
||||
|
||||
def get_name(self):
|
||||
def get_name(self, max_size=KSYM_NAME_LEN) -> Optional[str]:
|
||||
"""Returns the symbol name
|
||||
|
||||
Args:
|
||||
max_size: Maximum length for a symbol name string. Defaults to KSYM_NAME_LEN (512 bytes).
|
||||
|
||||
Returns:
|
||||
The symbol name
|
||||
"""
|
||||
|
||||
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.
|
||||
layer = self._context.layers[self.vol.layer_name]
|
||||
name_bytes = layer.read(addr, max_size, pad=True)
|
||||
if not name_bytes:
|
||||
return None
|
||||
|
||||
idx = name_bytes.find(b"\x00")
|
||||
if idx != -1:
|
||||
name_bytes = name_bytes[:idx]
|
||||
|
||||
return name_bytes.decode("utf-8", errors="ignore")
|
||||
|
||||
|
||||
class elf_phdr(objects.StructType):
|
||||
"""An elf program header"""
|
||||
|
||||
Reference in New Issue
Block a user