66import datetime
77import functools
88import logging
9+ import struct
910import math
10- from typing import Iterable , Iterator , Optional , Union , Tuple , List
11+ from typing import Iterable , Iterator , Optional , Union , Dict , Tuple , List
1112
1213from volatility .framework import constants , exceptions , interfaces , objects , renderers , symbols
1314from volatility .framework .layers import intel
@@ -30,6 +31,7 @@ def get_time(self):
3031
3132class MMVAD_SHORT (objects .StructType ):
3233 """A class that represents process virtual memory ranges.
34+
3335 Each instance is a node in a binary tree structure and is pointed to
3436 by VadRoot.
3537 """
@@ -135,7 +137,6 @@ def get_right_child(self):
135137 return self .Core .VadNode .RightChild
136138 if self .Core .VadNode .has_member ("Right" ):
137139 return self .Core .VadNode .Right
138-
139140 raise AttributeError ("Unable to find the right child member" )
140141
141142 def get_left_child (self ):
@@ -146,7 +147,6 @@ def get_left_child(self):
146147
147148 elif self .has_member ("Left" ):
148149 return self .Left
149-
150150 # this is for windows 8 and 10
151151 elif self .has_member ("VadNode" ):
152152 if self .VadNode .has_member ("LeftChild" ):
@@ -323,6 +323,7 @@ def get_file_name(self):
323323class EX_FAST_REF (objects .StructType ):
324324 """This is a standard Windows structure that stores a pointer to an object
325325 but also leverages the least significant bits to encode additional details.
326+
326327 When dereferencing the pointer, we need to strip off the extra bits.
327328 """
328329
@@ -404,7 +405,6 @@ def file_name_with_device(self) -> Union[str, interfaces.renderers.BaseAbsentVal
404405 pass
405406
406407 return name
407-
408408 def access_string (self ):
409409 ## Make a nicely formatted ACL string
410410 return (('R' if self .ReadAccess else '-' ) + ('W' if self .WriteAccess else '-' ) +
@@ -431,7 +431,6 @@ class ETHREAD(objects.StructType):
431431 def owning_process (self , kernel_layer : str = None ) -> interfaces .objects .ObjectInterface :
432432 """Return the EPROCESS that owns this thread."""
433433 return self .ThreadsProcess .dereference (kernel_layer )
434-
435434 def get_cross_thread_flags (self ) -> str :
436435 dictCrossThreadFlags = {
437436 'PS_CROSS_THREAD_FLAGS_TERMINATED' : 0 ,
@@ -666,7 +665,6 @@ def get_vad_root(self):
666665 else :
667666 # windows xp and 2003
668667 return self .VadRoot .dereference ().cast ("_MMVAD" )
669-
670668 def environment_variables (self ):
671669 """Generator for environment variables.
672670
@@ -756,7 +754,6 @@ def to_list(self,
756754 def __iter__ (self ) -> Iterator [interfaces .objects .ObjectInterface ]:
757755 return self .to_list (self .vol .parent .vol .type_name , self .vol .member_name )
758756
759-
760757class TOKEN (objects .StructType ):
761758 """A class for process etoken object."""
762759
@@ -875,6 +872,7 @@ def get_wait_reason(self) -> str:
875872 37 : 'MaximumWaitReason'
876873 }
877874 return dictWaitReason .get (self .WaitReason , renderers .NotApplicableValue ())
875+
878876class CONTROL_AREA (objects .StructType ):
879877 """A class for _CONTROL_AREA structures"""
880878
@@ -984,6 +982,24 @@ class VACB(objects.StructType):
984982
985983 FILEOFFSET_MASK = 0xFFFFFFFFFFFF0000
986984
985+ def is_valid (self , shared_cache_map : interfaces .objects .ObjectInterface ) -> bool :
986+ """Determine if the object is valid."""
987+ try :
988+ layer = self ._context .layers [self .vol .layer_name ]
989+
990+ # Check if the Overlay member of _VACB is resident. The Overlay member stores information
991+ # about the FileOffset and the ActiveCount. This is just another proactive sanity check.
992+ #if not self.Overlay:
993+ # return False
994+
995+ if not layer .is_valid (self .SharedCacheMap ):
996+ return False
997+
998+ # Make sure that the SharedCacheMap member of the VACB points back to the parent object.
999+ return self .SharedCacheMap == shared_cache_map .vol .offset
1000+ except exceptions .InvalidAddressException :
1001+ return False
1002+
9871003 def get_file_offset (self ) -> int :
9881004 # The FileOffset member of VACB is used to denote the offset within the file where the
9891005 # view begins. Since all views are 256 KB in size, the bottom 16 bits are used to
@@ -1075,19 +1091,15 @@ def get_available_pages(self) -> List:
10751091 iterval = 0
10761092 while (iterval < full_blocks ) and (full_blocks <= 4 ):
10771093 vacb_obj = self .InitialVacbs [iterval ]
1078- try :
1079- # Make sure that the SharedCacheMap member of the VACB points back to the parent object.
1080- if vacb_obj .SharedCacheMap == self .vol .offset :
1081- self .save_vacb (vacb_obj , vacb_list )
1082- except exceptions .InvalidAddressException :
1083- pass
1094+ if vacb_obj .is_valid (shared_cache_map = self ):
1095+ self .save_vacb (vacb_obj , vacb_list )
10841096 iterval += 1
10851097
10861098 # We also have to account for the spill over data that is not found in the full blocks.
10871099 # The first case to consider is when the spill over is still in InitialVacbs.
10881100 if (left_over > 0 ) and (full_blocks < 4 ):
10891101 vacb_obj = self .InitialVacbs [iterval ]
1090- if vacb_obj .SharedCacheMap == self . vol . offset :
1102+ if vacb_obj .is_valid ( shared_cache_map = self ) :
10911103 self .save_vacb (vacb_obj , vacb_list )
10921104
10931105 # If the file is larger than 1 MB, a seperate VACB index array needs to be allocated.
@@ -1124,7 +1136,7 @@ def get_available_pages(self) -> List:
11241136 continue
11251137
11261138 vacb = vacb_entry .dereference ().cast (symbol_table_name + constants .BANG + "_VACB" )
1127- if vacb .SharedCacheMap == self . vol . offset :
1139+ if vacb .is_valid ( shared_cache_map = self ) :
11281140 self .save_vacb (vacb , vacb_list )
11291141
11301142 if left_over > 0 :
@@ -1136,7 +1148,7 @@ def get_available_pages(self) -> List:
11361148 return vacb_list
11371149
11381150 vacb = vacb_entry .dereference ().cast (symbol_table_name + constants .BANG + "_VACB" )
1139- if vacb .SharedCacheMap == self . vol . offset :
1151+ if vacb .is_valid ( shared_cache_map = self ) :
11401152 self .save_vacb (vacb , vacb_list )
11411153
11421154 # The file is less than 32 MB, so we can stop processing.
@@ -1168,7 +1180,8 @@ def get_available_pages(self) -> List:
11681180
11691181 vacb = vacb_array [counter ].dereference ().cast (symbol_table_name + constants .BANG + "_VACB" )
11701182 if vacb .SharedCacheMap == self .vol .offset :
1171- self .save_vacb (vacb , vacb_list )
1183+ if vacb .is_valid (shared_cache_map = self ):
1184+ self .save_vacb (vacb , vacb_list )
11721185 else :
11731186 # Process the next level of the multi-level array. We set the limit_depth to be
11741187 # the depth of the tree as determined from the size and we initialize the
0 commit comments