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 time
6from typing import List, Tuple, Iterable
7
8from volatility.framework import constants, interfaces, layers
9from volatility.framework.configuration import requirements
10from volatility.framework.interfaces import plugins
11from volatility.framework.renderers import TreeGrid
12from volatility.framework.symbols import intermed
13from volatility.framework.symbols.windows import extensions
14from volatility.framework.symbols.windows.extensions import kdbg
15
16
17class Info(plugins.PluginInterface):
18    """Show OS & kernel details of the memory sample being analyzed."""
19
20    @classmethod
21    def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
22        return [
23            requirements.TranslationLayerRequirement(name = 'primary',
24                                                     description = 'Memory layer for the kernel',
25                                                     architectures = ["Intel32", "Intel64"]),
26            requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols")
27        ]
28
29    @classmethod
30    def get_depends(cls,
31                    context: interfaces.context.ContextInterface,
32                    layer_name: str,
33                    index: int = 0) -> Iterable[Tuple[int, interfaces.layers.DataLayerInterface]]:
34        """List the dependencies of a given layer.
35
36        Args:
37            context: The context to retrieve required layers from
38            layer_name: the name of the starting layer
39            index: the index/order of the layer
40
41        Returns:
42            An iterable containing the levels and layer objects for all dependent layers
43        """
44        layer = context.layers[layer_name]
45        yield index, layer
46        try:
47            for depends in layer.dependencies:
48                for j, dep in cls.get_depends(context, depends, index + 1):
49                    yield j, context.layers[dep.name]
50        except AttributeError:
51            # FileLayer won't have dependencies
52            pass
53
54    def _generator(self):
55
56        virtual_layer_name = self.config["primary"]
57        virtual_layer = self.context.layers[virtual_layer_name]
58        if not isinstance(virtual_layer, layers.intel.Intel):
59            raise TypeError("Virtual Layer is not an intel layer")
60
61        native_types = self.context.symbol_space[self.config["nt_symbols"]].natives
62
63        kdbg_table_name = intermed.IntermediateSymbolTable.create(self.context,
64                                                                  self.config_path,
65                                                                  "windows",
66                                                                  "kdbg",
67                                                                  native_types = native_types,
68                                                                  class_types = extensions.kdbg.class_types)
69
70        pe_table_name = intermed.IntermediateSymbolTable.create(self.context,
71                                                                self.config_path,
72                                                                "windows",
73                                                                "pe",
74                                                                class_types = extensions.pe.class_types)
75
76        kvo = virtual_layer.config["kernel_virtual_offset"]
77
78        ntkrnlmp = self.context.module(self.config["nt_symbols"], layer_name = virtual_layer_name, offset = kvo)
79
80        kdbg_offset = ntkrnlmp.get_symbol("KdDebuggerDataBlock").address
81
82        kdbg = self.context.object(kdbg_table_name + constants.BANG + "_KDDEBUGGER_DATA64",
83                                   offset = kvo + kdbg_offset,
84                                   layer_name = virtual_layer_name)
85
86        yield (0, ("Kernel Base", hex(self.config["primary.kernel_virtual_offset"])))
87        yield (0, ("DTB", hex(self.config["primary.page_map_offset"])))
88        yield (0, ("Symbols", self.config["nt_symbols.isf_url"]))
89
90        for i, layer in self.get_depends(self.context, "primary"):
91            yield (0, (layer.name, "{} {}".format(i, layer.__class__.__name__)))
92
93        if kdbg.Header.OwnerTag == 0x4742444B:
94
95            yield (0, ("KdDebuggerDataBlock", hex(kdbg.vol.offset)))
96            yield (0, ("NTBuildLab", kdbg.get_build_lab()))
97            yield (0, ("CSDVersion", str(kdbg.get_csdversion())))
98
99        vers_offset = ntkrnlmp.get_symbol("KdVersionBlock").address
100
101        vers = ntkrnlmp.object(object_type = "_DBGKD_GET_VERSION64",
102                               layer_name = virtual_layer_name,
103                               offset = vers_offset)
104
105        yield (0, ("KdVersionBlock", hex(vers.vol.offset)))
106        yield (0, ("Major/Minor", "{0}.{1}".format(vers.MajorVersion, vers.MinorVersion)))
107        yield (0, ("MachineType", str(vers.MachineType)))
108
109        cpu_count_offset = ntkrnlmp.get_symbol("KeNumberProcessors").address
110
111        cpu_count = ntkrnlmp.object(object_type = "unsigned int",
112                                    layer_name = virtual_layer_name,
113                                    offset = cpu_count_offset)
114
115        yield (0, ("KeNumberProcessors", str(cpu_count)))
116
117        # this is a hard-coded address in the Windows OS
118        if virtual_layer.bits_per_register == 32:
119            kuser_addr = 0xFFDF0000
120        else:
121            kuser_addr = 0xFFFFF78000000000
122
123        kuser = ntkrnlmp.object(object_type = "_KUSER_SHARED_DATA",
124                                layer_name = virtual_layer_name,
125                                offset = kuser_addr,
126                                absolute = True)
127
128        yield (0, ("SystemTime", str(kuser.SystemTime.get_time())))
129        yield (0, ("NtSystemRoot",
130                   str(kuser.NtSystemRoot.cast("string", encoding = "utf-16", errors = "replace", max_length = 260))))
131        yield (0, ("NtProductType", str(kuser.NtProductType.description)))
132        yield (0, ("NtMajorVersion", str(kuser.NtMajorVersion)))
133        yield (0, ("NtMinorVersion", str(kuser.NtMinorVersion)))
134        # yield (0, ("KdDebuggerEnabled", "True" if kuser.KdDebuggerEnabled else "False"))
135        # yield (0, ("SafeBootMode", "True" if kuser.SafeBootMode else "False"))
136
137        dos_header = self.context.object(pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER",
138                                         offset = kvo,
139                                         layer_name = virtual_layer_name)
140
141        nt_header = dos_header.get_nt_header()
142
143        yield (0, ("PE MajorOperatingSystemVersion", str(nt_header.OptionalHeader.MajorOperatingSystemVersion)))
144        yield (0, ("PE MinorOperatingSystemVersion", str(nt_header.OptionalHeader.MinorOperatingSystemVersion)))
145
146        yield (0, ("PE Machine", str(nt_header.FileHeader.Machine)))
147        yield (0, ("PE TimeDateStamp", time.asctime(time.gmtime(nt_header.FileHeader.TimeDateStamp))))
148
149    def run(self):
150
151        return TreeGrid([("Variable", str), ("Value", str)], self._generator())
152