1# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0 2# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 3# 4 5import logging 6from typing import List, Tuple, Dict, Generator 7 8from volatility.framework import interfaces, renderers, exceptions 9from volatility.framework.configuration import requirements 10from volatility.framework.layers import intel 11from volatility.framework.renderers import format_hints 12 13vollog = logging.getLogger(__name__) 14 15 16class VirtMap(interfaces.plugins.PluginInterface): 17 """Lists virtual mapped sections.""" 18 19 def __init__(self, *args, **kwargs): 20 super().__init__(*args, **kwargs) 21 22 @classmethod 23 def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: 24 # Since we're calling the plugin, make sure we have the plugin's requirements 25 return [ 26 requirements.TranslationLayerRequirement(name = 'primary', 27 description = 'Memory layer for the kernel', 28 architectures = ["Intel32", "Intel64"]), 29 requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols") 30 ] 31 32 def _generator(self, map): 33 for entry in sorted(map): 34 for (start, end) in map[entry]: 35 yield (0, (entry, format_hints.Hex(start), format_hints.Hex(end))) 36 37 @classmethod 38 def determine_map(cls, module: interfaces.context.ModuleInterface) -> \ 39 Dict[str, List[Tuple[int, int]]]: 40 """Returns the virtual map from a windows kernel module.""" 41 layer = module.context.layers[module.layer_name] 42 if not isinstance(layer, intel.Intel): 43 raise 44 45 result = {} # type: Dict[str, List[Tuple[int, int]]] 46 system_va_type = module.get_enumeration('_MI_SYSTEM_VA_TYPE') 47 large_page_size = (layer.page_size ** 2) // module.get_type("_MMPTE").size 48 49 if module.has_symbol('MiVisibleState'): 50 symbol = module.get_symbol('MiVisibleState') 51 visible_state = module.object(object_type = 'pointer', 52 offset = symbol.address, 53 subtype = module.get_type('_MI_VISIBLE_STATE')).dereference() 54 if hasattr(visible_state, 'SystemVaRegions'): 55 for i in range(visible_state.SystemVaRegions.count): 56 lookup = system_va_type.lookup(i) 57 region_range = result.get(lookup, []) 58 region_range.append( 59 (visible_state.SystemVaRegions[i].BaseAddress, visible_state.SystemVaRegions[i].NumberOfBytes)) 60 result[lookup] = region_range 61 elif hasattr(visible_state, 'SystemVaType'): 62 system_range_start = module.object(object_type = "pointer", 63 offset = module.get_symbol("MmSystemRangeStart").address) 64 result = cls._enumerate_system_va_type(large_page_size, system_range_start, module, 65 visible_state.SystemVaType) 66 else: 67 raise exceptions.SymbolError(None, module.name, "Required structures not found") 68 elif module.has_symbol('MiSystemVaType'): 69 system_range_start = module.object(object_type = "pointer", 70 offset = module.get_symbol("MmSystemRangeStart").address) 71 symbol = module.get_symbol('MiSystemVaType') 72 array_count = (0xFFFFFFFF + 1 - system_range_start) // large_page_size 73 type_array = module.object(object_type = 'array', 74 offset = symbol.address, 75 count = array_count, 76 subtype = module.get_type('char')) 77 78 result = cls._enumerate_system_va_type(large_page_size, system_range_start, module, type_array) 79 else: 80 raise exceptions.SymbolError(None, module.name, "Required structures not found") 81 82 return result 83 84 @classmethod 85 def _enumerate_system_va_type(cls, large_page_size: int, system_range_start: int, 86 module: interfaces.context.ModuleInterface, 87 type_array: interfaces.objects.ObjectInterface) -> Dict[str, List[Tuple[int, int]]]: 88 result = {} # type: Dict[str, List[Tuple[int, int]]] 89 system_va_type = module.get_enumeration('_MI_SYSTEM_VA_TYPE') 90 start = system_range_start 91 prev_entry = -1 92 cur_size = large_page_size 93 for entry in type_array: 94 entry = system_va_type.lookup(entry) 95 if entry != prev_entry: 96 region_range = result.get(entry, []) 97 region_range.append((start, cur_size)) 98 result[entry] = region_range 99 start = start + cur_size 100 cur_size = large_page_size 101 else: 102 cur_size += large_page_size 103 prev_entry = entry 104 105 return result 106 107 @classmethod 108 def scannable_sections(cls, module: interfaces.context.ModuleInterface) -> Generator[Tuple[int, int], None, None]: 109 mapping = cls.determine_map(module) 110 for entry in mapping: 111 if 'Unused' not in entry: 112 for value in mapping[entry]: 113 yield value 114 115 def run(self): 116 layer = self.context.layers[self.config['primary']] 117 module = self.context.module(self.config['nt_symbols'], 118 layer_name = layer.name, 119 offset = layer.config['kernel_virtual_offset']) 120 121 return renderers.TreeGrid([("Region", str), ("Start offset", format_hints.Hex), 122 ("End offset", format_hints.Hex)], 123 self._generator(self.determine_map(module = module))) 124