def process_dump( cls, context: interfaces.context.ContextInterface, kernel_table_name: str, pe_table_name: str, proc: interfaces.objects.ObjectInterface ) -> interfaces.plugins.FileInterface: """Extracts the complete data for a process as a FileInterface Args: context: the context to operate upon kernel_table_name: the name for the symbol table containing the kernel's symbols pe_table_name: the name for the symbol table containing the PE format symbols proc: the process object whose memory should be output Returns: A FileInterface object containing the complete data for the process """ proc_id = proc.UniqueProcessId proc_layer_name = proc.add_process_layer() peb = context.object(kernel_table_name + constants.BANG + "_PEB", layer_name=proc_layer_name, offset=proc.Peb) dos_header = context.object(pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER", offset=peb.ImageBaseAddress, layer_name=proc_layer_name) filedata = interfaces.plugins.FileInterface( "pid.{0}.{1:#x}.dmp".format(proc.UniqueProcessId, peb.ImageBaseAddress)) for offset, data in dos_header.reconstruct(): filedata.data.seek(offset) filedata.data.write(data) return filedata
def process_dump( cls, context: interfaces.context.ContextInterface, kernel_table_name: str, pe_table_name: str, proc: interfaces.objects.ObjectInterface, open_method: Type[interfaces.plugins.FileHandlerInterface]) -> interfaces.plugins.FileHandlerInterface: """Extracts the complete data for a process as a FileHandlerInterface Args: context: the context to operate upon kernel_table_name: the name for the symbol table containing the kernel's symbols pe_table_name: the name for the symbol table containing the PE format symbols proc: the process object whose memory should be output open_method: class to provide context manager for opening the file Returns: An open FileHandlerInterface object containing the complete data for the process or None in the case of failure """ file_handle = None try: proc_layer_name = proc.add_process_layer() peb = context.object(kernel_table_name + constants.BANG + "_PEB", layer_name = proc_layer_name, offset = proc.Peb) dos_header = context.object(pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER", offset = peb.ImageBaseAddress, layer_name = proc_layer_name) file_handle = open_method("pid.{0}.{1:#x}.dmp".format(proc.UniqueProcessId, peb.ImageBaseAddress)) for offset, data in dos_header.reconstruct(): file_handle.seek(offset) file_handle.write(data) except Exception as excp: vollog.debug("Unable to dump PE with pid {}: {}".format(proc.UniqueProcessId, excp)) return file_handle
def list_bugcheck_callbacks( cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str, callback_table_name: str) -> Iterable[Tuple[str, int, str]]: """Lists all kernel bugcheck callbacks. Args: 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 callback_table_name: The nae of the table containing the callback symbols Yields: A name, location and optional detail string """ kvo = context.layers[layer_name].config['kernel_virtual_offset'] ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo) try: list_offset = ntkrnlmp.get_symbol( "KeBugCheckCallbackListHead").address except exceptions.SymbolError: vollog.debug("Cannot find KeBugCheckCallbackListHead") return full_type_name = callback_table_name + constants.BANG + "_KBUGCHECK_CALLBACK_RECORD" callback_record = context.object(full_type_name, offset=kvo + list_offset, layer_name=layer_name) for callback in callback_record.Entry: try: context.layers[layer_name].is_valid(callback.CallbackRoutine) except exceptions.InvalidAddressException: continue try: component = context.object(symbol_table + constants.BANG + "string", layer_name=layer_name, offset=callback.Component, max_length=64, errors="replace") except exceptions.InvalidAddressException: component = renderers.UnreadableValue() yield "KeBugCheckCallbackListHead", callback.CallbackRoutine, component
def method_kdbg_offset( self, context: interfaces.context.ContextInterface, vlayer: layers.intel.Intel, progress_callback: constants.ProgressCallback = None ) -> ValidKernelsType: vollog.debug( "Kernel base determination - using KDBG structure for kernel offset" ) valid_kernels = {} # type: ValidKernelsType physical_layer_name = self.get_physical_layer_name(context, vlayer) physical_layer = context.layers[physical_layer_name] results = physical_layer.scan(context, scanners.BytesScanner(b"KDBG"), progress_callback=progress_callback) seen = set() # type: Set[int] for result in results: # TODO: Identify the specific structure we're finding and document this a bit better pointer = context.object("pdbscan!unsigned long long", offset=result + 8, layer_name=physical_layer_name) address = pointer & vlayer.address_mask if address in seen: continue seen.add(address) valid_kernels = self.check_kernel_offset(context, vlayer, address, progress_callback) if valid_kernels: break return valid_kernels
def get_kdbg_structure( cls, context: interfaces.context.ContextInterface, config_path: str, layer_name: str, symbol_table: str) -> interfaces.objects.ObjectInterface: """Returns the KDDEBUGGER_DATA64 structure for a kernel""" ntkrnlmp = cls.get_kernel_module(context, layer_name, symbol_table) native_types = context.symbol_space[symbol_table].natives kdbg_offset = ntkrnlmp.get_symbol("KdDebuggerDataBlock").address kdbg_table_name = intermed.IntermediateSymbolTable.create( context, interfaces.configuration.path_join(config_path, 'kdbg'), "windows", "kdbg", native_types=native_types, class_types=extensions.kdbg.class_types) kdbg = context.object(kdbg_table_name + constants.BANG + "_KDDEBUGGER_DATA64", offset=ntkrnlmp.offset + kdbg_offset, layer_name=layer_name) return kdbg
def get_ntheader_structure( cls, context: interfaces.context.ContextInterface, config_path: str, layer_name: str) -> interfaces.objects.ObjectInterface: """Gets the ntheader structure for the kernel of the specified layer""" virtual_layer = context.layers[layer_name] if not isinstance(virtual_layer, layers.intel.Intel): raise TypeError("Virtual Layer is not an intel layer") kvo = virtual_layer.config["kernel_virtual_offset"] pe_table_name = intermed.IntermediateSymbolTable.create( context, interfaces.configuration.path_join(config_path, 'pe'), "windows", "pe", class_types=extensions.pe.class_types) dos_header = context.object(pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER", offset=kvo, layer_name=layer_name) nt_header = dos_header.get_nt_header() return nt_header
def method_module_offset(self, context: interfaces.context.ContextInterface, vlayer: layers.intel.Intel, progress_callback: constants.ProgressCallback = None) -> ValidKernelsType: """Method for finding a suitable kernel offset based on a module table.""" vollog.debug("Kernel base determination - searching layer module list structure") valid_kernels = {} # type: ValidKernelsType # If we're here, chances are high we're in a Win10 x64 image with kernel base randomization virtual_layer_name = vlayer.name physical_layer_name = self.get_physical_layer_name(context, vlayer) physical_layer = context.layers[physical_layer_name] # TODO: On older windows, this might be \WINDOWS\system32\nt rather than \SystemRoot\system32\nt results = physical_layer.scan(context, scanners.BytesScanner(b"\\SystemRoot\\system32\\nt"), progress_callback = progress_callback) seen = set() # type: Set[int] # Because this will launch a scan of the virtual layer, we want to be careful for result in results: # TODO: Identify the specific structure we're finding and document this a bit better pointer = context.object("pdbscan!unsigned long long", offset = (result - 16 - int(vlayer.bits_per_register / 8)), layer_name = physical_layer_name) address = pointer & vlayer.address_mask if address in seen: continue seen.add(address) valid_kernels = self.check_kernel_offset(context, vlayer, address, progress_callback) if valid_kernels: break return valid_kernels
def find_cookie(cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str) -> Optional[interfaces.objects.ObjectInterface]: """Find the ObHeaderCookie value (if it exists)""" try: offset = context.symbol_space.get_symbol(symbol_table + constants.BANG + "ObHeaderCookie").address except exceptions.SymbolError: return None kvo = context.layers[layer_name].config['kernel_virtual_offset'] return context.object(symbol_table + constants.BANG + "unsigned int", layer_name, offset = kvo + offset)
def get_session_layers( cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str, pids: List[int] = None) -> Generator[str, None, None]: """Build a cache of possible virtual layers, in priority starting with the primary/kernel layer. Then keep one layer per session by cycling through the process list. Args: 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 pids: A list of process identifiers to include exclusively or None for no filter Returns: A list of session layer names """ seen_ids = [] # type: List[interfaces.objects.ObjectInterface] filter_func = pslist.PsList.create_pid_filter(pids or []) for proc in pslist.PsList.list_processes(context=context, layer_name=layer_name, symbol_table=symbol_table, filter_func=filter_func): proc_id = "Unknown" try: proc_id = proc.UniqueProcessId proc_layer_name = proc.add_process_layer() # create the session space object in the process' own layer. # not all processes have a valid session pointer. session_space = context.object(symbol_table + constants.BANG + "_MM_SESSION_SPACE", layer_name=layer_name, offset=proc.Session) if session_space.SessionId in seen_ids: continue except exceptions.InvalidAddressException: vollog.log( constants.LOGLEVEL_VVV, "Process {} does not have a valid Session or a layer could not be constructed for it" .format(proc_id)) continue # save the layer if we haven't seen the session yet seen_ids.append(session_space.SessionId) yield proc_layer_name
def dump_pe( cls, context: interfaces.context.ContextInterface, pe_table_name: str, dll_entry: interfaces.objects.ObjectInterface, open_method: Type[interfaces.plugins.FileHandlerInterface], layer_name: str = None, prefix: str = '' ) -> Optional[interfaces.plugins.FileHandlerInterface]: """Extracts the complete data for a process as a FileInterface Args: context: the context to operate upon pe_table_name: the name for the symbol table containing the PE format symbols dll_entry: the object representing the module layer_name: the layer that the DLL lives within open_method: class for constructing output files Returns: An open FileHandlerInterface object containing the complete data for the DLL or None in the case of failure """ try: try: name = dll_entry.FullDllName.get_string() except exceptions.InvalidAddressException: name = 'UnreadbleDLLName' if layer_name is None: layer_name = dll_entry.vol.layer_name file_handle = open_method("{}{}.{:#x}.{:#x}.dmp".format( prefix, ntpath.basename(name), dll_entry.vol.offset, dll_entry.DllBase)) dos_header = context.object(pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER", offset=dll_entry.DllBase, layer_name=layer_name) for offset, data in dos_header.reconstruct(): file_handle.seek(offset) file_handle.write(data) except (IOError, exceptions.VolatilityException, OverflowError, ValueError) as excp: vollog.debug("Unable to dump dll at offset {}: {}".format( dll_entry.DllBase, excp)) return None return file_handle
def get_version_information( cls, context: interfaces.context.ContextInterface, pe_table_name: str, layer_name: str, base_address: int) -> Tuple[int, int, int, int]: """Get File and Product version information from PE files. Args: context: volatility context on which to operate pe_table_name: name of the PE table layer_name: name of the layer containing the PE file base_address: base address of the PE (where MZ is found) """ if layer_name is None: raise ValueError("Layer must be a string not None") pe_data = io.BytesIO() dos_header = context.object(pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER", offset=base_address, layer_name=layer_name) for offset, data in dos_header.reconstruct(): pe_data.seek(offset) pe_data.write(data) pe = pefile.PE(data=pe_data.getvalue(), fast_load=True) pe.parse_data_directories( [pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_RESOURCE"]]) if isinstance(pe.VS_FIXEDFILEINFO, list): # pefile >= 2018.8.8 (estimated) version_struct = pe.VS_FIXEDFILEINFO[0] else: # pefile <= 2017.11.5 (estimated) version_struct = pe.VS_FIXEDFILEINFO major = version_struct.ProductVersionMS >> 16 minor = version_struct.ProductVersionMS & 0xFFFF product = version_struct.ProductVersionLS >> 16 build = version_struct.ProductVersionLS & 0xFFFF pe_data.close() return major, minor, product, build
def dump_pe(cls, context: interfaces.context.ContextInterface, pe_table_name: str, dll_entry: interfaces.objects.ObjectInterface, layer_name: str = None) -> interfaces.plugins.FileInterface: """Extracts the complete data for a process as a FileInterface Args: context: the context to operate upon pe_table_name: the name for the symbol table containing the PE format symbols dll_entry: the object representing the module layer_name: the layer that the DLL lives within Returns: A FileInterface object containing the complete data for the DLL or None in the case of failure""" filedata = None try: try: name = dll_entry.FullDllName.get_string() except exceptions.InvalidAddressException: name = 'UnreadbleDLLName' if layer_name is None: layer_name = dll_entry.vol.layer_name filedata = interfaces.plugins.FileInterface( "{0}.{1:#x}.{2:#x}.dmp".format(ntpath.basename(name), dll_entry.vol.offset, dll_entry.DllBase)) dos_header = context.object(pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER", offset=dll_entry.DllBase, layer_name=layer_name) for offset, data in dos_header.reconstruct(): filedata.data.seek(offset) filedata.data.write(data) except Exception as excp: vollog.debug("Unable to dump dll at offset {}: {}".format( dll_entry.DllBase, excp)) return filedata
def get_cmdline(cls, context: interfaces.context.ContextInterface, kernel_table_name: str, proc): """Extracts the cmdline from PEB Args: context: the context to operate upon kernel_table_name: the name for the symbol table containing the kernel's symbols proc: the process object Returns: A string with the command line """ proc_layer_name = proc.add_process_layer() peb = context.object(kernel_table_name + constants.BANG + "_PEB", layer_name=proc_layer_name, offset=proc.Peb) result_text = peb.ProcessParameters.CommandLine.get_string() return result_text