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