Scanners: Add quick parameter to various pool scanners.

This commit is contained in:
Mike Auty
2019-12-05 00:20:53 +00:00
parent 8cda5782f1
commit f4522c07d9
8 changed files with 115 additions and 23 deletions
@@ -23,13 +23,18 @@ class DriverScan(interfaces.plugins.PluginInterface):
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
requirements.PluginRequirement(name = 'poolscanner', plugin = poolscanner.PoolScanner, version = (1, 0, 0)),
requirements.BooleanRequirement(name = 'quick',
description = "Scan just allocated memory",
default = False,
optional = True),
]
@classmethod
def scan_drivers(cls,
context: interfaces.context.ContextInterface,
layer_name: str,
symbol_table: str) -> \
symbol_table: str,
quick: bool = False) -> \
Iterable[interfaces.objects.ObjectInterface]:
"""Scans for drivers using the poolscanner module and constraints.
@@ -37,6 +42,7 @@ class DriverScan(interfaces.plugins.PluginInterface):
context: The context to retrieve required elements (layers, symbol tables) from
layer_name: The name of the layer on which to operate
symbol_table: The name of the table containing the kernel symbols
quick: Scan only memory that windows has allocated
Returns:
A list of Driver objects as found from the `layer_name` layer based on Driver pool signatures
@@ -44,13 +50,20 @@ class DriverScan(interfaces.plugins.PluginInterface):
constraints = poolscanner.PoolScanner.builtin_constraints(symbol_table, [b'Dri\xf6', b'Driv'])
for result in poolscanner.PoolScanner.generate_pool_scan(context, layer_name, symbol_table, constraints):
for result in poolscanner.PoolScanner.generate_pool_scan(context,
layer_name,
symbol_table,
constraints,
quick = quick):
_constraint, mem_object, _header = result
yield mem_object
def _generator(self):
for driver in self.scan_drivers(self.context, self.config['primary'], self.config['nt_symbols']):
for driver in self.scan_drivers(self.context,
self.config['primary'],
self.config['nt_symbols'],
quick = self.config['quick']):
try:
driver_name = driver.get_driver_name()
@@ -21,13 +21,18 @@ class FileScan(interfaces.plugins.PluginInterface):
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
requirements.PluginRequirement(name = 'poolscanner', plugin = poolscanner.PoolScanner, version = (1, 0, 0)),
requirements.BooleanRequirement(name = 'quick',
description = "Scan just allocated memory",
default = False,
optional = True),
]
@classmethod
def scan_files(cls,
context: interfaces.context.ContextInterface,
layer_name: str,
symbol_table: str) -> \
symbol_table: str,
quick: bool = False) -> \
Iterable[interfaces.objects.ObjectInterface]:
"""Scans for file objects using the poolscanner module and constraints.
@@ -35,6 +40,7 @@ class FileScan(interfaces.plugins.PluginInterface):
context: The context to retrieve required elements (layers, symbol tables) from
layer_name: The name of the layer on which to operate
symbol_table: The name of the table containing the kernel symbols
quick: Scan only memory that windows has allocated
Returns:
A list of File objects as found from the `layer_name` layer based on File pool signatures
@@ -42,13 +48,20 @@ class FileScan(interfaces.plugins.PluginInterface):
constraints = poolscanner.PoolScanner.builtin_constraints(symbol_table, [b'Fil\xe5', b'File'])
for result in poolscanner.PoolScanner.generate_pool_scan(context, layer_name, symbol_table, constraints):
for result in poolscanner.PoolScanner.generate_pool_scan(context,
layer_name,
symbol_table,
constraints,
quick = quick):
_constraint, mem_object, _header = result
yield mem_object
def _generator(self):
for fileobj in self.scan_files(self.context, self.config['primary'], self.config['nt_symbols']):
for fileobj in self.scan_files(self.context,
self.config['primary'],
self.config['nt_symbols'],
quick = self.config['quick']):
try:
file_name = fileobj.FileName.String
@@ -20,13 +20,18 @@ class ModScan(interfaces.plugins.PluginInterface):
description = 'Memory layer for the kernel',
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
requirements.BooleanRequirement(name = 'quick',
description = "Scan just allocated memory",
default = False,
optional = True),
]
@classmethod
def scan_modules(cls,
context: interfaces.context.ContextInterface,
layer_name: str,
symbol_table: str) -> \
symbol_table: str,
quick: bool = False) -> \
Iterable[interfaces.objects.ObjectInterface]:
"""Scans for modules using the poolscanner module and constraints.
@@ -34,6 +39,7 @@ class ModScan(interfaces.plugins.PluginInterface):
context: The context to retrieve required elements (layers, symbol tables) from
layer_name: The name of the layer on which to operate
symbol_table: The name of the table containing the kernel symbols
quick: Scan only memory that windows has allocated
Returns:
A list of Driver objects as found from the `layer_name` layer based on Driver pool signatures
@@ -41,13 +47,20 @@ class ModScan(interfaces.plugins.PluginInterface):
constraints = poolscanner.PoolScanner.builtin_constraints(symbol_table, [b'MmLd'])
for result in poolscanner.PoolScanner.generate_pool_scan(context, layer_name, symbol_table, constraints):
for result in poolscanner.PoolScanner.generate_pool_scan(context,
layer_name,
symbol_table,
constraints,
quick = quick):
_constraint, mem_object, _header = result
yield mem_object
def _generator(self):
for mod in self.scan_modules(self.context, self.config['primary'], self.config['nt_symbols']):
for mod in self.scan_modules(self.context,
self.config['primary'],
self.config['nt_symbols'],
quick = self.config['quick']):
try:
BaseDllName = mod.BaseDllName.get_string()
@@ -21,13 +21,18 @@ class MutantScan(interfaces.plugins.PluginInterface):
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
requirements.PluginRequirement(name = 'poolscanner', plugin = poolscanner.PoolScanner, version = (1, 0, 0)),
requirements.BooleanRequirement(name = 'quick',
description = "Scan just allocated memory",
default = False,
optional = True),
]
@classmethod
def scan_mutants(cls,
context: interfaces.context.ContextInterface,
layer_name: str,
symbol_table: str) -> \
symbol_table: str,
quick: bool = False) -> \
Iterable[interfaces.objects.ObjectInterface]:
"""Scans for mutants using the poolscanner module and constraints.
@@ -35,6 +40,7 @@ class MutantScan(interfaces.plugins.PluginInterface):
context: The context to retrieve required elements (layers, symbol tables) from
layer_name: The name of the layer on which to operate
symbol_table: The name of the table containing the kernel symbols
quick: Scan only memory that windows has allocated
Returns:
A list of Mutant objects found by scanning memory for the Mutant pool signatures
@@ -42,13 +48,20 @@ class MutantScan(interfaces.plugins.PluginInterface):
constraints = poolscanner.PoolScanner.builtin_constraints(symbol_table, [b'Mut\xe1', b'Muta'])
for result in poolscanner.PoolScanner.generate_pool_scan(context, layer_name, symbol_table, constraints):
for result in poolscanner.PoolScanner.generate_pool_scan(context,
layer_name,
symbol_table,
constraints,
quick = quick):
_constraint, mem_object, _header = result
yield mem_object
def _generator(self):
for mutant in self.scan_mutants(self.context, self.config['primary'], self.config['nt_symbols']):
for mutant in self.scan_mutants(self.context,
self.config['primary'],
self.config['nt_symbols'],
quick = self.config['quick']):
try:
name = mutant.get_name()
@@ -4,7 +4,7 @@
import enum
import logging
from typing import Dict, Generator, List, Optional, Tuple, Callable
from typing import Dict, Generator, List, Optional, Tuple, Callable, Iterable
from volatility.framework import constants, interfaces, renderers, exceptions, symbols
from volatility.framework.configuration import requirements
@@ -411,7 +411,7 @@ class PoolScanner(plugins.PluginInterface):
pool_constraints: List[PoolConstraint],
alignment: int = 8,
progress_callback: Optional[constants.ProgressCallback] = None,
sections: List = None) \
sections: Iterable[Tuple[int, int]] = None) \
-> Generator[Tuple[PoolConstraint, interfaces.objects.ObjectInterface], None, None]:
"""Returns the _POOL_HEADER object (based on the symbol_table template)
after scanning through layer_name returning all headers that match any
@@ -425,6 +425,7 @@ class PoolScanner(plugins.PluginInterface):
pool_constraints: List of pool constraints used to limit the scan results
alignment: An optional value that all pool headers will be aligned to
progress_callback: An optional function to provide progress feedback whilst scanning
sections: Specific memory sections to scan through
Returns:
An Iterable of pool constraints and the pool headers associated with them
+16 -3
View File
@@ -22,13 +22,18 @@ class PsScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
description = 'Memory layer for the kernel',
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
requirements.BooleanRequirement(name = 'quick',
description = "Scan just allocated memory",
default = False,
optional = True),
]
@classmethod
def scan_processes(cls,
context: interfaces.context.ContextInterface,
layer_name: str,
symbol_table: str) -> \
symbol_table: str,
quick: bool = False) -> \
Iterable[interfaces.objects.ObjectInterface]:
"""Scans for processes using the poolscanner module and constraints.
@@ -36,6 +41,7 @@ class PsScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
context: The context to retrieve required elements (layers, symbol tables) from
layer_name: The name of the layer on which to operate
symbol_table: The name of the table containing the kernel symbols
quick: Scan only memory that windows has allocated
Returns:
A list of processes found by scanning the `layer_name` layer for process pool signatures
@@ -43,13 +49,20 @@ class PsScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
constraints = poolscanner.PoolScanner.builtin_constraints(symbol_table, [b'Pro\xe3', b'Proc'])
for result in poolscanner.PoolScanner.generate_pool_scan(context, layer_name, symbol_table, constraints):
for result in poolscanner.PoolScanner.generate_pool_scan(context,
layer_name,
symbol_table,
constraints,
quick = quick):
_constraint, mem_object, _header = result
yield mem_object
def _generator(self):
for proc in self.scan_processes(self.context, self.config['primary'], self.config['nt_symbols']):
for proc in self.scan_processes(self.context,
self.config['primary'],
self.config['nt_symbols'],
quick = self.config['quick']):
yield (0, (proc.UniqueProcessId, proc.InheritedFromUniqueProcessId,
proc.ImageFileName.cast("string", max_length = proc.ImageFileName.vol.count, errors = 'replace'),
@@ -22,13 +22,18 @@ class HiveScan(interfaces.plugins.PluginInterface):
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
requirements.PluginRequirement(name = 'poolscanner', plugin = poolscanner.PoolScanner, version = (1, 0, 0)),
requirements.BooleanRequirement(name = 'quick',
description = "Scan just allocated memory",
default = False,
optional = True),
]
@classmethod
def scan_hives(cls,
context: interfaces.context.ContextInterface,
layer_name: str,
symbol_table: str) -> \
symbol_table: str,
quick: bool = False) -> \
Iterable[interfaces.objects.ObjectInterface]:
"""Scans for hives using the poolscanner module and constraints.
@@ -36,6 +41,7 @@ class HiveScan(interfaces.plugins.PluginInterface):
context: The context to retrieve required elements (layers, symbol tables) from
layer_name: The name of the layer on which to operate
symbol_table: The name of the table containing the kernel symbols
quick: Scan only memory that windows has allocated
Returns:
A list of Hive objects as found from the `layer_name` layer based on Hive pool signatures
@@ -43,13 +49,20 @@ class HiveScan(interfaces.plugins.PluginInterface):
constraints = poolscanner.PoolScanner.builtin_constraints(symbol_table, [b'CM10'])
for result in poolscanner.PoolScanner.generate_pool_scan(context, layer_name, symbol_table, constraints):
for result in poolscanner.PoolScanner.generate_pool_scan(context,
layer_name,
symbol_table,
constraints,
quick = quick):
_constraint, mem_object, _header = result
yield mem_object
def _generator(self):
for hive in self.scan_hives(self.context, self.config['primary'], self.config['nt_symbols']):
for hive in self.scan_hives(self.context,
self.config['primary'],
self.config['nt_symbols'],
quick = self.config['quick']):
yield (0, (format_hints.Hex(hive.vol.offset), ))
@@ -22,13 +22,18 @@ class SymlinkScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterfa
description = 'Memory layer for the kernel',
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
requirements.BooleanRequirement(name = 'quick',
description = "Scan just allocated memory",
default = False,
optional = True),
]
@classmethod
def scan_symlinks(cls,
context: interfaces.context.ContextInterface,
layer_name: str,
symbol_table: str) -> \
symbol_table: str,
quick: bool = False) -> \
Iterable[interfaces.objects.ObjectInterface]:
"""Scans for links using the poolscanner module and constraints.
@@ -36,6 +41,7 @@ class SymlinkScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterfa
context: The context to retrieve required elements (layers, symbol tables) from
layer_name: The name of the layer on which to operate
symbol_table: The name of the table containing the kernel symbols
quick: Scan only memory that windows has allocated
Returns:
A list of symlink objects found by scanning memory for the Symlink pool signatures
@@ -43,13 +49,20 @@ class SymlinkScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterfa
constraints = poolscanner.PoolScanner.builtin_constraints(symbol_table, [b'Sym\xe2', b'Symb'])
for result in poolscanner.PoolScanner.generate_pool_scan(context, layer_name, symbol_table, constraints):
for result in poolscanner.PoolScanner.generate_pool_scan(context,
layer_name,
symbol_table,
constraints,
quick = quick):
_constraint, mem_object, _header = result
yield mem_object
def _generator(self):
for link in self.scan_symlinks(self.context, self.config['primary'], self.config['nt_symbols']):
for link in self.scan_symlinks(self.context,
self.config['primary'],
self.config['nt_symbols'],
quick = self.config['quick']):
try:
from_name = link.get_link_name()