1414from volatility3 .framework .layers import scanners
1515from volatility3 .framework .objects import utility
1616from volatility3 .framework .renderers import format_hints
17- from volatility3 .plugins .windows import pslist , vadinfo , info , verinfo , consoles
18- from volatility3 .plugins .windows .registry import hivelist
17+ from volatility3 .plugins .windows import pslist , consoles
1918
2019
21- try :
22- import capstone
23-
24- has_capstone = True
25- except ImportError :
26- has_capstone = False
27-
2820vollog = logging .getLogger (__name__ )
2921
3022
3123class CmdScan (interfaces .plugins .PluginInterface ):
3224 """Looks for Windows Command History lists"""
3325
3426 _required_framework_version = (2 , 4 , 0 )
27+ _version = (1 , 0 , 0 )
3528
3629 @classmethod
3730 def get_requirements (cls ):
@@ -46,7 +39,7 @@ def get_requirements(cls):
4639 name = "pslist" , component = pslist .PsList , version = (2 , 0 , 0 )
4740 ),
4841 requirements .PluginRequirement (
49- name = "hivelist " , plugin = hivelist . HiveList , version = (1 , 0 , 0 )
42+ name = "consoles " , plugin = consoles . Consoles , version = (1 , 0 , 0 )
5043 ),
5144 requirements .BooleanRequirement (
5245 name = "no_registry" ,
@@ -70,7 +63,7 @@ def get_filtered_vads(
7063 size_filter : Optional [int ] = 0x40000000 ,
7164 ) -> List [Tuple [int , int ]]:
7265 """
73- Returns vads of a process with smaller than size_filter
66+ Returns vads of a process with size smaller than size_filter
7467
7568 Args:
7669 conhost_proc: the process object for conhost.exe
@@ -114,12 +107,10 @@ def get_command_history(
114107
115108 Returns:
116109 The conhost process object, the command history structure, a dictionary of properties for
117- that command historyn structure.
110+ that command history structure.
118111 """
119112
120- conhost_symbol_table = consoles .Consoles .create_conhost_symbol_table (
121- context , kernel_layer_name , kernel_table_name , config_path
122- )
113+ conhost_symbol_table = None
123114
124115 for conhost_proc , proc_layer_name in consoles .Consoles .find_conhost_proc (procs ):
125116 if not conhost_proc :
@@ -143,11 +134,22 @@ def get_command_history(
143134
144135 proc_layer = context .layers [proc_layer_name ]
145136
137+ if conhost_symbol_table is None :
138+ conhost_symbol_table = consoles .Consoles .create_conhost_symbol_table (
139+ context ,
140+ kernel_layer_name ,
141+ kernel_table_name ,
142+ config_path ,
143+ proc_layer_name ,
144+ conhostexe_base ,
145+ )
146+
146147 conhost_module = context .module (
147148 conhost_symbol_table , proc_layer_name , offset = conhostexe_base
148149 )
149150
150151 sections = cls .get_filtered_vads (conhost_proc )
152+ found_history_for_proc = False
151153 # scan for potential _COMMAND_HISTORY structures by using the CommandHistorySize
152154 for max_history_value in max_history :
153155 max_history_bytes = struct .pack ("H" , max_history_value )
@@ -258,7 +260,12 @@ def get_command_history(
258260 f"reading { command_history } encountered exception { e } "
259261 )
260262
261- yield conhost_proc , command_history , command_history_properties
263+ if command_history and command_history_properties :
264+ found_history_for_proc = True
265+ yield conhost_proc , command_history , command_history_properties
266+
267+ if not found_history_for_proc :
268+ yield conhost_proc , command_history or None , []
262269
263270 def _generator (
264271 self , procs : Generator [interfaces .objects .ObjectInterface , None , None ]
@@ -276,19 +283,18 @@ def _generator(
276283 no_registry = self .config .get ("no_registry" )
277284
278285 if no_registry is False :
279- max_history , _max_buffers = (
280- consoles .Consoles .get_console_settings_from_registry (
281- self .context ,
282- self .config_path ,
283- kernel .layer_name ,
284- kernel .symbol_table_name ,
285- max_history ,
286- [],
287- )
286+ max_history , _ = consoles .Consoles .get_console_settings_from_registry (
287+ self .context ,
288+ self .config_path ,
289+ kernel .layer_name ,
290+ kernel .symbol_table_name ,
291+ max_history ,
292+ [],
288293 )
289294
290295 vollog .debug (f"Possible CommandHistorySize values: { max_history } " )
291296
297+ proc = None
292298 for (
293299 proc ,
294300 command_history ,
@@ -302,13 +308,14 @@ def _generator(
302308 max_history ,
303309 ):
304310 process_name = utility .array_to_string (proc .ImageFileName )
311+ process_pid = proc .UniqueProcessId
305312
306313 if command_history and command_history_properties :
307314 for command_history_property in command_history_properties :
308315 yield (
309316 command_history_property ["level" ],
310317 (
311- proc . UniqueProcessId ,
318+ process_pid ,
312319 process_name ,
313320 format_hints .Hex (command_history .vol .offset ),
314321 command_history_property ["name" ],
@@ -322,6 +329,25 @@ def _generator(
322329 str (command_history_property ["data" ]),
323330 ),
324331 )
332+ else :
333+ yield (
334+ 0 ,
335+ (
336+ process_pid ,
337+ process_name ,
338+ (
339+ format_hints .Hex (command_history .vol .offset )
340+ if command_history
341+ else renderers .NotApplicableValue ()
342+ ),
343+ "_COMMAND_HISTORY" ,
344+ renderers .NotApplicableValue (),
345+ "History Not Found" ,
346+ ),
347+ )
348+
349+ if proc is None :
350+ vollog .warn ("No conhost.exe processes found." )
325351
326352 def _conhost_proc_filter (self , proc ):
327353 """
0 commit comments