diff --git a/volatility3/framework/automagic/windows.py b/volatility3/framework/automagic/windows.py index b93ee244c..f5dd720d6 100644 --- a/volatility3/framework/automagic/windows.py +++ b/volatility3/framework/automagic/windows.py @@ -219,30 +219,50 @@ class WindowsIntelStacker(interfaces.automagic.StackerLayerInterface): for description, tests, sections in cls.test_sets: vollog.debug(description) # There is a very high chance that the DTB will live in these very narrow segments, assuming we couldn't find them previously - hits = context.layers[layer_name].scan(context, - PageMapScanner(tests = tests), - sections = sections, - progress_callback = progress_callback) + hits = base_layer.scan(context, + PageMapScanner(tests = tests), + sections = sections, + progress_callback = progress_callback) # Flatten the generator def sort_by_tests(x): + """Key used to sort by tests""" return tests.index(x[0]), x[1] + def get_max_pointer(page_table, test, ptr_size: int): + """Determines a pointer from a page_table""" + max_ptr = 0 + for index in range(0, len(page_table), ptr_size): + pointer = struct.unpack(test.ptr_struct, page_table[index:index + ptr_size])[0] + # Make sure the pointer is valid, ignore large pages which would require more calculation + if pointer & 0x1 and not pointer & 0x80: + max_ptr = max(max_ptr, (pointer ^ (pointer & 0xfff)) % test.layer_type.maximum_address) + return max_ptr + hits = sorted(list(hits), key = sort_by_tests) - if hits: - # TODO: Decide which to use if there are multiple options - test, page_map_offset = hits[0] - vollog.debug(f"{test.__class__.__name__} test succeeded at {hex(page_map_offset)}") - new_layer_name = context.layers.free_layer_name("IntelLayer") - config_path = interfaces.configuration.path_join("IntelHelper", new_layer_name) - context.config[interfaces.configuration.path_join(config_path, "memory_layer")] = layer_name - context.config[interfaces.configuration.path_join(config_path, "page_map_offset")] = page_map_offset - # TODO: Need to determine the layer type (chances are high it's x64, hence this default) - layer = test.layer_type(context, - config_path = config_path, - name = new_layer_name, - metadata = {'os': 'Windows'}) + for test, page_map_offset in hits: + # Turn the page tables into integers and find the largest one + page_table = base_layer.read(page_map_offset, 0x1000) + ptr_size = struct.calcsize(test.ptr_struct) + max_pointer = get_max_pointer(page_table, test, ptr_size) + + if max_pointer <= base_layer.maximum_address: + vollog.debug(f"{test.__class__.__name__} test succeeded at {hex(page_map_offset)}") + new_layer_name = context.layers.free_layer_name("IntelLayer") + config_path = interfaces.configuration.path_join("IntelHelper", new_layer_name) + context.config[interfaces.configuration.path_join(config_path, "memory_layer")] = layer_name + context.config[ + interfaces.configuration.path_join(config_path, "page_map_offset")] = page_map_offset + layer = test.layer_type(context, + config_path = config_path, + name = new_layer_name, + metadata = {'os': 'Windows'}) + break + else: + vollog.debug( + f"Max pointer for hit with test {test.__class__.__name__} not met: {hex(max_pointer)} > {hex(base_layer.maximum_address)}") + if layer is not None and config_path: break if layer is not None and config_path: