def _generator(self, procs): type_map = self.get_type_map(context=self.context, layer_name=self.config["primary"], symbol_table=self.config["nt_symbols"]) cookie = self.find_cookie(context=self.context, layer_name=self.config["primary"], symbol_table=self.config["nt_symbols"]) for proc in procs: try: object_table = proc.ObjectTable except exceptions.InvalidAddressException: vollog.log( constants.LOGLEVEL_VVV, "Cannot access _EPROCESS.ObjectType at {0:#x}".format( proc.vol.offset)) continue process_name = utility.array_to_string(proc.ImageFileName) for entry in self.handles(object_table): try: obj_type = entry.get_object_type(type_map, cookie) if obj_type is None: continue if obj_type == "File": item = entry.Body.cast("_FILE_OBJECT") obj_name = item.file_name_with_device() elif obj_type == "Process": item = entry.Body.cast("_EPROCESS") obj_name = "{} Pid {}".format( utility.array_to_string(proc.ImageFileName), item.UniqueProcessId) elif obj_type == "Thread": item = entry.Body.cast("_ETHREAD") obj_name = "Tid {} Pid {}".format( item.Cid.UniqueThread, item.Cid.UniqueProcess) elif obj_type == "Key": item = entry.Body.cast("_CM_KEY_BODY") obj_name = item.get_full_key_name() else: try: obj_name = entry.NameInfo.Name.String except (ValueError, exceptions.InvalidAddressException): obj_name = "" except (exceptions.InvalidAddressException): vollog.log( constants.LOGLEVEL_VVV, "Cannot access _OBJECT_HEADER at {0:#x}".format( entry.vol.offset)) continue yield (0, (proc.UniqueProcessId, process_name, format_hints.Hex(entry.Body.vol.offset), format_hints.Hex(entry.HandleValue), obj_type, format_hints.Hex(entry.GrantedAccess), obj_name))
def _generator(self): for mount in self.list_mounts(self.context, self.config['primary'], self.config['darwin']): vfs = mount.mnt_vfsstat device_name = utility.array_to_string(vfs.f_mntonname) mount_point = utility.array_to_string(vfs.f_mntfromname) mount_type = utility.array_to_string(vfs.f_fstypename) yield 0, (device_name, mount_point, mount_type)
def probe_address(self, ptr): sshenc = self.context.object(self.openssh_table_name + constants.BANG + "sshenc_61p2", offset=ptr, layer_name=self.proc_layer_name) name_valid = sshenc.name.is_readable() cipher_valid = sshenc.cipher.is_readable() if not (name_valid and cipher_valid): return None enc_name = sshenc.name.dereference() enc_name = utility.array_to_string(enc_name) enc_properties = lookup_enc(enc_name) if not enc_properties: return None expected_key_len = enc_properties[2] key_len_valid = expected_key_len == sshenc.key_len if not key_len_valid: return None cipher_name = sshenc.cipher.name.dereference() cipher_name = utility.array_to_string(cipher_name) if cipher_name != enc_name: return None vollog.debug("Found possible candidate at address 0x{:x}.".format(ptr)) #At this point we know pretty certain this is the sshenc struct. Let's figure out which version... expected_block_size = enc_properties[1] block_size_valid = expected_block_size == sshenc.block_size if not block_size_valid: vollog.warning( "Detected structure misaslignment. Trying sshenc_61p1 structure.." ) sshenc = self.context.object(self.openssh_table_name + constants.BANG + "sshenc_61p1", offset=ptr, layer_name=self.proc_layer_name) block_size_valid = expected_block_size == sshenc.block_size if not block_size_valid: vollog.error("Detected sshenc structure but can't seem to align!") # Bugger we can't seem to properly align the structure return None key_valid = sshenc.key.is_readable() iv_valid = sshenc.iv.is_readable() if key_valid and iv_valid: return sshenc vollog.error("Detected sshenc structure but invalid key/IV address!") return None
def _generator(self, tasks): result = [] is_32bit = not symbols.symbol_table_is_64bit(self.context, self.config["vmlinux"]) if is_32bit: openssh_json_file = "openssh32" else: openssh_json_file = "openssh64" openssh_table_name = intermed.IntermediateSymbolTable.create( self.context, self.config_path, 'linux', openssh_json_file) for task in tasks: if not task.mm: continue name = utility.array_to_string(task.comm) vollog.info("Scanning process #{} ({} {})".format( task.pid, name, "")) proc_layer_name = task.add_process_layer() extractor = SSHKeyExtractor(self.context, openssh_table_name, proc_layer_name, task, self._progress_callback) keys = extractor.extract() result.extend(keys) return result
def yield_processes(pid): proc = self._processes[pid] row = (proc.pid, proc.parent.pid, utility.array_to_string(proc.comm)) yield (self._levels[pid] - 1, row) for child_pid in self._children.get(pid, []): yield from yield_processes(child_pid)
def _generator(self, tasks): for task in tasks: if not task.mm: continue name = utility.array_to_string(task.comm) for vma in task.mm.get_mmap_iter(): flags = vma.get_protection() page_offset = vma.get_page_offset() major = 0 minor = 0 inode = 0 if vma.vm_file != 0: dentry = vma.vm_file.get_dentry() if dentry != 0: inode_object = dentry.d_inode major = inode_object.i_sb.major minor = inode_object.i_sb.minor inode = inode_object.i_ino path = vma.get_name(self.context, task) yield (0, (task.pid, name, format_hints.Hex(vma.vm_start), format_hints.Hex(vma.vm_end), flags, format_hints.Hex(page_offset), major, minor, inode, path))
def list_kernel_events(cls, context: interfaces.context.ContextInterface, layer_name: str, darwin_symbols: str, filter_func: Callable[[int], bool] = lambda _: False) -> \ Iterable[Tuple[interfaces.objects.ObjectInterface, interfaces.objects.ObjectInterface, interfaces.objects.ObjectInterface]]: """ Returns the kernel event filters registered Return values: A tuple of 3 elements: 1) The name of the process that registered the filter 2) The process ID of the process that registered the filter 3) The object of the associated kernel event filter """ kernel = contexts.Module(context, darwin_symbols, layer_name, 0) list_tasks = pslist.PsList.get_list_tasks( pslist.PsList.pslist_methods[0]) for task in list_tasks(context, layer_name, darwin_symbols, filter_func): task_name = utility.array_to_string(task.p_comm) pid = task.p_pid for kn in cls._get_task_kevents(kernel, task): yield task_name, pid, kn
def is_valid(self): try: cmd = self.get_command() ts = utility.array_to_string(self.timestamp.dereference()) except exceptions.InvalidAddressException: return False if not cmd or len(cmd) == 0: return False if not ts or len(ts) == 0: return False # At this point in time, the epoc integer size will # never be less than 10 characters, and the stamp is # always preceded by a pound/hash character. if len(ts) < 10 or str(ts)[0] != "#": return False # The final check is to make sure the entire string # is composed of numbers. Try to convert to an int. try: int(str(ts)[1:]) except ValueError: return False return True
def _generator(self, tasks): # determine if we're on a 32 or 64 bit kernel if self.context.symbol_space.get_type(self.config["vmlinux"] + constants.BANG + "pointer").size == 4: is_32bit_arch = True else: is_32bit_arch = False for task in tasks: process_name = utility.array_to_string(task.comm) for vma, data in self._list_injections(task): if is_32bit_arch: architecture = "intel" else: architecture = "intel64" disasm = interfaces.renderers.Disassembly( data, vma.vm_start, architecture) yield (0, (task.pid, process_name, format_hints.Hex(vma.vm_start), format_hints.Hex(vma.vm_end), vma.get_protection(), format_hints.HexBytes(data), disasm))
def _generator(self, tasks: Iterator[Any]) -> Generator[Tuple[int, Tuple[int, str, int, str]], None, None]: for task in tasks: proc_layer_name = task.add_process_layer() if proc_layer_name is None: continue proc_layer = self.context.layers[proc_layer_name] argsstart = task.user_stack - task.p_argslen if not proc_layer.is_valid(argsstart) or task.p_argslen == 0 or task.p_argc == 0: continue # Add one because the first two are usually duplicates argc = task.p_argc + 1 # smear protection if argc > 1024: continue task_name = utility.array_to_string(task.p_comm) args = [] # type: List[bytes] while argc > 0: try: arg = proc_layer.read(argsstart, 256) except exceptions.InvalidAddressException: break idx = arg.find(b'\x00') if idx != -1: arg = arg[:idx] argsstart += len(str(arg)) + 1 # deal with the stupid alignment (leading nulls) and arg duplication if len(args) == 0: while argsstart < task.user_stack: try: check = proc_layer.read(argsstart, 1) except exceptions.InvalidAddressException: break if check != b"\x00": break argsstart = argsstart + 1 args.append(arg) # also check for initial duplicates since OS X is painful elif arg != args[0]: args.append(arg) argc = argc - 1 args_str = " ".join([s.decode("utf-8") for s in args]) yield (0, (task.p_pid, task_name, task.p_argc, args_str))
def _generator(self, procs): for proc in procs: process_name = utility.array_to_string(proc.ImageFileName) try: proc_layer_name = proc.add_process_layer() except exceptions.InvalidAddressException: continue try: peb = self._context.object(self.config["nt_symbols"] + constants.BANG + "_PEB", layer_name=proc_layer_name, offset=proc.Peb) result_text = peb.ProcessParameters.CommandLine.get_string() except exceptions.SwappedInvalidAddressException as exp: result_text = "Required memory at {0:#x} is inaccessible (swapped)".format( exp.invalid_address) except exceptions.PagedInvalidAddressException as exp: result_text = "Required memory at {0:#x} is not valid (process exited?)".format( exp.invalid_address) except exceptions.InvalidAddressException as exp: result_text = "Required memory at {0:#x} is not valid (incomplete layer {1}?)".format( exp.invalid_address, exp.layer_name) yield (0, (proc.UniqueProcessId, process_name, result_text))
def _generator(self, procs): def passthrough(_: 'interfaces.objects.ObjectInterface') -> bool: return False filter_func = passthrough if self.config.get('address', None) is not None: def filter_function( x: 'interfaces.objects.ObjectInterface') -> bool: return x.get_start() not in [self.config['address']] filter_func = filter_function for proc in procs: process_name = utility.array_to_string(proc.ImageFileName) for vad in self.list_vads(proc, filter_func=filter_func): yield (0, (proc.UniqueProcessId, process_name, format_hints.Hex(vad.vol.offset), format_hints.Hex(vad.get_start()), format_hints.Hex(vad.get_end()), vad.get_tag(), vad.get_protection( self.protect_values(self.context, self.config['primary'], self.config['nt_symbols']), winnt_protections), vad.get_commit_charge(), vad.get_private_memory(), format_hints.Hex(vad.get_parent()), vad.get_file_name()))
def list_sockets(cls, context: interfaces.context.ContextInterface, layer_name: str, darwin_symbols: str, filter_func: Callable[[int], bool] = lambda _: False) -> \ Iterable[interfaces.objects.ObjectInterface]: """ Returns the open socket descriptors of a process Return values: A tuple of 3 elements: 1) The name of the process that opened the socket 2) The process ID of the processed that opened the socket 3) The address of the associated socket structure """ for task in tasks.Tasks.list_tasks(context, layer_name, darwin_symbols, filter_func): task_name = utility.array_to_string(task.p_comm) pid = task.p_pid for filp, _, _ in mac.MacUtilities.files_descriptors_for_process(context, darwin_symbols, task): try: ftype = filp.f_fglob.get_fg_type() except exceptions.InvalidAddressException: continue if ftype != 'SOCKET': continue try: socket = filp.f_fglob.fg_data.dereference().cast("socket") except exceptions.InvalidAddressException: continue yield task_name, pid, socket
def _generator(self): filter_func = tasks.Tasks.create_pid_filter([self.config.get('pid', None)]) for task_name, pid, socket in self.list_sockets(self.context, self.config['primary'], self.config['darwin'], filter_func = filter_func): family = socket.get_family() if family == 1: try: upcb = socket.so_pcb.dereference().cast("unpcb") path = utility.array_to_string(upcb.unp_addr.sun_path) except exceptions.InvalidAddressException: continue yield (0, (format_hints.Hex(socket.vol.offset), "UNIX", path, 0, "", 0, "", "{}/{:d}".format(task_name, pid))) elif family in [2, 30]: state = socket.get_state() proto = socket.get_protocol_as_string() vals = socket.get_converted_connection_info() if vals: (lip, lport, rip, rport) = vals yield (0, (format_hints.Hex(socket.vol.offset), proto, lip, lport, rip, rport, state, "{}/{:d}".format(task_name, pid)))
def _generator(self, procs): pe_table_name = intermed.IntermediateSymbolTable.create( self.context, self.config_path, "windows", "pe", class_types=pe.class_types) for proc in procs: try: proc_id = proc.UniqueProcessId process_name = utility.array_to_string(proc.ImageFileName) filedata = self.process_dump(self.context, self.config["nt_symbols"], pe_table_name, proc) self.produce_file(filedata) result_text = "Stored {}".format(filedata.preferred_filename) except ValueError: result_text = "PE parsing error" except exceptions.SwappedInvalidAddressException as exp: result_text = "Process {}: Required memory at {:#x} is inaccessible (swapped)".format( proc_id, exp.invalid_address) except exceptions.PagedInvalidAddressException as exp: result_text = "Process {}: Required memory at {:#x} is not valid (process exited?)".format( proc_id, exp.invalid_address) except exceptions.InvalidAddressException as exp: result_text = "Process {}: Required memory at {:#x} is not valid (incomplete layer {}?)".format( proc_id, exp.invalid_address, exp.layer_name) yield (0, (proc.UniqueProcessId, process_name, result_text))
def _generator(self): """ Lists the registered VFS event watching processes Also lists which event(s) a process is registered for """ kernel = contexts.Module(self.context, self.config['darwin'], self.config['primary'], 0) watcher_table = kernel.object_from_symbol("watcher_table") for watcher in watcher_table: if watcher == 0: continue task_name = utility.array_to_string(watcher.proc_name) task_pid = watcher.pid events = [] try: event_array = kernel.object(object_type = "array", offset = watcher.event_list, count = 13, subtype = kernel.get_type("unsigned char")) except exceptions.InvalidAddressException: continue for i, event in enumerate(event_array): if event == 1: events.append(self.event_types[i]) if events != []: yield (0, (task_name, task_pid, ",".join(events)))
def _generator(self, procs): def passthrough(_: interfaces.objects.ObjectInterface) -> bool: return False filter_func = passthrough if self.config.get('address', None) is not None: def filter_function(x: interfaces.objects.ObjectInterface) -> bool: return x.get_start() not in [self.config['address']] filter_func = filter_function for proc in procs: process_name = utility.array_to_string(proc.ImageFileName) for vad in self.list_vads(proc, filter_func = filter_func): file_output = "Disabled" if self.config['dump']: file_handle = self.vad_dump(self.context, proc, vad, self.open) file_output = "Error outputting file" if file_handle: file_handle.close() file_output = file_handle.preferred_filename yield (0, (proc.UniqueProcessId, process_name, format_hints.Hex(vad.vol.offset), format_hints.Hex(vad.get_start()), format_hints.Hex(vad.get_end()), vad.get_tag(), vad.get_protection( self.protect_values(self.context, self.config['primary'], self.config['nt_symbols']), winnt_protections), vad.get_commit_charge(), vad.get_private_memory(), format_hints.Hex(vad.get_parent()), vad.get_file_name(), file_output))
def _generator(self, procs): # determine if we're on a 32 or 64 bit kernel is_32bit_arch = not symbols.symbol_table_is_64bit( self.context, self.config["nt_symbols"]) for proc in procs: process_name = utility.array_to_string(proc.ImageFileName) for vad, data in self.list_injections(self.context, self.config["nt_symbols"], proc): # if we're on a 64 bit kernel, we may still need 32 bit disasm due to wow64 if is_32bit_arch or proc.get_is_wow64(): architecture = "intel" else: architecture = "intel64" disasm = interfaces.renderers.Disassembly( data, vad.get_start(), architecture) yield (0, (proc.UniqueProcessId, process_name, format_hints.Hex(vad.get_start()), format_hints.Hex(vad.get_end()), vad.get_tag(), vad.get_protection( vadinfo.VadInfo.protect_values( self.context, proc.vol.layer_name, self.config["nt_symbols"]), vadinfo.winnt_protections), vad.get_commit_charge(), vad.get_private_memory(), format_hints.HexBytes(data), disasm))
def __init__(self, task, sshenc, addr): self.task = task self.task_name = utility.array_to_string(task.comm) self.sshenc_addr = addr self.enc_name = None self.key = None self.iv = None self.sshenc = sshenc
def _generator(self, tasks): for task in tasks: name = utility.array_to_string(task.comm) pid = int(task.pid) for fd_num, _, full_path in linux.LinuxUtilities.files_descriptors_for_process( self.config, self.context, task): yield (0, (pid, name, fd_num, full_path))
def _generator(self): for module in self.list_modules(self.context, self.config['primary'], self.config['darwin']): mod_name = utility.array_to_string(module.name) mod_size = module.size yield 0, (format_hints.Hex(module.vol.offset), mod_name, mod_size)
def _generator(self, tasks): is_32bit = not symbols.symbol_table_is_64bit(self.context, self.config["darwin"]) if is_32bit: pack_format = "I" bash_json_file = "bash32" else: pack_format = "Q" bash_json_file = "bash64" bash_table_name = BashIntermedSymbols.create(self.context, self.config_path, "linux", bash_json_file) ts_offset = self.context.symbol_space.get_type( bash_table_name + constants.BANG + "hist_entry").relative_child_offset("timestamp") for task in tasks: task_name = utility.array_to_string(task.p_comm) if task_name not in ["bash", "sh", "dash"]: continue proc_layer_name = task.add_process_layer() if proc_layer_name is None: continue proc_layer = self.context.layers[proc_layer_name] bang_addrs = [] # find '#' values on the heap for address in proc_layer.scan( self.context, scanners.BytesScanner(b"#"), sections=task.get_process_memory_sections( self.context, self.config['darwin'], rw_no_file=True)): bang_addrs.append(struct.pack(pack_format, address)) history_entries = [] for address, _ in proc_layer.scan( self.context, scanners.MultiStringScanner(bang_addrs), sections=task.get_process_memory_sections( self.context, self.config['darwin'], rw_no_file=True)): hist = self.context.object(bash_table_name + constants.BANG + "hist_entry", offset=address - ts_offset, layer_name=proc_layer_name) if hist.is_valid(): history_entries.append(hist) for hist in sorted(history_entries, key=lambda x: x.get_time_as_integer()): yield (0, (int(task.p_pid), task_name, hist.get_time_object(), hist.get_command()))
def _generator(self, tasks): for task in tasks: task_name = utility.array_to_string(task.p_comm) pid = task.p_pid for filp, _, _ in mac.MacUtilities.files_descriptors_for_process( self.config, self.context, task): try: ftype = filp.f_fglob.get_fg_type() except exceptions.InvalidAddressException: continue if ftype != 'DTYPE_SOCKET': continue try: socket = filp.f_fglob.fg_data.dereference().cast("socket") except exceptions.InvalidAddressException: continue family = socket.get_family() if family == 1: try: upcb = socket.so_pcb.dereference().cast("unpcb") path = utility.array_to_string(upcb.unp_addr.sun_path) except exceptions.InvalidAddressException: continue yield (0, (format_hints.Hex(socket.vol.offset), "UNIX", path, 0, "", 0, "", "{}/{:d}".format(task_name, pid))) elif family in [2, 30]: state = socket.get_state() proto = socket.get_protocol_as_string() vals = socket.get_converted_connection_info() if vals: (lip, lport, rip, rport) = vals yield (0, (format_hints.Hex(socket.vol.offset), proto, lip, lport, rip, rport, state, "{}/{:d}".format(task_name, pid)))
def _generator(self): for module in self.list_modules(self.context, self.config['primary'], self.config['vmlinux']): mod_size = module.get_init_size() + module.get_core_size() mod_name = utility.array_to_string(module.name) yield 0, (format_hints.Hex(module.vol.offset), mod_name, mod_size)
def __init__(self, context, openssh_table_name, proc_layer_name, task, progress_callback): self.context = context self.openssh_table_name = openssh_table_name self.proc_layer_name = proc_layer_name self.proc_layer = self.context.layers[proc_layer_name] self.task = task self.task_name = utility.array_to_string(task.comm) self.openssh_symbols = self.context.symbol_space[openssh_table_name] self.progress_callback = progress_callback
def _check_header(self) -> Optional[Tuple[str, interfaces.objects.ObjectInterface]]: """Verifies the header of the PDB file and returns the version of the file.""" for header in self._headers: header_type = self.pdb_symbol_table + constants.BANG + header current_header = self.context.object(header_type, self._base_layer, 0) if utility.array_to_string(current_header.Magic) == self._headers[header]: if not (current_header.PageSize < 0x100 or current_header.PageSize > (128 * 0x10000)): return header, current_header return None
def _generator(self): for task in self.list_tasks(self.context, self.config['primary'], self.config['darwin'], filter_func=self.create_pid_filter( [self.config.get('pid', None)])): pid = task.p_pid ppid = task.p_ppid name = utility.array_to_string(task.p_comm) yield (0, (pid, ppid, name))
def _generator(self, mods: Iterator[Any]): mac.MacUtilities.aslr_mask_symbol_table(self.context, self.config['darwin'], self.config['primary']) kernel = contexts.Module(self._context, self.config['darwin'], self.config['primary'], 0) policy_list = kernel.object_from_symbol( symbol_name="mac_policy_list").cast("mac_policy_list") entries = kernel.object( object_type="array", offset=policy_list.entries.dereference().vol.offset, subtype=kernel.get_type('mac_policy_list_element'), count=policy_list.staticmax + 1) mask = self.context.layers[self.config['primary']].address_mask mods_list = [(mod.name, mod.address & mask, (mod.address & mask) + mod.size) for mod in mods] for i, ent in enumerate(entries): # I don't know how this can happen, but the kernel makes this check all over the place # the policy isn't useful without any ops so a rootkit can't abuse this try: mpc = ent.mpc.dereference() ops = mpc.mpc_ops.dereference() except exceptions.InvalidAddressException: continue try: ent_name = utility.pointer_to_string(mpc.mpc_name, 255) except exceptions.InvalidAddressException: ent_name = "N/A" for check in ops.vol.members: call_addr = getattr(ops, check) if call_addr is None or call_addr == 0: continue found_module = None for mod_name_info, mod_base, mod_end in mods_list: if call_addr >= mod_base and call_addr <= mod_end: found_module = mod_name_info break if found_module: symbol_module = utility.array_to_string(found_module) else: symbol_module = "UNKNOWN" yield (0, (check, ent_name, symbol_module, format_hints.Hex(call_addr)))
def _generator(self, procs): pe_table_name = intermed.IntermediateSymbolTable.create( self.context, self.config_path, "windows", "pe", class_types=pe.class_types) for proc in procs: process_name = utility.array_to_string(proc.ImageFileName) try: proc_layer_name = proc.add_process_layer() except exceptions.InvalidAddressException: continue try: peb = self._context.object(self.config["nt_symbols"] + constants.BANG + "_PEB", layer_name=proc_layer_name, offset=proc.Peb) dos_header = self.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) self.produce_file(filedata) result_text = "Stored {}".format(filedata.preferred_filename) except ValueError: result_text = "PE parsing error" except exceptions.SwappedInvalidAddressException as exp: result_text = "Required memory at {0:#x} is inaccessible (swapped)".format( exp.invalid_address) except exceptions.PagedInvalidAddressException as exp: result_text = "Required memory at {0:#x} is not valid (process exited?)".format( exp.invalid_address) except exceptions.InvalidAddressException as exp: result_text = "Required memory at {0:#x} is not valid (incomplete layer {1}?)".format( exp.invalid_address, exp.layer_name) yield (0, (proc.UniqueProcessId, process_name, result_text))
def _generator(self, procs): pe_table_name = intermed.IntermediateSymbolTable.create(self.context, self.config_path, "windows", "pe", class_types = extensions.pe.class_types) filter_func = lambda _: False if self.config.get('address', None) is not None: filter_func = lambda x: x.get_start() not in [self.config['address']] for proc in procs: process_name = utility.array_to_string(proc.ImageFileName) # TODO: what kind of exceptions could this raise and what should we do? proc_layer_name = proc.add_process_layer() for vad in vadinfo.VadInfo.list_vads(proc, filter_func = filter_func): # this parameter is inherited from the VadInfo plugin. if a user specifies # an address, then it bypasses the DLL identification heuristics if self.config.get("address", None) is None: # rather than relying on the PEB for DLLs, which can be swapped, # it requires special handling on wow64 processes, and its # unreliable from an integrity standpoint, let's use the VADs instead protection_string = vad.get_protection( vadinfo.VadInfo.protect_values(self.context, self.config['primary'], self.config['nt_symbols']), vadinfo.winnt_protections) # DLLs are write copy... if protection_string != "PAGE_EXECUTE_WRITECOPY": continue # DLLs have mapped files... if isinstance(vad.get_file_name(), interfaces.renderers.BaseAbsentValue): continue try: filedata = interfaces.plugins.FileInterface("pid.{0}.{1}.{2:#x}.dmp".format( proc.UniqueProcessId, ntpath.basename(vad.get_file_name()), vad.get_start())) dos_header = self.context.object(pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER", offset = vad.get_start(), layer_name = proc_layer_name) for offset, data in dos_header.reconstruct(): filedata.data.seek(offset) filedata.data.write(data) self.produce_file(filedata) result_text = "Stored {}".format(filedata.preferred_filename) except Exception: result_text = "Unable to dump PE at {0:#x}".format(vad.get_start()) yield (0, (proc.UniqueProcessId, process_name, result_text))