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