def list_plugins(): result = "\n\tSupported Plugin Commands:\n\n" cmds = registry.get_plugin_classes(commands.Command, lower = True) profs = registry.get_plugin_classes(obj.Profile) if config.PROFILE == None: config.update("PROFILE", "WinXPSP2x86") if config.PROFILE not in profs: raise BaseException("Invalid profile " + config.PROFILE + " selected") profile = profs[config.PROFILE]() wrongprofile = "" for cmdname in sorted(cmds): command = cmds[cmdname] helpline = command.help() or '' ## Just put the title line (First non empty line) in this ## abbreviated display for line in helpline.splitlines(): if line: helpline = line break if command.is_valid_profile(profile): result += "\t\t{0:15}\t{1}\n".format(cmdname, helpline) else: wrongprofile += "\t\t{0:15}\t{1}\n".format(cmdname, helpline) if wrongprofile and config.VERBOSE: result += "\n\tPlugins requiring a different profile:\n\n" result += wrongprofile return result
def list_plugins(): result = "\n\tSupported Plugin Commands:\n\n" cmds = registry.get_plugin_classes(commands.Command, lower = True) profs = registry.get_plugin_classes(obj.Profile) if config.PROFILE not in profs: raise BaseException("Invalid profile " + config.PROFILE + " selected") profile = profs[config.PROFILE]() wrongprofile = "" for cmdname in sorted(cmds): command = cmds[cmdname] helpline = command.help() or '' ## Just put the title line (First non empty line) in this ## abbreviated display for line in helpline.splitlines(): if line: helpline = line break if command.is_valid_profile(profile): result += "\t\t{0:15}\t{1}\n".format(cmdname, helpline) else: wrongprofile += "\t\t{0:15}\t{1}\n".format(cmdname, helpline) if wrongprofile and config.VERBOSE: result += "\n\tPlugins requiring a different profile:\n\n" result += wrongprofile return result
def init_config(self): """ Volatility 설정 초기화 :return: """ if self.config is not None and self.addr_space is not None: return self.config self.config = conf.ConfObject() self.config.optparser.set_conflict_handler("resolve") registry.register_global_options(self.config, commands.Command) registry.register_global_options(self.config, addrspace.BaseAddressSpace) base_conf = { "profile": "WinXPSP2x86", "use_old_as": None, "kdbg": None, "help": False, "kpcr": None, "tz": None, "pid": None, "output_file": None, "physical_offset": None, "conf_file": None, "dtb": None, "output": None, "info": None, "location": "file://" + self.memdump, "plugins": 'plugins', "debug": 4, "filename": None, "cache_directory": None, "verbose": None, "write": False } self.config.parse_options() if self.osprofile: base_conf["profile"] = self.osprofile self.update_config(base_conf) # 사용가능한 플러그인 목록 저장 # self.plugins = Dictionary # key: 플러그인 클래스 이름 # value: 플러그인 클래스 인스턴스 self.plugins = registry.get_plugin_classes(commands.Command, lower=True) profs = registry.get_plugin_classes(obj.Profile) profile = profs[self.config.PROFILE]() # self.plugins에서 플러그인 리스트 추출 for cmd_name, command in self.plugins.items(): if command.is_valid_profile(profile): self.plugin_list.append(cmd_name) return self.config
def list_plugins(self): plugin_list = [] cmds = registry.get_plugin_classes(commands.Command, lower=True) profs = registry.get_plugin_classes(obj.Profile) profile_type = self.config.PROFILE if profile_type not in profs: print "Not a valid profile" profile = profs[profile_type]() for cmdname in sorted(cmds): command = cmds[cmdname] helpline = command.help() or '' if command.is_valid_profile(profile): plugin_list.append([cmdname, helpline]) return plugin_list
def print_info(): """ Returns the results """ categories = {addrspace.BaseAddressSpace: 'Address Spaces', commands.Command : 'Plugins', obj.Profile: 'Profiles', scan.ScannerCheck: 'Scanner Checks'} for c, n in sorted(categories.items()): lower = (c == commands.Command) plugins = registry.get_plugin_classes(c, lower = lower) print "\n" print "{0}".format(n) print "-" * len(n) result = [] max_length = 0 for clsname, cls in sorted(plugins.items()): try: doc = cls.__doc__.strip().splitlines()[0] except AttributeError: doc = 'No docs' result.append((clsname, doc)) max_length = max(len(clsname), max_length) for (name, doc) in result: print "{0:{2}} - {1:15}".format(name, doc, max_length)
def execute(self): """ Executes the plugin command.""" # Check we can support the plugins profs = registry.get_plugin_classes(obj.Profile) if self._config.PROFILE not in profs: debug.error("Invalid profile " + self._config.PROFILE + " selected") if not self.is_valid_profile(profs[self._config.PROFILE]()): debug.error("This command does not support the profile " + self._config.PROFILE) # # Executing plugins is done in two stages - first we calculate data = self.calculate() ## Then we render the result in some way based on the ## requested output mode: function_name = "render_{0}".format(self._config.OUTPUT) if self._config.OUTPUT_FILE: outfd = open(self._config.OUTPUT_FILE, 'w') # TODO: We should probably check that this won't blat over an existing file else: outfd = sys.stdout try: func = getattr(self, function_name) except AttributeError: ## Try to find out what formats are supported result = [] for x in dir(self): if x.startswith("render_"): _a, b = x.split("_", 1) result.append(b) print "Plugin {0} is unable to produce output in format {1}. Supported formats are {2}. Please send a feature request".format(self.__class__.__name__, self._config.OUTPUT, result) return func(outfd, data)
def runModule(self, moduleName): #print self.profile if self.profile == 'Use Imageinfo': retValtxt = self.imageinfo() return retObj(True, retValtxt) elif moduleName == 'procdump': retValtxt = self.procdump() return retObj(True, None) else: cmds = registry.get_plugin_classes(commands.Command, lower=True) command = cmds[moduleName](self.config) try: calc = command.calculate() command.render_sqlite(self.config.OUTPUT_FILE, calc) return retObj(True, None) except Exception as err: print err.message return retObj(None, None)
def calculate(self): """Determines the address space""" profilelist = [ p.__name__ for p in registry.get_plugin_classes(obj.Profile).values() ] encrypted_kdbg_profiles = [] proflens = {} maxlen = 0 origprofile = self._config.PROFILE for p in profilelist: self._config.update('PROFILE', p) buf = addrspace.BufferAddressSpace(self._config) if buf.profile.metadata.get('os', 'unknown') == 'windows': proflens[p] = str(obj.VolMagic(buf).KDBGHeader) maxlen = max(maxlen, len(proflens[p])) if (buf.profile.metadata.get('memory_model', '64bit') == '64bit' and (buf.profile.metadata.get('major', 0), buf.profile.metadata.get('minor', 0)) >= (6, 2)): encrypted_kdbg_profiles.append(p) self._config.update('PROFILE', origprofile) # keep track of the number of potential KDBGs we find count = 0 if origprofile not in encrypted_kdbg_profiles: scanner = KDBGScanner(needles = proflens.values()) aspace = utils.load_as(self._config, astype = 'any') suspects = [] for offset in scanner.scan(aspace): val = aspace.read(offset, maxlen + 0x10) for l in proflens: if val.find(proflens[l]) >= 0: kdbg = obj.Object("_KDDEBUGGER_DATA64", offset = offset, vm = aspace) suspects.append((l, kdbg)) count += 1 for p, k in suspects: if not self._config.FORCE: yield p, k continue self._config.update("PROFILE", p) nspace = utils.load_as(self._config, astype = "any") for offset in scanner.scan(nspace): val = nspace.read(offset, maxlen + 0x10) if val.find(proflens[p]) >= 0: kdbg = obj.Object("_KDDEBUGGER_DATA64", offset = offset, vm = nspace) yield p, kdbg self._config.update('PROFILE', origprofile) # only perform the special win8/2012 scan if we didn't find # any others and if a virtual x64 address space is available if count == 0: if origprofile in encrypted_kdbg_profiles: encrypted_kdbg_profiles = [origprofile] for profile in encrypted_kdbg_profiles: self._config.update('PROFILE', profile) aspace = utils.load_as(self._config, astype = 'any') if hasattr(aspace, 'vtop'): for kdbg in obj.VolMagic(aspace).KDBG.generate_suggestions(): yield profile, kdbg
def load_as(config, astype = 'virtual', **kwargs): """Loads an address space by stacking valid ASes on top of each other (priority order first)""" base_as = None error = exceptions.AddrSpaceError() # Start off requiring another round found = True ## A full iteration through all the classes without anyone ## selecting us means we are done: while found: debug.debug("Voting round") found = False for cls in sorted(registry.get_plugin_classes(addrspace.BaseAddressSpace).values(), key = lambda x: x.order if hasattr(x, 'order') else 10): debug.debug("Trying {0} ".format(cls)) try: base_as = cls(base_as, config, astype = astype, **kwargs) debug.debug("Succeeded instantiating {0}".format(base_as)) found = True break except addrspace.ASAssertionError, e: debug.debug("Failed instantiating {0}: {1}".format(cls.__name__, e), 2) error.append_reason(cls.__name__, e) continue except Exception, e: debug.debug("Failed instantiating (exception): {0}".format(e)) error.append_reason(cls.__name__ + " - EXCEPTION", e) continue
def guess_profile(self, memimg): ''' Using one of the user-specified memory image files, try to guess a working Volatility profile. This can easily take on the order of minutes. @memimg: a memory image file name @return: the guessed Volatiltiy profile string ''' sys.stderr.write("Auto configuring profile. This may take a some time.\n") self.set_memimg(memimg) # Must set a dummy profile or volatility dies self.set_profile('WinXPSP2x86') chosen = None profilelist = [p.__name__ for p in registry.get_plugin_classes(obj.Profile).values()] for profile in profilelist: self.config.update('profile', profile) addr_space = utils.load_as(self.config, astype='any') if hasattr(addr_space, "dtb"): chosen = profile break return chosen
def _run_all_checks(self, checks, pool_header): """Execute all constraint checks. @param checks: a dictionary with check names as keys and another dictionary of arguments as the values. @param pool_header: the target _POOL_HEADER to check @returns False if any checks fail, otherwise True. """ for check, args in checks: if check == "CheckPoolSize": if not self._check_pool_size(args, pool_header): return False elif check == "CheckPoolType": if not self._check_pool_type(args, pool_header): return False elif check == "CheckPoolIndex": if not self._check_pool_index(args, pool_header): return False else: custom_check = registry.get_plugin_classes(scan.ScannerCheck)[ check ](pool_header.obj_vm, **args) return custom_check.check(pool_header.PoolTag.obj_offset) return True
def load_as(config, astype='virtual', **kwargs): """Loads an address space by stacking valid ASes on top of each other (priority order first)""" base_as = None error = exceptions.AddrSpaceError() # Start off requiring another round found = True ## A full iteration through all the classes without anyone ## selecting us means we are done: while found: debug.debug("Voting round") found = False for cls in sorted(registry.get_plugin_classes( addrspace.BaseAddressSpace).values(), key=lambda x: x.order if hasattr(x, 'order') else 10): debug.debug("Trying {0} ".format(cls)) try: base_as = cls(base_as, config, astype=astype, **kwargs) debug.debug("Succeeded instantiating {0}".format(base_as)) found = True break except addrspace.ASAssertionError, e: debug.debug( "Failed instantiating {0}: {1}".format(cls.__name__, e), 2) error.append_reason(cls.__name__, e) continue except Exception, e: debug.debug("Failed instantiating (exception): {0}".format(e)) error.append_reason(cls.__name__ + " - EXCEPTION", e) continue
def calculate(self): """Determines the address space""" profilelist = [ p.__name__ for p in registry.get_plugin_classes(obj.Profile).values() ] proflens = {} maxlen = 0 origprofile = self._config.PROFILE for p in profilelist: self._config.update('PROFILE', p) buf = addrspace.BufferAddressSpace(self._config) if buf.profile.metadata.get('os', 'unknown') == 'windows': proflens[p] = str(obj.VolMagic(buf).KDBGHeader) maxlen = max(maxlen, len(proflens[p])) self._config.update('PROFILE', origprofile) scanner = KDBGScanner(needles=proflens.values()) aspace = utils.load_as(self._config, astype='any') for offset in scanner.scan(aspace): val = aspace.read(offset, maxlen + 0x10) for l in proflens: if val.find(proflens[l]) >= 0: kdbg = obj.Object("_KDDEBUGGER_DATA64", offset=offset, vm=aspace) yield l, kdbg
def __init__(self): # Get the version information on every output from the beginning # Exceptionally useful for debugging/telling people what's going on #sys.stderr.write("Volatile Systems Volatility Framework {0}\n".format(constants.VERSION)) #sys.stderr.flush() self.config.add_option("INFO", default = None, action = "store_true", cache_invalidator = False, help = "Print information about all registered objects") # Setup the debugging format debug.setup() # Load up modules in case they set config options registry.PluginImporter() ## Register all register_options for the various classes registry.register_global_options(self.config, addrspace.BaseAddressSpace) registry.register_global_options(self.config, commands.Command) # Reset the logging level now we know whether debug is set or not debug.setup(self.config.DEBUG) #pdb.set_trace() ## Try to find the first thing that looks like a module name self.cmds = registry.get_plugin_classes(commands.Command, lower = True)
def search_stack_frames(self, start, stack_base, stack_limit, yara_rules, frame_delta=32, unwind=DEFAULT_UNWIND): """ Use Yara to search kernel/user stack frames within +/- frame_delta of the frame's start address. Frames to search are chosen by using the strategies specifed by the unwind parameter. yara_rules - compiled Yara rules, built for example with: 1. yara.compile("/path/to/yara.rules") or 2. yara.compile(source="rule dummy { condition: true }") """ if not yara_installed: debug.error("In order to search the stack frames, it is necessary to install yara") stack_registry = registry.get_plugin_classes(StackTop) for unwind_strategy_nm in unwind.split(","): if unwind_strategy_nm not in stack_registry: raise ValueError("{0} is not a known stack unwind strategy".format(unwind_strategy_nm)) unwind_strategy = stack_registry[unwind_strategy_nm](start, stack_base, stack_limit, self) for frame in itertools.chain(unwind_strategy.up(), unwind_strategy.down()): search_data = self.get_process_address_space().zread(frame.start - frame_delta, 2* frame_delta) for match in yara_rules.match(data = search_data): for moffset, name, value in match.strings: # Match offset here is converted into frame start address and a +/- frame_delta yield match, name, value, frame.start, moffset-frame_delta raise StopIteration
def guess_profile(self, memimg): ''' Using one of the user-specified memory image files, try to guess a working Volatility profile. This can easily take on the order of minutes. @memimg: a memory image file name @return: the guessed Volatiltiy profile string ''' sys.stderr.write( "Auto configuring profile. This may take a some time.\n") self.set_memimg(memimg) # Must set a dummy profile or volatility dies self.set_profile('WinXPSP2x86') chosen = None profilelist = [ p.__name__ for p in registry.get_plugin_classes(obj.Profile).values() ] for profile in profilelist: self.config.update('profile', profile) addr_space = utils.load_as(self.config, astype='any') if hasattr(addr_space, "dtb"): chosen = profile break return chosen
def _run_all_checks(self, checks, pool_header): """Execute all constraint checks. @param checks: a dictionary with check names as keys and another dictionary of arguments as the values. @param pool_header: the target _POOL_HEADER to check @returns False if any checks fail, otherwise True. """ for check, args in checks: if check == "CheckPoolSize": if not self._check_pool_size(args, pool_header): return False elif check == "CheckPoolType": if not self._check_pool_type(args, pool_header): return False elif check == "CheckPoolIndex": if not self._check_pool_index(args, pool_header): return False else: custom_check = registry.get_plugin_classes(scan.ScannerCheck)[check](pool_header.obj_vm, **args) return custom_check.check(pool_header.PoolTag.obj_offset) return True
def render_text(self, outfd, data): checks = registry.get_plugin_classes(MalthfindRule) for thread, addr_space, thread_start_function, thread_callstack in data: has_comment = False s = "\n------\n\n" s += "ETHREAD: {0:#010x} Pid: {1} Tid: {2}\n".format( thread.obj_offset, thread.Cid.UniqueProcess, thread.Cid.UniqueThread) s += "Owning Process: {0}\n".format( thread.owning_process().ImageFileName) s += "Attached Process: {0}\n".format( thread.attached_process().ImageFileName) s += "Thread Flags: {0}\n".format(str(thread.CrossThreadFlags)) # get all currently implemented rules # and run them against the threads callstack for cls_name, cls in checks.items(): thread_callstack = cls(thread_callstack).check() if len(thread_callstack.mal_pattern) > 0: if len(thread_callstack.callstack) > 0: s += "Malicious patterns detected: " first_pattern = True for pattern in thread_callstack.mal_pattern: if first_pattern: s += pattern first_pattern = False else: s += ", " + pattern s += "\nCallstack:\n" if thread_callstack.eip: s += "\t{0:<8} {3:<8} {1:<8} {2}\n".format("No.", "RetAddr", "Function", "Ebp") s += "\t{0:<8} 0x{5:08x} 0x{1:08x} {2}!{3}+0x{4:<8x}\n".format("[eip]", thread_callstack.callstack[0].function.address, thread_callstack.callstack[0].owning_module_name, thread_callstack.callstack[0].function.name, thread_callstack.callstack[0].ret_address - thread_callstack.callstack[0].function.address, 0) thread_callstack.callstack.remove(thread_callstack.callstack[0]) i = 0 for item in thread_callstack.callstack: s += "\t{0:<8} 0x{5:08x} 0x{1:08x} {2}!{3}+0x{4:<8x}\n".format("[" + str(i) + "]", item.function.address, item.owning_module_name, item.function.name, item.ret_address - item.function.address, item.frame_address) i += 1 if item.comment != "": has_comment = True else: s += "Couldn't acquire threads _KTRAP_FRAME\n" if has_comment: outfd.write("{0}\n".format(s))
def __init__(self): # Get the version information on every output from the beginning # Exceptionally useful for debugging/telling people what's going on #sys.stderr.write("Volatile Systems Volatility Framework {0}\n".format(constants.VERSION)) #sys.stderr.flush() self.config = conf.ConfObject() self.cmds = {} #self.profile = "--profile=Linuxcentos5_5x86" self.vmprocessMap = {} self.config.add_option("INFO", default = None, action = "store_true", cache_invalidator = False, help = "Print information about all registered objects") # Setup the debugging format debug.setup() # Load up modules in case they set config options registry.PluginImporter() ## Register all register_options for the various classes registry.register_global_options(self.config, addrspace.BaseAddressSpace) registry.register_global_options(self.config, commands.Command) # Reset the logging level now we know whether debug is set or not debug.setup(self.config.DEBUG) #pdb.set_trace() ## Try to find the first thing that looks like a module name self.cmds = registry.get_plugin_classes(commands.Command, lower = True)
def calculate(self): """Determines the address space""" profilelist = [ p.__name__ for p in registry.get_plugin_classes(obj.Profile).values() ] proflens = {} maxlen = 0 origprofile = self._config.PROFILE for p in profilelist: self._config.update('PROFILE', p) buf = addrspace.BufferAddressSpace(self._config) if buf.profile.metadata.get('os', 'unknown') == 'windows': proflens[p] = str(obj.VolMagic(buf).KDBGHeader) maxlen = max(maxlen, len(proflens[p])) self._config.update('PROFILE', origprofile) scanner = KDBGScanner(needles = proflens.values()) aspace = utils.load_as(self._config, astype = 'any') for offset in scanner.scan(aspace): val = aspace.read(offset, maxlen + 0x10) for l in proflens: if val.find(proflens[l]) >= 0: kdbg = obj.Object("_KDDEBUGGER_DATA64", offset = offset, vm = aspace) yield l, kdbg
def run_plugin(self, plugin_name, pid=None, dump_dir=None, plugin_options=None, hive_offset=None, output_style="json"): # Get Valid commands cmds = registry.get_plugin_classes(commands.Command, lower=True) if plugin_name in cmds.keys(): command = cmds[plugin_name] # Set PID self.config.PID = pid self.config.DUMP_DIR = dump_dir self.config.hive_offset = hive_offset # Add any other options if plugin_options: for option, value in plugin_options.iteritems(): self.config.update(option, value) # Plugins with specific output types if plugin_name == 'pstree': output_data = self.get_dot(command) return output_data # Just for imageinfo as it occasionally throws unicode errors at me elif plugin_name == 'imageinfo': output_data = self.get_text(command) return output_data elif plugin_name == 'memdump': if not pid: return None output_data = self.get_text(command) return output_data elif plugin_name == 'dumpfiles': if 'PHYSOFFSET' not in plugin_options: logger.debug('No Offset Provided') return None print self.config.REGEX output_data = self.get_text(command) print "a" print output_data return output_data # All other plugins else: if output_style == 'json': output_data = self.get_json(command) return output_data if output_style == 'text': output_data = self.get_text(command) return output_data else: return 'Error: Not a valid plugin'
def execute(self): """ Executes the plugin command.""" # Check we can support the plugins profs = registry.get_plugin_classes(obj.Profile) # force user to give a profile if a plugin # other than kdbgscan or imageinfo are given: plugin_name = self.__class__.__name__.lower() if plugin_name != "mac_get_profile": if self._config.PROFILE == None: if plugin_name in ["kdbgscan", "imageinfo"]: self._config.update("PROFILE", "WinXPSP2x86") else: debug.error("You must set a profile!") if self._config.PROFILE not in profs: debug.error(f"Invalid profile {self._config.PROFILE} selected") if not self.is_valid_profile(profs[self._config.PROFILE]()): debug.error( f"This command does not support the profile {self._config.PROFILE}" ) # # Executing plugins is done in two stages - first we calculate data = self.calculate() ## Then we render the result in some way based on the ## requested output mode: function_name = "render_{0}".format(self._config.OUTPUT) if not self._config.OUTPUT == "sqlite" and self._config.OUTPUT_FILE: out_file = (f"{time.strftime('%Y%m%d%H%M%S')}_{plugin_name}.txt" if self._config.OUTPUT_FILE == '.' else self._config.OUTPUT_FILE) if os.path.exists(out_file): debug.error( f"File {out_file} already exists. Cowardly refusing to overwrite it..." ) print(f"Outputting to: {out_file}") outfd = open(out_file, 'wb') else: outfd = sys.stdout try: func = getattr(self, function_name) except AttributeError: ## Try to find out what formats are supported result = [] for x in dir(self): if x.startswith("render_"): _a, b = x.split("_", 1) result.append(b) print( f"Plugin {self.__class__.__name__} is unable to produce output in format {self._config.OUTPUT}. Supported formats are {result}. Please send a feature request" ) return func(outfd, data)
def load_volatility_plugins(self): cmds = registry.get_plugin_classes(commands.Command, lower=True) for plugin_name in cmds: if cmds[plugin_name].is_valid_profile( self.addrspace.profile) and plugin_name is not 'tprobe': # TODO: passing config causes option overlapping so we need class similiar to config but not a singleton, rather a copy of config per each plugin # AbstractVolatilityPluginWrapper(self.functions, self.config, cmds[plugin_name]) AbstractVolatilityPluginWrapper(self, LocalConfig(self.config), cmds[plugin_name])
def __init__(self, dump, apps, syst, out_dir="files", plugins_dir=None, from_cache=True): """ Determines the profile, retrieves the list of processes and creates the list of application dumpers. :param dump: Volatility memory dump filename :param apps: list of the application dumper classes to be handled :param syst: list of the system dumper classes to be handled :param out_dir: output directory for retrieved resources :param plugins_dir: Volatility custom plugins directory :param from_cache: boolean indicating if the profile must be retrieved from a cache file in /tmp or found by Volatility """ short = dump dump = abspath(dump) assert isfile(dump), "{} is not a dump file".format(dump) assert all(x in APPDUMPERS for x in apps), "Unknown application dumper(s)" assert all(x in SYSDUMPERS for x in syst), "Unknown system dumper(s)" assert plugins_dir is None or isdir(plugins_dir), "Bad plugins dir" assert isinstance(from_cache, bool) self._artifacts = [] self._cache = {} self._selected_apps = apps self._selected_syst = syst if len(self._selected_apps) == 0 and len(self._selected_syst) == 0: logger.warning("No dumper selected") sys.exit(0) logger.debug("Setting output directory to '{}'...".format(out_dir)) self.out_dir = abspath(out_dir) if not exists(self.out_dir): os.makedirs(self.out_dir) self._cachefile = join(self.out_dir, ".cache") # initialize dump opening registry.PluginImporter() self.__is_profile_tested = False self.config = conf.ConfObject() if plugins_dir is not None: plugins_dir = expanduser(plugins_dir) logger.debug( "Setting plugins directory to '{}'...".format(plugins_dir)) self.config.plugins = abspath(plugins_dir) for cls in [commands.Command, addrspace.BaseAddressSpace]: registry.register_global_options(self.config, cls) self.__commands = {k.lower(): v for k, v in \ registry.get_plugin_classes(commands.Command).items()} self.config.LOCATION = "file://{}".format(dump) # get the right dump profile and test it while getting processes logger.info("Opening dump file '{}'...".format(short)) self.__is_profile_tested = self.__get_profile(from_cache)
def profile_list(): """ Return a list of available Profiles :return: """ prof_list = ['AutoDetect'] profs = registry.get_plugin_classes(obj.Profile) for profile in profs.iterkeys(): prof_list.append(profile) return sorted(prof_list)
def profile_list(self): """ return a list of profiles :return: list """ prof_list = [] profs = registry.get_plugin_classes(obj.Profile) for profile in profs.iterkeys(): prof_list.append(profile) return sorted(prof_list)
def profile_list(): plugins = registry.get_plugin_classes(obj.Profile) result = [] for clsname, cls in sorted(plugins.items()): try: doc = cls.__doc__.strip().splitlines()[0] except AttributeError: doc = 'No docs' result.append((clsname, doc)) return json.dumps(result)
def main(): # Get the version information on every output from the beginning # Exceptionally useful for debugging/telling people what's going on sys.stderr.write( "Volatility Foundation Volatility Framework {0}\n".format( constants.VERSION ) ) sys.stderr.flush() # Setup the debugging format debug.setup() # Load up modules in case they set config options registry.PluginImporter() ## Register all register_options for the various classes registry.register_global_options(config, addrspace.BaseAddressSpace) registry.register_global_options(config, commands.Command) if config.INFO: print_info() sys.exit(0) ## Parse all the options now config.parse_options(False) # Reset the logging level now we know whether debug is set or not debug.setup(config.DEBUG) module = None ## Try to find the first thing that looks like a module name cmds = registry.get_plugin_classes(commands.Command, lower=True) for m in config.args: if m in list(cmds.keys()): module = m break if not module: config.parse_options() debug.error("You must specify something to do (try -h)") try: if module in list(cmds.keys()): command = cmds[module](config) ## Register the help cb from the command itself config.set_help_hook(obj.Curry(command_help, command)) config.parse_options() if not config.LOCATION: debug.error("Please specify a location (-l) or filename (-f)") command.execute() except exceptions.VolatilityException as e: print(e)
def __config(self): """Creates a volatility configuration.""" if self.config != None and self.addr_space != None: return self.config self.config = conf.ConfObject() self.config.optparser.set_conflict_handler("resolve") registry.register_global_options(self.config, commands.Command) base_conf = { "profile": "WinXPSP2x86", "use_old_as": None, "kdbg": None, "help": False, "kpcr": None, "tz": None, "pid": None, "output_file": None, "physical_offset": None, "conf_file": None, "dtb": None, "output": None, "info": None, "location": "file://" + self.memdump, "plugins": None, "debug": None, "cache_dtb": True, "filename": None, "cache_directory": None, "verbose": None, "write": False } if self.osprofile: base_conf["profile"] = self.osprofile if self.kdbg: base_conf["kdbg"] = long(self.kdbg, 16) for key, value in base_conf.items(): self.config.update(key, value) # Deal with Volatility support for KVM/qemu memory dump. # See: #464. try: self.addr_space = utils.load_as(self.config) except exc.AddrSpaceError as e: if self._get_dtb(): self.addr_space = utils.load_as(self.config) else: raise self.plugins = registry.get_plugin_classes(commands.Command, lower=True) return self.config
def __init__(self): if not with_volatility: raise RuntimeError("Volatility not found. Please install it") Module.__init__(self, "mvolatility", Volatility) self.conf.addArgument({ "name": "file", "description": "Dump to analyse", "input": Argument.Required | Argument.Single | typeId.Node }) self.conf.addArgument({ "name": "hdd_base", "description": "Hard Disk Drive mount point associated to this memory dump", "input": Argument.Optional | Argument.Single | typeId.Node }) self.conf.addArgument({ "name": "profile", "description": "Profile to use", "input": Argument.Optional | Argument.Single | typeId.String, "parameters": { "type": Parameter.NotEditable, "predefined": sorted([ p.__name__ for p in registry.get_plugin_classes(obj.Profile).values() ]) } }) self.conf.addConstant({ "name": "extention-type", "type": typeId.String, "description": "managed extension", "values": ["vmem"] }) self.conf.addConstant({ "name": "mime-type", "type": typeId.String, "description": "managed mime type", "values": ["x-coredump"] }) self.conf.description = "Analyse windows ram dump" self.tags = "Volatile memory" self.icon = ":dev_ram.png"
def __init__(self, memdump, osprofile): """@param memdump: the memdump file path @param osprofile: the profile (OS type) """ registry.PluginImporter() self.memdump = memdump self.osprofile = osprofile self.config = None self.addr_space = None self.profiles = registry.get_plugin_classes(obj.Profile).keys() self.init_config()
def calculate(self): """Determines the address space""" profilelist = [ p.__name__ for p in registry.get_plugin_classes(obj.Profile).values() ] encrypted_kdbg_profiles = [] proflens = {} maxlen = 0 origprofile = self._config.PROFILE for p in profilelist: self._config.update('PROFILE', p) buf = addrspace.BufferAddressSpace(self._config) if buf.profile.metadata.get('os', 'unknown') == 'windows': proflens[p] = str(obj.VolMagic(buf).KDBGHeader) maxlen = max(maxlen, len(proflens[p])) if (buf.profile.metadata.get('memory_model', '64bit') == '64bit' and (buf.profile.metadata.get('major', 0), buf.profile.metadata.get('minor', 0)) >= (6, 2)): encrypted_kdbg_profiles.append(p) self._config.update('PROFILE', origprofile) # keep track of the number of potential KDBGs we find count = 0 if origprofile not in encrypted_kdbg_profiles: scanner = KDBGScanner(needles=proflens.values()) aspace = utils.load_as(self._config, astype='any') for offset in scanner.scan(aspace): val = aspace.read(offset, maxlen + 0x10) for l in proflens: if val.find(proflens[l]) >= 0: kdbg = obj.Object("_KDDEBUGGER_DATA64", offset=offset, vm=aspace) yield l, kdbg count += 1 # only perform the special win8/2012 scan if we didn't find # any others and if a virtual x64 address space is available if count == 0: if origprofile in encrypted_kdbg_profiles: encrypted_kdbg_profiles = [origprofile] for profile in encrypted_kdbg_profiles: self._config.update('PROFILE', profile) aspace = utils.load_as(self._config, astype='any') if hasattr(aspace, 'vtop'): for kdbg in obj.VolMagic( aspace).KDBG.generate_suggestions(): yield profile, kdbg
def profile_list(self): """ 사용가능한 프로파일 리스트를 정렬 후 반환 :return: sorted profile list """ prof_list = ['AutoDetect'] profs = registry.get_plugin_classes(obj.Profile) for profile in profs.iterkeys(): prof_list.append(profile) return sorted(prof_list)
def check_valid_profile(option, _opt_str, value, parser): """Checks to make sure the selected profile is valid""" # PROFILES may not have been created yet, # but the callback should get called once it has # during the final parse of the config options profs = registry.get_plugin_classes(obj.Profile) if profs: try: profs[value] except KeyError: debug.error("Invalid profile " + value + " selected") setattr(parser.values, option.dest, value)
def check_valid_profile(option, _opt_str, value, parser): """Checks to make sure the selected profile is valid""" # PROFILES may not have been created yet, # but the callback should get called once it has # during the final parse of the config options profs = registry.get_plugin_classes(obj.Profile) if profs: try: profs[value] except KeyError: debug.error(f"Invalid profile {value} selected") setattr(parser.values, option.dest, value)
def __config(self): """Creates a volatility configuration.""" if self.config != None and self.addr_space != None: return self.config self.config = conf.ConfObject() self.config.optparser.set_conflict_handler("resolve") registry.register_global_options(self.config, commands.Command) base_conf = { "profile": "WinXPSP2x86", "use_old_as": None, "kdbg": None, "help": False, "kpcr": None, "tz": None, "pid": None, "output_file": None, "physical_offset": None, "conf_file": None, "dtb": None, "output": None, "info": None, "location": "file://" + self.memdump, "plugins": None, "debug": None, "cache_dtb": True, "filename": None, "cache_directory": None, "verbose": None, "write": False } if self.osprofile: base_conf["profile"] = self.osprofile for key, value in base_conf.items(): self.config.update(key, value) # Deal with Volatility support for KVM/qemu memory dump. # See: #464. try: self.addr_space = utils.load_as(self.config) except exc.AddrSpaceError as e: if self._get_dtb(): self.addr_space = utils.load_as(self.config) else: raise self.plugins = registry.get_plugin_classes(commands.Command, lower=True) return self.config
def execute(self): """ Executes the plugin command.""" # Check we can support the plugins profs = registry.get_plugin_classes(obj.Profile) # force user to give a profile if a plugin # other than kdbgscan or imageinfo are given: plugin_name = self.__class__.__name__.lower() if plugin_name != "mac_get_profile": if self._config.PROFILE == None: if plugin_name in ["kdbgscan", "imageinfo"]: self._config.update("PROFILE", "WinXPSP2x86") else: debug.error("You must set a profile!") if self._config.PROFILE not in profs: debug.error("Invalid profile " + self._config.PROFILE + " selected") if not self.is_valid_profile(profs[self._config.PROFILE]()): debug.error("This command does not support the profile " + self._config.PROFILE) # # Executing plugins is done in two stages - first we calculate data = self.calculate() ## Then we render the result in some way based on the ## requested output mode: function_name = "render_{0}".format(self._config.OUTPUT) if not self._config.OUTPUT == "sqlite" and self._config.OUTPUT_FILE: if os.path.exists(self._config.OUTPUT_FILE): debug.error( "File " + self._config.OUTPUT_FILE + " already exists. Cowardly refusing to overwrite it..." ) outfd = open(self._config.OUTPUT_FILE, "wb") # TODO: We should probably check that this won't blat over an existing file else: outfd = sys.stdout try: func = getattr(self, function_name) except AttributeError: ## Try to find out what formats are supported result = [] for x in dir(self): if x.startswith("render_"): _a, b = x.split("_", 1) result.append(b) print "Plugin {0} is unable to produce output in format {1}. Supported formats are {2}. Please send a feature request".format( self.__class__.__name__, self._config.OUTPUT, result ) return func(outfd, data)
def __init__(self, config, *args, **kwargs): threads.Threads.__init__(self, config, *args, **kwargs) if not yara_installed: debug.warning("In order to search the stack frames, it is necessary to install yara - searching is disabled") config.add_option('UNWIND', default = DEFAULT_UNWIND, help = 'List of frame unwinding strategies (comma-separated)', action = 'store', type = 'str') config.add_option('LISTUNWINDS', default = False, help = 'List all known frame unwinding strategies', action = 'store_true') config.add_option("SYMBOLS", default = False, action = 'store_true', cache_invalidator = False, help = "Use symbol servers to resolve process addresses to module names (we assume symbol tables have already been built)") stack_registry = registry.get_plugin_classes(StackTop) if getattr(config, 'LISTUNWINDS', False): print "Stack Frame Unwind Strategies:\n" for cls_name, cls in sorted(stack_registry.items(), key=lambda v: v[0]): if cls_name not in ["UserFrame", "KernelFrame"]: print "{0:<20}: {1}\n".format(cls_name, pydoc.getdoc(cls)) sys.exit(0) self.kernel_strategies = [] self.user_strategies = [] for strategy in getattr(config, 'UNWIND', DEFAULT_UNWIND).split(","): if ":" in strategy: if strategy.startswith("kernel:"): strategy = strategy[len("kernel:"):] if strategy not in stack_registry or not issubclass(stack_registry[strategy], KernelFrame): debug.error("{0} is not a valid kernel stack unwinding strategy".format(strategy)) self.kernel_strategies.append(stack_registry[strategy]) elif strategy.startswith("user:"******"user:"******"{0} is not a valid user stack unwinding strategy".format(strategy)) self.user_strategies.append(stack_registry[strategy]) else: debug.error("{0} is an unrecognised stack".format(strategy.split(":")[0])) elif strategy not in stack_registry: debug.error("{0} is neither a valid kernel nor user stack unwinding strategy".format(strategy)) elif not issubclass(stack_registry[strategy], KernelFrame) and not issubclass(stack_registry[strategy], UserFrame): debug.error("{0} is neither a valid kernel nor stack unwinding strategy".format(strategy)) else: if issubclass(stack_registry[strategy], KernelFrame): self.kernel_strategies.append(stack_registry[strategy]) if issubclass(stack_registry[strategy], UserFrame): self.user_strategies.append(stack_registry[strategy]) self.use_symbols = getattr(config, 'SYMBOLS', False) # Determine which filters the user wants to see if getattr(config, 'FILTER', None): self.filters = set(config.FILTER.split(',')) else: self.filters = set()
def volmain(argv): # Few modifications in original code config.set_usage(usage = "Volatility - A memory forensics analysis platform.") config.add_help_hook(list_plugins) argv = argv.split(" ") sys.argv = argv #print sys.argv # Get the version information on every output from the beginning # Exceptionally useful for debugging/telling people what's going on sys.stderr.write("Volatile Systems Volatility Framework {0}\n".format(constants.VERSION)) # Setup the debugging format debug.setup() # Load up modules in case they set config options registry.PluginImporter() ## Register all register_options for the various classes registry.register_global_options(config, addrspace.BaseAddressSpace) registry.register_global_options(config, commands.Command) if config.INFO: print_info() #sys.exit(0) ## Parse all the options now config.parse_options(False) # Reset the logging level now we know whether debug is set or not debug.setup(config.DEBUG) module = None ## Try to find the first thing that looks like a module name cmds = registry.get_plugin_classes(commands.Command, lower = True) for m in config.args: if m in cmds.keys(): module = m break if not module: config.parse_options() #debug.error("You must specify something to do (try -h)") try: if module in cmds.keys(): command = cmds[module](config) ## Register the help cb from the command itself config.set_help_hook(obj.Curry(command_help, command)) config.parse_options() if not config.LOCATION: debug.error("Please specify a location (-l) or filename (-f)") #print config.LOCATION command.execute() except exceptions.VolatilityException, e: print e
def run_plugin(self, plugin_name, pid=None, dump_dir=None, plugin_options=None, hive_offset=None, output_style="json"): """ run a plugin and set config options :param plugin_name: :param pid: :param dump_dir: :param plugin_options: :param hive_offset: :param output_style: :return: json """ # Get Valid commands cmds = registry.get_plugin_classes(commands.Command, lower=True) if plugin_name in cmds.keys(): command = cmds[plugin_name] # Set Config options self.config.PID = pid self.config.DUMP_DIR = dump_dir self.config.hive_offset = hive_offset if plugin_options: for option, value in plugin_options.iteritems(): self.config.update(option, value) # Plugins with specific output types if plugin_name == 'pstree': output_data = self.get_dot(command) return output_data if plugin_name == 'imageinfo': output_data = self.get_text(command) return output_data # All other plugins else: if output_style == 'json': output_data = self.get_json(command) return self.result_modifier(output_data) if output_style == 'text': output_data = self.get_text(command) return output_data else: return 'Error: Not a valid plugin'
def run_plugin(self, plugin_name, pid=None, dump_dir=None, plugin_options=None, hive_offset=None, output_style="json"): # Get Valid commands cmds = registry.get_plugin_classes(commands.Command, lower=True) if plugin_name in cmds.keys(): command = cmds[plugin_name] # Set PID self.config.PID = pid self.config.DUMP_DIR = dump_dir self.config.hive_offset = hive_offset # Add any other options if plugin_options: for option, value in plugin_options.iteritems(): self.config.update(option, value) if plugin_name == 'pstree': output_data = self.get_dot(command) return output_data # Just for imageinfo as i want it formatted for another table if plugin_name == 'imageinfo': output_data = self.get_text(command) return output_data # All other plugins else: if output_style == 'json': output_data = self.get_json(command) return output_data if output_style == 'text': output_data = self.get_text(command) return output_data else: return 'Error: Not a valid plugin'
def _set_profile(self, profile_name): ## Load the required profile if profile_name in PROFILES: ret = PROFILES[profile_name] else: profs = registry.get_plugin_classes(obj.Profile) if profile_name in profs: ret = profs[profile_name]() PROFILES[profile_name] = ret else: raise ASAssertionError, "Invalid profile " + profile_name + " selected" if not self.is_valid_profile(ret): raise ASAssertionError, "Incompatible profile " + profile_name + " selected" return ret
def execute(self): """ Executes the plugin command.""" # Check we can support the plugins profs = registry.get_plugin_classes(obj.Profile) # force user to give a profile if a plugin # other than kdbgscan or imageinfo are given: if self.__class__.__name__.lower() in [ "kdbgscan", "imageinfo" ] and self._config.PROFILE == None: self._config.update("PROFILE", "WinXPSP2x86") elif self._config.PROFILE == None: debug.error("You must set a profile!") if self._config.PROFILE not in profs: debug.error("Invalid profile " + self._config.PROFILE + " selected") if not self.is_valid_profile(profs[self._config.PROFILE]()): debug.error("This command does not support the profile " + self._config.PROFILE) # # Executing plugins is done in two stages - first we calculate data = self.calculate() ## Then we render the result in some way based on the ## requested output mode: function_name = "render_{0}".format(self._config.OUTPUT) if self._config.OUTPUT_FILE: if os.path.exists(self._config.OUTPUT_FILE): debug.error( "File " + self._config.OUTPUT_FILE + " already exists. Cowardly refusing to overwrite it...") outfd = open(self._config.OUTPUT_FILE, 'wb') # TODO: We should probably check that this won't blat over an existing file else: outfd = sys.stdout try: func = getattr(self, function_name) except AttributeError: ## Try to find out what formats are supported result = [] for x in dir(self): if x.startswith("render_"): _a, b = x.split("_", 1) result.append(b) print "Plugin {0} is unable to produce output in format {1}. Supported formats are {2}. Please send a feature request".format( self.__class__.__name__, self._config.OUTPUT, result) return func(outfd, data)
def modification(self, profile): profiles = registry.get_plugin_classes(obj.Profile) meta = profile.metadata # find the equivalent 32-bit profile to this 64-bit profile. # the prof._md_build + 1 accounts for a poor decision we made # a while back where we added + 1 to the build number for # server-based profiles as a method to distinguish between # client vs server in a plugin. profile_32bit = None for prof in list(profiles.values()): if (prof._md_os == "windows" and prof._md_major == meta.get("major") and prof._md_minor == meta.get("minor") and ((prof._md_build == meta.get("build")) or (prof._md_build + 1 == meta.get("build"))) and prof._md_memory_model == "32bit"): profile_32bit = prof() break if profile_32bit == None: debug.warning( "Cannot find a 32-bit equivalent profile. The " "WoW64 plugins (dlllist, ldrmodules, etc) may not work.") return profile.vtypes.update({ "_PEB32_LDR_DATA": self.cast_as_32bit(profile_32bit.vtypes["_PEB_LDR_DATA"]), "_LDR32_DATA_TABLE_ENTRY": self.cast_as_32bit(profile_32bit.vtypes["_LDR_DATA_TABLE_ENTRY"]), '_UNICODE32_STRING': self.cast_as_32bit(profile_32bit.vtypes["_UNICODE_STRING"]), }) profile.object_classes.update({ "_LDR32_DATA_TABLE_ENTRY": pe_vtypes._LDR_DATA_TABLE_ENTRY, "_UNICODE32_STRING": windows._UNICODE_STRING, "LIST_ENTRY32": LIST_ENTRY32, }) profile.merge_overlay({ '_PEB32': [ None, { 'Ldr': [None, ['pointer32', ['_PEB32_LDR_DATA']]], }, ] })
def __get_profile(self, from_cache=True): """ Get the dump image profile by loading it from a cache file or by running 'imageinfo' Volatility command. :param from_cache: load the profile from the cache file if it exists :return: boolean indicating if the profile is tested as correct """ cf = self._cachefile assert isinstance(from_cache, bool) logger.info("Getting profile...") # get available profiles and commands available_profiles = registry.get_plugin_classes(obj.Profile) compatible_profiles = [] # load profile from cache or use the 'imageinfo' command to find it if from_cache: if isfile(cf): with open(cf) as f: self.config.PROFILE = f.readlines()[0].strip() if not self.__get_pslist(): self.config.PROFILE = None else: compatible_profiles = [self.config.PROFILE] else: from_cache = False if not from_cache or self.config.PROFILE is None: self.config.PROFILE = "WinXPSP2x86" # reset to default compatible_profiles = [ p for p in self.call('imageinfo', parser=self.parsers['imageinfo']) ] self.__profiles = {p: c for p, c in available_profiles.items() \ if p in compatible_profiles} # try 'pslist' command on the found profile ; if an error occurs, try # the next profile in the list cursor, is_profile_tested = 0, False while not is_profile_tested and cursor < len(self.__profiles): self.config.PROFILE = self.__profiles.keys()[cursor] logger.debug("Profile: {}".format(self.config.PROFILE)) is_profile_tested = self.__get_pslist() cursor += 1 if not is_profile_tested: logger.error("No suitable profile could be found ; please check " "that your memory dump is supported by Volatility") sys.exit(2) self._update_cache(self.config.PROFILE) logger.info("> Selected profile: {}".format(self.config.PROFILE)) return is_profile_tested
def _set_profile(self, profile_name): ## Load the required profile if profile_name == None: raise ASAssertionError("You must set a profile!") if profile_name in PROFILES: ret = PROFILES[profile_name] else: profs = registry.get_plugin_classes(obj.Profile) if profile_name in profs: ret = profs[profile_name]() PROFILES[profile_name] = ret else: raise ASAssertionError( f"Invalid profile {profile_name} selected") if not self.is_valid_profile(ret): raise ASAssertionError( f"Incompatible profile {profile_name} selected") return ret
def init_config(self): """Creates a volatility configuration.""" if self.config is not None and self.addr_space is not None: return self.config self.config = conf.ConfObject() self.config.optparser.set_conflict_handler("resolve") registry.register_global_options(self.config, commands.Command) registry.register_global_options(self.config, addrspace.BaseAddressSpace) base_conf = { "profile": "WinXPSP2x86", "use_old_as": None, "kdbg": None, "help": False, "kpcr": None, "tz": None, "pid": None, "output_file": None, "physical_offset": None, "conf_file": None, "dtb": None, "output": None, "info": None, "location": "file://" + self.memdump, "plugins": None, "debug": 4, "cache_dtb": True, "filename": None, "cache_directory": None, "verbose": None, "write": False } if self.osprofile: base_conf["profile"] = self.osprofile for key, value in base_conf.items(): self.config.update(key, value) self.plugins = registry.get_plugin_classes(commands.Command, lower=True) return self.config
def linux_get_offsets(): from utils import ConfigurationManager as conf_m import volatility.obj as obj import volatility.registry as registry try: profs = registry.get_plugin_classes(obj.Profile) profile = profs[conf_m.vol_profile]() init_task_offset = profile.get_symbol("init_task") comm_offset = profile.get_obj_offset("task_struct", "comm") pid_offset = profile.get_obj_offset("task_struct", "pid") tasks_offset = profile.get_obj_offset("task_struct", "tasks") mm_offset = profile.get_obj_offset("task_struct", "mm") pgd_offset = profile.get_obj_offset("mm_struct", "pgd") parent_offset = profile.get_obj_offset("task_struct", "parent") exit_state_offset = profile.get_obj_offset("task_struct", "exit_state") thread_stack_size = profile.get_obj_offset( "pyrebox_thread_stack_size_info", "offset") # new process proc_exec_connector_offset = profile.get_symbol("proc_exec_connector") # new kernel module trim_init_extable_offset = profile.get_symbol("trim_init_extable") # process exit proc_exit_connector_offset = profile.get_symbol("proc_exit_connector") return (long(init_task_offset), long(comm_offset), long(pid_offset), long(tasks_offset), long(mm_offset), long(pgd_offset), long(parent_offset), long(exit_state_offset), long(thread_stack_size), long(proc_exec_connector_offset), long(trim_init_extable_offset), long(proc_exit_connector_offset)) except Exception as e: pp_error("Could not retrieve symbols for profile initialization %s" % str(e)) return None
def unique_sizes(self): """Determine the possible KDBG sizes to scan for, across all profiles Win8 x64 and above. We do this by reflecting back on the profile modifications to see which ones would trigger and then grabbing the KDBG size.""" items = registry.get_plugin_classes(windows_main.AbstractKDBGMod).items() sizes = set() for name, cls in items: try: if (not cls.conditions["os"]("windows") or not cls.conditions["major"](6)): continue sizes.add(cls.kdbgsize) except: continue return sizes
def unique_sizes(self): items = registry.get_plugin_classes(obj.Profile).items() sizes = set() for name, cls in items: if (cls._md_os != "windows" or cls._md_memory_model != "64bit"): continue #if (cls._md_major, cls._md_minor) < (6, 2): # continue conf = copy.deepcopy(self.obj_vm.get_config()) conf.PROFILE = name buff = addrspace.BufferAddressSpace(config = conf) header = obj.VolMagic(buff).KDBGHeader.v() # this unpacks the kdbgsize from the signature size = struct.unpack("<H", header[-2:])[0] sizes.add(size) return sizes