def list_notify_routines( cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str, callback_table_name: str ) -> Iterable[Tuple[str, int, Optional[str]]]: """Lists all kernel notification routines. 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) is_vista_or_later = versions.is_vista_or_later( context=context, symbol_table=symbol_table) full_type_name = callback_table_name + constants.BANG + "_GENERIC_CALLBACK" symbol_names = [("PspLoadImageNotifyRoutine", False), ("PspCreateThreadNotifyRoutine", True), ("PspCreateProcessNotifyRoutine", True)] for symbol_name, extended_list in symbol_names: try: symbol_offset = ntkrnlmp.get_symbol(symbol_name).address except exceptions.SymbolError: vollog.debug(f"Cannot find {symbol_name}") continue if is_vista_or_later and extended_list: count = 64 else: count = 8 fast_refs = ntkrnlmp.object( object_type="array", offset=symbol_offset, subtype=ntkrnlmp.get_type("_EX_FAST_REF"), count=count) for fast_ref in fast_refs: try: callback = fast_ref.dereference().cast(full_type_name) except exceptions.InvalidAddressException: continue if callback.Callback != 0: yield symbol_name, callback.Callback, None
def _generator(self, syshive: registry.RegistryHive, sechive: registry.RegistryHive): kernel = self.context.modules[self.config['kernel']] vista_or_later = versions.is_vista_or_later( context=self.context, symbol_table=kernel.symbol_table_name) bootkey = hashdump.Hashdump.get_bootkey(syshive) lsakey = self.get_lsa_key(sechive, bootkey, vista_or_later) if not bootkey: vollog.warning("Unable to find bootkey") return if not lsakey: vollog.warning("Unable to find lsa key") return secrets_key = hashdump.Hashdump.get_hive_key(sechive, 'Policy\\Secrets') if not secrets_key: vollog.warning("Unable to find secrets key") return for key in secrets_key.get_subkeys(): sec_val_key = hashdump.Hashdump.get_hive_key( sechive, 'Policy\\Secrets\\' + key.get_key_path().split('\\')[3] + '\\CurrVal') if not sec_val_key: continue enc_secret_value = next(sec_val_key.get_values()) if not enc_secret_value: continue enc_secret = sechive.read(enc_secret_value.Data + 4, enc_secret_value.DataLength) if not enc_secret: continue if not vista_or_later: secret = self.decrypt_secret(enc_secret[0xC:], lsakey) else: secret = self.decrypt_aes(enc_secret, lsakey) yield (0, (key.get_name(), secret.decode('latin1'), secret))
def _generator(self, syshive, sechive): bootkey = hashdump.Hashdump.get_bootkey(syshive) if not bootkey: vollog.warning('Unable to find bootkey') return kernel = self.context.modules[self.config['kernel']] vista_or_later = versions.is_vista_or_later( context=self.context, symbol_table=kernel.symbol_table_name) lsakey = lsadump.Lsadump.get_lsa_key(sechive, bootkey, vista_or_later) if not lsakey: vollog.warning('Unable to find lsa key') return nlkm = self.get_nlkm(sechive, lsakey, vista_or_later) if not nlkm: vollog.warning('Unable to find nlkma key') return cache = hashdump.Hashdump.get_hive_key(sechive, "Cache") if not cache: vollog.warning('Unable to find cache key') return for cache_item in cache.get_values(): if cache_item.Name == "NL$Control": continue data = sechive.read(cache_item.Data + 4, cache_item.DataLength) if data is None: continue (uname_len, domain_len, domain_name_len, enc_data, ch) = self.parse_cache_entry(data) # Skip if nothing in this cache entry if uname_len == 0 or len(ch) == 0: continue dec_data = self.decrypt_hash(enc_data, nlkm, ch, not vista_or_later) (username, domain, domain_name, hashh) = self.parse_decrypted_cache(dec_data, uname_len, domain_len, domain_name_len) yield (0, (username, domain, domain_name, hashh))
def _generator(self, syshive: registry.RegistryHive, sechive: registry.RegistryHive): vista_or_later = versions.is_vista_or_later( context=self.context, symbol_table=self.config['nt_symbols']) bootkey = hashdump.Hashdump.get_bootkey(syshive) lsakey = self.get_lsa_key(sechive, bootkey, vista_or_later) if not bootkey: raise ValueError('Unable to find bootkey') if not lsakey: raise ValueError('Unable to find lsa key') secrets_key = sechive.get_key('Policy\\Secrets') if not secrets_key: raise ValueError('Unable to find secrets key') for key in secrets_key.get_subkeys(): sec_val_key = sechive.get_key('Policy\\Secrets\\' + key.get_key_path().split('\\')[3] + '\\CurrVal') if not sec_val_key: continue enc_secret_value = next(sec_val_key.get_values()) if not enc_secret_value: continue enc_secret = sechive.read(enc_secret_value.Data + 4, enc_secret_value.DataLength) if not enc_secret: continue if not vista_or_later: secret = self.decrypt_secret(enc_secret[0xC:], lsakey) else: secret = self.decrypt_aes(enc_secret, lsakey) yield (0, (key.get_name(), secret.decode('latin1'), secret))
def get_pool_header_table(cls, context: interfaces.context.ContextInterface, symbol_table: str) -> str: """Returns the appropriate symbol_table containing a _POOL_HEADER type, even if the original symbol table doesn't contain one. Args: context: The context that the symbol tables does (or will) reside in symbol_table: The expected symbol_table to contain the _POOL_HEADER type """ # Setup the pool header and offset differential try: context.symbol_space.get_type(symbol_table + constants.BANG + "_POOL_HEADER") table_name = symbol_table except exceptions.SymbolError: # We have to manually load a symbol table if symbols.symbol_table_is_64bit(context, symbol_table): is_win_7 = versions.is_windows_7(context, symbol_table) if is_win_7: pool_header_json_filename = "poolheader-x64-win7" else: pool_header_json_filename = "poolheader-x64" else: pool_header_json_filename = "poolheader-x86" # set the class_type to match the normal WindowsKernelIntermedSymbols is_vista_or_later = versions.is_vista_or_later(context, symbol_table) if is_vista_or_later: class_type = extensions.pool.POOL_HEADER_VISTA else: class_type = extensions.pool.POOL_HEADER table_name = intermed.IntermediateSymbolTable.create(context = context, config_path = configuration.path_join( context.symbol_space[symbol_table].config_path, "poolheader"), sub_path = "windows", filename = pool_header_json_filename, table_mapping = {'nt_symbols': symbol_table}, class_types = {'_POOL_HEADER': class_type}) return table_name
def create_service_table(context: interfaces.context.ContextInterface, symbol_table: str, config_path: str) -> str: """Constructs a symbol table containing the symbols for services depending upon the operating system in use. Args: context: The context to retrieve required elements (layers, symbol tables) from symbol_table: The name of the table containing the kernel symbols config_path: The configuration path for any settings required by the new table Returns: A symbol table containing the symbols necessary for services """ native_types = context.symbol_space[symbol_table].natives is_64bit = symbols.symbol_table_is_64bit(context, symbol_table) if versions.is_windows_xp(context=context, symbol_table=symbol_table) and not is_64bit: symbol_filename = "services-xp-x86" elif versions.is_xp_or_2003(context=context, symbol_table=symbol_table) and is_64bit: symbol_filename = "services-xp-2003-x64" elif versions.is_win10_16299_or_later( context=context, symbol_table=symbol_table) and is_64bit: symbol_filename = "services-win10-16299-x64" elif versions.is_win10_16299_or_later( context=context, symbol_table=symbol_table) and not is_64bit: symbol_filename = "services-win10-16299-x86" elif versions.is_win10_up_to_15063( context=context, symbol_table=symbol_table) and is_64bit: symbol_filename = "services-win8-x64" elif versions.is_win10_up_to_15063( context=context, symbol_table=symbol_table) and not is_64bit: symbol_filename = "services-win8-x86" elif versions.is_win10_15063(context=context, symbol_table=symbol_table) and is_64bit: symbol_filename = "services-win10-15063-x64" elif versions.is_win10_15063( context=context, symbol_table=symbol_table) and not is_64bit: symbol_filename = "services-win10-15063-x86" elif versions.is_windows_8_or_later( context=context, symbol_table=symbol_table) and is_64bit: symbol_filename = "services-win8-x64" elif versions.is_windows_8_or_later( context=context, symbol_table=symbol_table) and not is_64bit: symbol_filename = "services-win8-x86" elif versions.is_vista_or_later( context=context, symbol_table=symbol_table) and is_64bit: symbol_filename = "services-vista-x64" elif versions.is_vista_or_later( context=context, symbol_table=symbol_table) and not is_64bit: symbol_filename = "services-vista-x86" else: raise NotImplementedError( "This version of Windows is not supported!") return intermed.IntermediateSymbolTable.create( context, config_path, os.path.join("windows", "services"), symbol_filename, class_types=services.class_types, native_types=native_types)
def _generator(self): service_table_name = self.create_service_table( self.context, self.config["nt_symbols"], self.config_path) relative_tag_offset = self.context.symbol_space.get_type( service_table_name + constants.BANG + "_SERVICE_RECORD").relative_child_offset("Tag") filter_func = pslist.PsList.create_name_filter(["services.exe"]) is_vista_or_later = versions.is_vista_or_later( context=self.context, symbol_table=self.config["nt_symbols"]) if is_vista_or_later: service_tag = b"serH" else: service_tag = b"sErv" seen = [] for task in pslist.PsList.list_processes( context=self.context, layer_name=self.config['primary'], symbol_table=self.config['nt_symbols'], filter_func=filter_func): proc_id = "Unknown" try: proc_id = task.UniqueProcessId proc_layer_name = task.add_process_layer() except exceptions.InvalidAddressException as excp: vollog.debug( "Process {}: invalid address {} in layer {}".format( proc_id, excp.invalid_address, excp.layer_name)) continue layer = self.context.layers[proc_layer_name] for offset in layer.scan( context=self.context, scanner=scanners.BytesScanner(needle=service_tag), sections=vadyarascan.VadYaraScan.get_vad_maps(task)): if not is_vista_or_later: service_record = self.context.object( service_table_name + constants.BANG + "_SERVICE_RECORD", offset=offset - relative_tag_offset, layer_name=proc_layer_name) if not service_record.is_valid(): continue yield (0, self.get_record_tuple(service_record)) else: service_header = self.context.object( service_table_name + constants.BANG + "_SERVICE_HEADER", offset=offset, layer_name=proc_layer_name) if not service_header.is_valid(): continue # since we walk the s-list backwards, if we've seen # an object, then we've also seen all objects that # exist before it, thus we can break at that time. for service_record in service_header.ServiceRecord.traverse( ): if service_record in seen: break seen.append(service_record) yield (0, self.get_record_tuple(service_record))
def list_big_pools(cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str, tags: Optional[list] = None): """Returns the big page pool objects from the kernel PoolBigPageTable array. 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 tags: An optional list of pool tags to filter big page pool tags by Yields: A big page pool object """ kvo = context.layers[layer_name].config['kernel_virtual_offset'] ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo) big_page_table_offset = ntkrnlmp.get_symbol("PoolBigPageTable").address big_page_table = ntkrnlmp.object(object_type="unsigned long long", offset=big_page_table_offset) big_page_table_size_offset = ntkrnlmp.get_symbol( "PoolBigPageTableSize").address big_page_table_size = ntkrnlmp.object( object_type="unsigned long", offset=big_page_table_size_offset) try: big_page_table_type = ntkrnlmp.get_type("_POOL_TRACKER_BIG_PAGES") except exceptions.SymbolError: # We have to manually load a symbol table is_vista_or_later = versions.is_vista_or_later( context, symbol_table) is_win10 = versions.is_win10(context, symbol_table) if is_win10: big_pools_json_filename = "bigpools-win10" elif is_vista_or_later: big_pools_json_filename = "bigpools-vista" else: big_pools_json_filename = "bigpools" if symbols.symbol_table_is_64bit(context, symbol_table): big_pools_json_filename += "-x64" else: big_pools_json_filename += "-x86" new_table_name = intermed.IntermediateSymbolTable.create( context=context, config_path=configuration.path_join( context.symbol_space[symbol_table].config_path, "bigpools"), sub_path=os.path.join("windows", "bigpools"), filename=big_pools_json_filename, table_mapping={'nt_symbols': symbol_table}, class_types={ '_POOL_TRACKER_BIG_PAGES': extensions.pool.POOL_TRACKER_BIG_PAGES }) module = context.module(new_table_name, layer_name, offset=0) big_page_table_type = module.get_type("_POOL_TRACKER_BIG_PAGES") big_pools = ntkrnlmp.object(object_type="array", offset=big_page_table, subtype=big_page_table_type, count=big_page_table_size, absolute=True) for big_pool in big_pools: if big_pool.is_valid(): if tags is None or big_pool.get_key() in tags: yield big_pool