Ensure that new symbol tables are only created when needed. Avoid name collisions leading to inconsistent behaviour. Make API for symbol table acquisition sane.

This commit is contained in:
Andrew Case
2025-03-10 03:27:56 +00:00
parent b99918c423
commit 7289f7dc70
6 changed files with 45 additions and 41 deletions
@@ -32,7 +32,7 @@ class ModScan(modules.Modules):
architectures=["Intel32", "Intel64"],
),
requirements.VersionRequirement(
name="poolscanner", component=poolscanner.PoolScanner, version=(2, 0, 0)
name="poolscanner", component=poolscanner.PoolScanner, version=(3, 0, 0)
),
requirements.VersionRequirement(
name="modules", component=modules.Modules, version=(3, 0, 0)
@@ -34,7 +34,7 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
architectures=["Intel32", "Intel64"],
),
requirements.VersionRequirement(
name="poolscanner", component=poolscanner.PoolScanner, version=(2, 0, 0)
name="poolscanner", component=poolscanner.PoolScanner, version=(3, 0, 0)
),
requirements.VersionRequirement(
name="info", component=info.Info, version=(2, 0, 0)
@@ -129,7 +129,7 @@ class PoolScanner(plugins.PluginInterface):
"""A generic pool scanner plugin."""
_required_framework_version = (2, 0, 0)
_version = (2, 0, 0)
_version = (3, 0, 0)
@classmethod
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
@@ -423,6 +423,7 @@ class PoolScanner(plugins.PluginInterface):
# scan in the main kernel layer for the object(s)
for constraint, header in cls.pool_scan(
context,
kernel_module_name,
scan_layer,
object_symbol_table_name,
constraints,
@@ -501,6 +502,7 @@ class PoolScanner(plugins.PluginInterface):
def pool_scan(
cls,
context: interfaces.context.ContextInterface,
kernel_module_name: str,
layer_name: str,
symbol_table: str,
pool_constraints: List[PoolConstraint],
@@ -534,8 +536,16 @@ class PoolScanner(plugins.PluginInterface):
)
constraint_lookup[constraint.tag] = constraint
pool_header_table_name = cls.get_pool_header_table(context, symbol_table)
module = context.module(pool_header_table_name, layer_name, offset=0)
kernel = context.modules[kernel_module_name]
if kernel.has_type("_POOL_HEADER"):
pool_header_table_name = kernel.symbol_table_name
else:
pool_header_table_name = cls.get_pool_header_table(context, symbol_table)
module = context.module(
pool_header_table_name, layer_name, offset=kernel.offset
)
# Run the scan locating the offsets of a particular tag
layer = context.layers[layer_name]
@@ -553,43 +563,37 @@ class PoolScanner(plugins.PluginInterface):
context: The context that the symbol tables does (or will) reside in
symbol_table: The expected symbol_table to contain the _POOL_HEADER type
"""
# Setup the pool header and offset differential
try:
context.symbol_space.get_type(
symbol_table + constants.BANG + "_POOL_HEADER"
)
table_name = symbol_table
except exceptions.SymbolError:
# We have to manually load a symbol table
# We have to manually load a symbol table
if symbols.symbol_table_is_64bit(
context=context, symbol_table_name=symbol_table
):
is_win_7 = versions.is_windows_7(context, symbol_table)
if is_win_7:
pool_header_json_filename = "poolheader-x64-win7"
else:
pool_header_json_filename = "poolheader-x64"
if symbols.symbol_table_is_64bit(
context=context, symbol_table_name=symbol_table
):
is_win_7 = versions.is_windows_7(context, symbol_table)
if is_win_7:
pool_header_json_filename = "poolheader-x64-win7"
else:
pool_header_json_filename = "poolheader-x86"
pool_header_json_filename = "poolheader-x64"
else:
pool_header_json_filename = "poolheader-x86"
# set the class_type to match the normal WindowsKernelIntermedSymbols
is_vista_or_later = versions.is_vista_or_later(context, symbol_table)
if is_vista_or_later:
class_type = extensions.pool.POOL_HEADER_VISTA
else:
class_type = extensions.pool.POOL_HEADER
# set the class_type to match the normal WindowsKernelIntermedSymbols
is_vista_or_later = versions.is_vista_or_later(context, symbol_table)
if is_vista_or_later:
class_type = extensions.pool.POOL_HEADER_VISTA
else:
class_type = extensions.pool.POOL_HEADER
table_name = intermed.IntermediateSymbolTable.create(
context=context,
config_path=configuration.path_join(
context.symbol_space[symbol_table].config_path, "poolheader"
),
sub_path="windows",
filename=pool_header_json_filename,
table_mapping={"nt_symbols": symbol_table},
class_types={"_POOL_HEADER": class_type},
)
table_name = intermed.IntermediateSymbolTable.create(
context=context,
config_path=configuration.path_join(
context.symbol_space[symbol_table].config_path, "poolheader"
),
sub_path="windows",
filename=pool_header_json_filename,
table_mapping={"nt_symbols": symbol_table},
class_types={"_POOL_HEADER": class_type},
)
return table_name
def run(self) -> renderers.TreeGrid:
@@ -40,7 +40,7 @@ class PsScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
name="info", component=info.Info, version=(2, 0, 0)
),
requirements.VersionRequirement(
name="poolscanner", component=poolscanner.PoolScanner, version=(2, 0, 0)
name="poolscanner", component=poolscanner.PoolScanner, version=(3, 0, 0)
),
requirements.ListRequirement(
name="pid",
@@ -28,7 +28,7 @@ class SymlinkScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterfa
architectures=["Intel32", "Intel64"],
),
requirements.VersionRequirement(
name="poolscanner", component=poolscanner.PoolScanner, version=(2, 0, 0)
name="poolscanner", component=poolscanner.PoolScanner, version=(3, 0, 0)
),
]
@@ -47,7 +47,7 @@ class WindowStations(interfaces.plugins.PluginInterface):
architectures=["Intel32", "Intel64"],
),
requirements.VersionRequirement(
name="poolscanner", component=poolscanner.PoolScanner, version=(2, 0, 0)
name="poolscanner", component=poolscanner.PoolScanner, version=(3, 0, 0)
),
requirements.VersionRequirement(
name="modules", component=modules.Modules, version=(3, 0, 0)