@@ -37,8 +37,11 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]
3737 requirements .IntRequirement (name = 'pid' ,
3838 description = "Process ID to include (all other processes are excluded)" ,
3939 optional = True ),
40- requirements .IntRequirement (name = 'fileoffset' ,
41- description = "Dump a single _FILE_OBJECT at this offset" ,
40+ requirements .IntRequirement (name = 'virtaddr' ,
41+ description = "Dump a single _FILE_OBJECT at this virtual address" ,
42+ optional = True ),
43+ requirements .IntRequirement (name = 'physaddr' ,
44+ description = "Dump a single _FILE_OBJECT at this physical address" ,
4245 optional = True ),
4346 requirements .PluginRequirement (name = 'pslist' , plugin = pslist .PsList , version = (1 , 0 , 0 )),
4447 requirements .PluginRequirement (name = 'handles' , plugin = handles .Handles , version = (1 , 0 , 0 ))
@@ -145,13 +148,12 @@ def process_file_object(self, file_obj: interfaces.objects.ObjectInterface) -> T
145148 result_text )
146149
147150 def _generator (self , procs : List , offsets : List ):
148- # The handles plugin doesn't expose any staticmethod/classmethod, and it also requires stashing
149- # private variables, so we need an instance (for now, anyway). We _could_ call Handles._generator()
150- # to do some of the other work that is duplicated here, but then we'd need to parse the TreeGrid
151- # results instead of just dealing with them as direct objects here.
152151
153152 if procs :
154- # Standard code for invoking the Handles() plugin from another plugin.
153+ # The handles plugin doesn't expose any staticmethod/classmethod, and it also requires stashing
154+ # private variables, so we need an instance (for now, anyway). We _could_ call Handles._generator()
155+ # to do some of the other work that is duplicated here, but then we'd need to parse the TreeGrid
156+ # results instead of just dealing with them as direct objects here.
155157 handles_plugin = handles .Handles (context = self .context , config_path = self ._config_path )
156158 type_map = handles_plugin .get_type_map (context = self .context ,
157159 layer_name = self .config ["primary" ],
@@ -204,10 +206,15 @@ def _generator(self, procs: List, offsets: List):
204206
205207 elif offsets :
206208 # Now process any offsets explicitly requested by the user.
207- for offset in offsets :
209+ for offset , is_virtual in offsets :
208210 try :
211+ layer_name = self .config ["primary" ]
212+ # switch to a memory layer if the user provided --physaddr instead of --virtaddr
213+ if not is_virtual :
214+ layer_name = self .context .layers [layer_name ].config ["memory_layer" ]
215+
209216 file_obj = self .context .object (self .config ["nt_symbols" ] + constants .BANG + "_FILE_OBJECT" ,
210- layer_name = self . config [ "primary" ] ,
217+ layer_name = layer_name ,
211218 native_layer_name = self .config ["primary" ],
212219 offset = offset )
213220 for result in self .process_file_object (file_obj ):
@@ -217,12 +224,17 @@ def _generator(self, procs: List, offsets: List):
217224 "Cannot extract file at {0:#x}" .format (offset ))
218225
219226 def run (self ):
220- if self .config .get ("fileoffset" , None ) is not None :
221- offsets = [self .config ["fileoffset" ]]
222- procs = []
227+ # a list of tuples (<int>, <bool>) where <int> is the address and <bool> is True for virtual.
228+ offsets = []
229+ # a list of processes matching the pid filter. all files for these process(es) will be dumped.
230+ procs = []
231+
232+ if self .config .get ("virtaddr" , None ) is not None :
233+ offsets .append ((self .config ["virtaddr" ], True ))
234+ elif self .config .get ("physaddr" , None ) is not None :
235+ offsets .append ((self .config ["physaddr" ], False ))
223236 else :
224237 filter_func = pslist .PsList .create_pid_filter ([self .config .get ("pid" , None )])
225- offsets = []
226238 procs = pslist .PsList .list_processes (self .context ,
227239 self .config ["primary" ],
228240 self .config ["nt_symbols" ],
0 commit comments