Add API for mapping kernel addresses to kernel symbols or a specific kext

This commit is contained in:
Andrew Case
2020-04-08 18:17:34 +01:00
committed by ikelos
parent d5bdf9633d
commit b42dfd614a
6 changed files with 139 additions and 79 deletions
+61 -1
View File
@@ -4,7 +4,7 @@
import logging
import struct
from typing import Optional, Iterable, Set
from typing import Optional, Iterable, Set, Iterator, Any
from volatility.framework import interfaces, constants, layers, exceptions, objects
from volatility.framework import symbols
@@ -118,6 +118,66 @@ class MacintelStacker(interfaces.automagic.StackerLayerInterface):
class MacUtilities(object):
"""Class with multiple useful mac functions."""
@classmethod
def mask_mods_list(cls,
context: interfaces.context.ContextInterface,
layer_name: str,
mods: Iterator[Any]) -> Iterator[Any]:
"""
A helper function to mask the starting and end address of kernel modules
"""
mask = context.layers[layer_name].address_mask
return [(objects.utility.array_to_string(mod.name), mod.address & mask, (mod.address & mask) + mod.size) for mod in mods]
@classmethod
def generate_kernel_handler_info(cls,
context: interfaces.context.ContextInterface,
layer_name: str,
kernel, # ikelos - how to type this??
mods_list: Iterator[Any]):
try:
start_addr = kernel.object_from_symbol("vm_kernel_stext")
except exceptions.SymbolError:
start_addr = kernel.object_from_symbol("stext")
try:
end_addr = kernel.object_from_symbol("vm_kernel_etext")
except exceptions.SymbolError:
end_addr = kernel.object_from_symbol("etext")
mask = context.layers[layer_name].address_mask
start_addr = start_addr & mask
end_addr = end_addr & mask
return [("__kernel__", start_addr, end_addr)] + \
MacUtilities.mask_mods_list(context, layer_name, mods_list)
@classmethod
def lookup_module_address(cls,
context: interfaces.context.ContextInterface,
handlers: Iterator[Any],
target_address):
mod_name = "UNKNOWN"
symbol_name = "N/A"
for name, start, end in handlers:
if start <= target_address <= end:
mod_name = name
if name == "__kernel__":
symbols = list(context.symbol_space.get_symbols_by_location(target_address))
if len(symbols) > 0:
symbol_name = str(symbols[0].split(constants.BANG)[1]) if constants.BANG in symbols[0] else \
str(symbols[0])
break
return mod_name, symbol_name
@classmethod
def aslr_mask_symbol_table(cls,
context: interfaces.context.ContextInterface,
@@ -2,7 +2,7 @@
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#
import logging
from typing import List
from typing import List, Iterator, Any
from volatility.framework import exceptions, interfaces
from volatility.framework import renderers, constants, contexts
@@ -10,6 +10,7 @@ from volatility.framework.automagic import mac
from volatility.framework.configuration import requirements
from volatility.framework.interfaces import plugins
from volatility.framework.renderers import format_hints
from volatility.plugins.mac import lsmod
vollog = logging.getLogger(__name__)
@@ -23,13 +24,16 @@ class Check_syscall(plugins.PluginInterface):
requirements.TranslationLayerRequirement(name = 'primary',
description = 'Memory layer for the kernel',
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "darwin", description = "Mac kernel symbols")
requirements.SymbolTableRequirement(name = "darwin", description = "Mac kernel symbols"),
requirements.PluginRequirement(name = 'lsmod', plugin = lsmod.Lsmod, version = (1, 0, 0))
]
def _generator(self):
def _generator(self, mods: Iterator[Any]):
mac.MacUtilities.aslr_mask_symbol_table(self.context, self.config['darwin'], self.config['primary'])
kernel = contexts.Module(self._context, self.config['darwin'], self.config['primary'], 0)
handlers = mac.MacUtilities.generate_kernel_handler_info(self.context, self.config['primary'], kernel, mods)
nsysent = kernel.object_from_symbol(symbol_name = "nsysent")
table = kernel.object_from_symbol(symbol_name = "sysent")
@@ -48,16 +52,15 @@ class Check_syscall(plugins.PluginInterface):
if not call_addr or call_addr == 0:
continue
symbols = list(self.context.symbol_space.get_symbols_by_location(call_addr))
module_name, symbol_name = mac.MacUtilities.lookup_module_address(self.context, handlers, call_addr)
if len(symbols) > 0:
sym_name = str(symbols[0].split(constants.BANG)[1]) if constants.BANG in symbols[0] else \
str(symbols[0])
else:
sym_name = "UNKNOWN"
yield (0, (format_hints.Hex(table.vol.offset), "SysCall", i, format_hints.Hex(call_addr), sym_name))
yield (0, (format_hints.Hex(table.vol.offset), "SysCall", i, format_hints.Hex(call_addr), module_name, symbol_name))
def run(self):
return renderers.TreeGrid([("Table Address", format_hints.Hex), ("Table Name", str), ("Index", int),
("Handler Address", format_hints.Hex), ("Handler Symbol", str)], self._generator())
("Handler Address", format_hints.Hex), ("Handler Module", str), ("Handler Symbol", str)],
self._generator(
lsmod.Lsmod.list_modules(self.context, self.config['primary'],
self.config['darwin'])))
@@ -2,7 +2,7 @@
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#
import logging
from typing import List
from typing import List, Iterator, Any
import volatility
from volatility.framework import exceptions, interfaces
@@ -12,6 +12,7 @@ from volatility.framework.configuration import requirements
from volatility.framework.interfaces import plugins
from volatility.framework.renderers import format_hints
from volatility.framework.objects import utility
from volatility.plugins.mac import lsmod
vollog = logging.getLogger(__name__)
@@ -25,7 +26,8 @@ class Check_sysctl(plugins.PluginInterface):
requirements.TranslationLayerRequirement(name = 'primary',
description = 'Memory layer for the kernel',
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "darwin", description = "Mac kernel symbols")
requirements.SymbolTableRequirement(name = "darwin", description = "Mac kernel symbols"),
requirements.PluginRequirement(name = 'lsmod', plugin = lsmod.Lsmod, version = (1, 0, 0))
]
def _parse_global_variable_sysctls(self, kernel, name):
@@ -109,30 +111,28 @@ class Check_sysctl(plugins.PluginInterface):
except exceptions.InvalidAddressException:
break
def _generator(self):
def _generator(self, mods: Iterator[Any]):
mac.MacUtilities.aslr_mask_symbol_table(self.context, self.config['darwin'], self.config['primary'])
kernel = contexts.Module(self._context, self.config['darwin'], self.config['primary'], 0)
handlers = mac.MacUtilities.generate_kernel_handler_info(self.context, self.config['primary'], kernel, mods)
sysctl_list = kernel.object_from_symbol(symbol_name = "sysctl__children")
for sysctl, name, val in self._process_sysctl_list(kernel, sysctl_list):
check_addr = sysctl.oid_handler
try:
check_addr = sysctl.oid_handler
except exceptions.InvalidAddressException:
continue
if check_addr == 0:
sym_name = "<No Handler>"
else:
symbols = list(self.context.symbol_space.get_symbols_by_location(check_addr))
module_name, symbol_name = mac.MacUtilities.lookup_module_address(self.context, handlers, check_addr)
if len(symbols) > 0:
sym_name = str(symbols[0].split(constants.BANG)[1]) if constants.BANG in symbols[0] else \
str(symbols[0])
else:
sym_name = "UNKNOWN"
yield (0, (name, sysctl.oid_number, sysctl.get_perms(), format_hints.Hex(check_addr), val, sym_name))
yield (0, (name, sysctl.oid_number, sysctl.get_perms(), format_hints.Hex(check_addr), val, module_name, symbol_name))
def run(self):
return renderers.TreeGrid([("Name", str), ("Number", int), ("Perms", str),
("Handler Address", format_hints.Hex), ("Value", str), ("Handler Symbol", str)],
self._generator())
return renderers.TreeGrid([("Name", str), ("Number", int), ("Perms", str), ("Handler Address", format_hints.Hex),
("Value", str), ("Handler Module", str), ("Handler Symbol", str)],
self._generator(
lsmod.Lsmod.list_modules(self.context, self.config['primary'],
self.config['darwin'])))
@@ -3,7 +3,7 @@
#
import logging
from typing import List
from typing import List, Iterator, Any
from volatility.framework import exceptions, interfaces
from volatility.framework import renderers, constants, contexts
@@ -11,6 +11,7 @@ from volatility.framework.automagic import mac
from volatility.framework.configuration import requirements
from volatility.framework.interfaces import plugins
from volatility.framework.renderers import format_hints
from volatility.plugins.mac import lsmod
vollog = logging.getLogger(__name__)
@@ -24,35 +25,40 @@ class Check_trap_table(plugins.PluginInterface):
requirements.TranslationLayerRequirement(name = 'primary',
description = 'Memory layer for the kernel',
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "darwin", description = "Mac kernel symbols")
requirements.SymbolTableRequirement(name = "darwin", description = "Mac kernel symbols"),
requirements.PluginRequirement(name = 'lsmod', plugin = lsmod.Lsmod, version = (1, 0, 0))
]
def _generator(self):
def _generator(self, mods: Iterator[Any]):
mac.MacUtilities.aslr_mask_symbol_table(self.context, self.config['darwin'], self.config['primary'])
kernel = contexts.Module(self._context, self.config['darwin'], self.config['primary'], 0)
handlers = mac.MacUtilities.generate_kernel_handler_info(self.context, self.config['primary'], kernel, mods)
table = kernel.object_from_symbol(symbol_name = "mach_trap_table")
for i, ent in enumerate(table):
try:
call_addr = ent.mach_trap_function.dereference().vol.offset
except exceptions.InvalidPagedAddressException:
except exceptions.InvalidAddressException:
continue
if not call_addr or call_addr == 0:
continue
symbols = list(self.context.symbol_space.get_symbols_by_location(call_addr))
module_name, symbol_name = mac.MacUtilities.lookup_module_address(self.context, handlers, call_addr)
if len(symbols) > 0:
sym_name = str(symbols[0].split(constants.BANG)[1]) if constants.BANG in symbols[0] else \
str(symbols[0])
else:
sym_name = "UNKNOWN"
yield (0, (format_hints.Hex(table.vol.offset), "TrapTable", i, format_hints.Hex(call_addr), sym_name))
yield (0, (format_hints.Hex(table.vol.offset), "TrapTable", i, format_hints.Hex(call_addr), module_name, symbol_name))
def run(self):
return renderers.TreeGrid([("Table Address", format_hints.Hex), ("Table Name", str), ("Index", int),
("Handler Address", format_hints.Hex), ("Handler Symbol", str)], self._generator())
("Handler Address", format_hints.Hex), ("Handler Module", str), ("Handler Symbol", str)],
self._generator(
lsmod.Lsmod.list_modules(self.context, self.config['primary'],
self.config['darwin'])))
+19 -17
View File
@@ -2,7 +2,7 @@
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
#
import logging
from typing import List
from typing import List, Iterator, Any
import volatility
from volatility.framework import exceptions, interfaces
@@ -12,6 +12,7 @@ from volatility.framework.configuration import requirements
from volatility.framework.interfaces import plugins
from volatility.framework.renderers import format_hints
from volatility.framework.objects import utility
from volatility.plugins.mac import lsmod
vollog = logging.getLogger(__name__)
@@ -25,13 +26,16 @@ class Timers(plugins.PluginInterface):
requirements.TranslationLayerRequirement(name = 'primary',
description = 'Memory layer for the kernel',
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "darwin", description = "Mac kernel symbols")
requirements.SymbolTableRequirement(name = "darwin", description = "Mac kernel symbols"),
requirements.PluginRequirement(name = 'lsmod', plugin = lsmod.Lsmod, version = (1, 0, 0))
]
def _generator(self):
def _generator(self, mods: Iterator[Any]):
mac.MacUtilities.aslr_mask_symbol_table(self.context, self.config['darwin'], self.config['primary'])
kernel = contexts.Module(self._context, self.config['darwin'], self.config['primary'], 0)
kernel = contexts.Module(self.context, self.config['darwin'], self.config['primary'], 0)
handlers = mac.MacUtilities.generate_kernel_handler_info(self.context, self.config['primary'], kernel, mods)
real_ncpus = kernel.object_from_symbol(symbol_name = "real_ncpus")
@@ -45,7 +49,7 @@ class Timers(plugins.PluginInterface):
offset = cpu_data_ptrs_addr,
subtype = kernel.get_type('cpu_data'),
count = real_ncpus)
for cpu_data_ptr in cpu_data_ptrs:
try:
queue = cpu_data_ptr.rtclock_timer.queue.head
@@ -54,26 +58,24 @@ class Timers(plugins.PluginInterface):
for timer in queue.walk_list(queue, "q_link", "call_entry"):
try:
handler = timer.func
handler = timer.func.dereference().vol.offset
except exceptions.InvalidAddressException:
continue
symbols = list(self.context.symbol_space.get_symbols_by_location(handler))
if len(symbols) > 0:
sym_name = str(symbols[0].split(constants.BANG)[1]) if constants.BANG in symbols[0] else \
str(symbols[0])
else:
sym_name = "UNKNOWN"
if hasattr(timer, "entry_time"):
if timer.has_member("entry_time"):
entry_time = timer.entry_time
else:
entry_time = -1
yield (0, (format_hints.Hex(handler), format_hints.Hex(timer.param0), format_hints.Hex(timer.param1), timer.deadline, entry_time, "kernel", sym_name))
module_name, symbol_name = mac.MacUtilities.lookup_module_address(self.context, handlers, handler)
yield (0, (format_hints.Hex(handler), format_hints.Hex(timer.param0), format_hints.Hex(timer.param1), \
timer.deadline, entry_time, module_name, symbol_name))
def run(self):
return renderers.TreeGrid([("Function", format_hints.Hex), ("Param 0", format_hints.Hex), ("Param 1", format_hints.Hex),
("Deadline", int), ("Entry Time", int), ("Module", str), ("Symbol", str)],
self._generator())
self._generator(
lsmod.Lsmod.list_modules(self.context, self.config['primary'],
self.config['darwin'])))
+7 -18
View File
@@ -34,6 +34,8 @@ class trustedbsd(plugins.PluginInterface):
mac.MacUtilities.aslr_mask_symbol_table(self.context, self.config['darwin'], self.config['primary'])
kernel = contexts.Module(self._context, self.config['darwin'], self.config['primary'], 0)
handlers = mac.MacUtilities.generate_kernel_handler_info(self.context, self.config['primary'], kernel, mods)
policy_list = kernel.object_from_symbol(symbol_name = "mac_policy_list").cast("mac_policy_list")
@@ -41,10 +43,7 @@ class trustedbsd(plugins.PluginInterface):
offset = policy_list.entries.dereference().vol.offset,
subtype = kernel.get_type('mac_policy_list_element'),
count = policy_list.staticmax + 1)
mask = self.context.layers[self.config['primary']].address_mask
mods_list = [(mod.name, mod.address & mask, (mod.address & mask) + mod.size) for mod in mods]
for i, ent in enumerate(entries):
# I don't know how this can happen, but the kernel makes this check all over the place
# the policy isn't useful without any ops so a rootkit can't abuse this
@@ -65,23 +64,13 @@ class trustedbsd(plugins.PluginInterface):
if call_addr is None or call_addr == 0:
continue
found_module = None
module_name, symbol_name = mac.MacUtilities.lookup_module_address(self.context, handlers, call_addr)
for mod_name_info, mod_base, mod_end in mods_list:
if call_addr >= mod_base and call_addr <= mod_end:
found_module = mod_name_info
break
if found_module:
symbol_module = utility.array_to_string(found_module)
else:
symbol_module = "UNKNOWN"
yield (0, (check, ent_name, symbol_module, format_hints.Hex(call_addr)))
yield (0, (check, ent_name, format_hints.Hex(call_addr), module_name, symbol_name))
def run(self):
return renderers.TreeGrid([("Member", str), ("Policy Name", str), ("Handler Module", str),
("Handler Address", format_hints.Hex)],
return renderers.TreeGrid([("Member", str), ("Policy Name", str), ("Handler Address", format_hints.Hex), ("Handler Module", str),
("Handler Symbol", str)],
self._generator(
lsmod.Lsmod.list_modules(self.context, self.config['primary'],
self.config['darwin'])))