#816 - fix cmdscan

This commit is contained in:
Dave Lassalle
2024-09-27 16:07:44 -05:00
parent 9d98ab9b65
commit bd678eaf80
2 changed files with 75 additions and 41 deletions
@@ -14,17 +14,9 @@ from volatility3.framework.configuration import requirements
from volatility3.framework.layers import scanners
from volatility3.framework.objects import utility
from volatility3.framework.renderers import format_hints
from volatility3.plugins.windows import pslist, vadinfo, info, verinfo, consoles
from volatility3.plugins.windows.registry import hivelist
from volatility3.plugins.windows import pslist, consoles
try:
import capstone
has_capstone = True
except ImportError:
has_capstone = False
vollog = logging.getLogger(__name__)
@@ -32,6 +24,7 @@ class CmdScan(interfaces.plugins.PluginInterface):
"""Looks for Windows Command History lists"""
_required_framework_version = (2, 4, 0)
_version = (1, 0, 0)
@classmethod
def get_requirements(cls):
@@ -46,7 +39,7 @@ class CmdScan(interfaces.plugins.PluginInterface):
name="pslist", component=pslist.PsList, version=(2, 0, 0)
),
requirements.PluginRequirement(
name="hivelist", plugin=hivelist.HiveList, version=(1, 0, 0)
name="consoles", plugin=consoles.Consoles, version=(1, 0, 0)
),
requirements.BooleanRequirement(
name="no_registry",
@@ -70,7 +63,7 @@ class CmdScan(interfaces.plugins.PluginInterface):
size_filter: Optional[int] = 0x40000000,
) -> List[Tuple[int, int]]:
"""
Returns vads of a process with smaller than size_filter
Returns vads of a process with size smaller than size_filter
Args:
conhost_proc: the process object for conhost.exe
@@ -114,12 +107,10 @@ class CmdScan(interfaces.plugins.PluginInterface):
Returns:
The conhost process object, the command history structure, a dictionary of properties for
that command historyn structure.
that command history structure.
"""
conhost_symbol_table = consoles.Consoles.create_conhost_symbol_table(
context, kernel_layer_name, kernel_table_name, config_path
)
conhost_symbol_table = None
for conhost_proc, proc_layer_name in consoles.Consoles.find_conhost_proc(procs):
if not conhost_proc:
@@ -143,11 +134,22 @@ class CmdScan(interfaces.plugins.PluginInterface):
proc_layer = context.layers[proc_layer_name]
if conhost_symbol_table is None:
conhost_symbol_table = consoles.Consoles.create_conhost_symbol_table(
context,
kernel_layer_name,
kernel_table_name,
config_path,
proc_layer_name,
conhostexe_base,
)
conhost_module = context.module(
conhost_symbol_table, proc_layer_name, offset=conhostexe_base
)
sections = cls.get_filtered_vads(conhost_proc)
found_history_for_proc = False
# scan for potential _COMMAND_HISTORY structures by using the CommandHistorySize
for max_history_value in max_history:
max_history_bytes = struct.pack("H", max_history_value)
@@ -258,7 +260,12 @@ class CmdScan(interfaces.plugins.PluginInterface):
f"reading {command_history} encountered exception {e}"
)
yield conhost_proc, command_history, command_history_properties
if command_history and command_history_properties:
found_history_for_proc = True
yield conhost_proc, command_history, command_history_properties
if not found_history_for_proc:
yield conhost_proc, command_history or None, []
def _generator(
self, procs: Generator[interfaces.objects.ObjectInterface, None, None]
@@ -276,19 +283,18 @@ class CmdScan(interfaces.plugins.PluginInterface):
no_registry = self.config.get("no_registry")
if no_registry is False:
max_history, _max_buffers = (
consoles.Consoles.get_console_settings_from_registry(
self.context,
self.config_path,
kernel.layer_name,
kernel.symbol_table_name,
max_history,
[],
)
max_history, _ = consoles.Consoles.get_console_settings_from_registry(
self.context,
self.config_path,
kernel.layer_name,
kernel.symbol_table_name,
max_history,
[],
)
vollog.debug(f"Possible CommandHistorySize values: {max_history}")
proc = None
for (
proc,
command_history,
@@ -302,13 +308,14 @@ class CmdScan(interfaces.plugins.PluginInterface):
max_history,
):
process_name = utility.array_to_string(proc.ImageFileName)
process_pid = proc.UniqueProcessId
if command_history and command_history_properties:
for command_history_property in command_history_properties:
yield (
command_history_property["level"],
(
proc.UniqueProcessId,
process_pid,
process_name,
format_hints.Hex(command_history.vol.offset),
command_history_property["name"],
@@ -322,6 +329,25 @@ class CmdScan(interfaces.plugins.PluginInterface):
str(command_history_property["data"]),
),
)
else:
yield (
0,
(
process_pid,
process_name,
(
format_hints.Hex(command_history.vol.offset)
if command_history
else renderers.NotApplicableValue()
),
"_COMMAND_HISTORY",
renderers.NotApplicableValue(),
"History Not Found",
),
)
if proc is None:
vollog.warn("No conhost.exe processes found.")
def _conhost_proc_filter(self, proc):
"""
@@ -17,19 +17,11 @@ from volatility3.framework.layers import scanners
from volatility3.framework.objects import utility
from volatility3.framework.renderers import format_hints
from volatility3.framework.symbols import intermed
from volatility3.framework.symbols.windows import pdbutil
from volatility3.framework.symbols.windows.extensions import pe, consoles
from volatility3.plugins.windows import pslist, vadinfo, info, verinfo
from volatility3.plugins.windows import pslist, info, verinfo
from volatility3.plugins.windows.registry import hivelist
try:
import capstone
has_capstone = True
except ImportError:
has_capstone = False
vollog = logging.getLogger(__name__)
@@ -37,6 +29,7 @@ class Consoles(interfaces.plugins.PluginInterface):
"""Looks for Windows console buffers"""
_required_framework_version = (2, 4, 0)
_version = (1, 0, 0)
@classmethod
def get_requirements(cls):
@@ -53,9 +46,6 @@ class Consoles(interfaces.plugins.PluginInterface):
requirements.VersionRequirement(
name="verinfo", component=verinfo.VerInfo, version=(1, 0, 0)
),
requirements.VersionRequirement(
name="pdbutil", component=pdbutil.PDBUtility, version=(1, 0, 0)
),
requirements.PluginRequirement(
name="hivelist", plugin=hivelist.HiveList, version=(1, 0, 0)
),
@@ -443,6 +433,7 @@ class Consoles(interfaces.plugins.PluginInterface):
conhost_symbol_table, proc_layer_name, offset=conhostexe_base
)
found_console_info_for_proc = False
# scan for potential _CONSOLE_INFORMATION structures by using the CommandHistorySize
for max_history_value in max_history:
max_history_bytes = struct.pack("H", max_history_value)
@@ -790,7 +781,12 @@ class Consoles(interfaces.plugins.PluginInterface):
)
continue
yield conhost_proc, console_info, console_properties
if console_info and console_properties:
found_console_info_for_proc = True
yield conhost_proc, console_info, console_properties
if not found_console_info_for_proc:
yield conhost_proc, console_info or None, []
@classmethod
def get_console_settings_from_registry(
@@ -903,8 +899,20 @@ class Consoles(interfaces.plugins.PluginInterface):
),
)
else:
vollog.warn(
f"_CONSOLE_INFORMATION not found for {process_name} with pid {process_pid}."
yield (
0,
(
process_pid,
process_name,
(
format_hints.Hex(console_info.vol.offset)
if console_info
else renderers.NotApplicableValue()
),
"_CONSOLE_INFORMATION",
renderers.NotApplicableValue(),
"Console Information Not Found",
),
)
if proc is None: