Source code for

# This file is Copyright 2020 Volatility Foundation and licensed under the Volatility Software License 1.0
# which is available at

import logging
import os
from typing import List, Optional, Tuple, Iterator

from volatility3.framework import interfaces, renderers, exceptions, symbols
from volatility3.framework.configuration import requirements
from volatility3.framework.interfaces import configuration
from volatility3.framework.renderers import format_hints
from volatility3.framework.symbols import intermed
from import extensions
from import versions

vollog = logging.getLogger(__name__)

[docs]class BigPools(interfaces.plugins.PluginInterface): """List big page pools.""" _required_framework_version = (2, 0, 0) _version = (1, 1, 0)
[docs] @classmethod def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: # Since we're calling the plugin, make sure we have the plugin's requirements return [ requirements.ModuleRequirement( name="kernel", description="Windows kernel", architectures=["Intel32", "Intel64"], ), requirements.StringRequirement( name="tags", description="Comma separated list of pool tags to filter pools returned", optional=True, default=None, ), requirements.BooleanRequirement( name="show-free", description="Show freed regions (otherwise only show allocations in use)", default=False, optional=True, ), ]
[docs] @classmethod def list_big_pools( cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str, tags: Optional[list] = None, show_free: bool = False, ): """Returns the big page pool objects from the kernel PoolBigPageTable array. Args: context: The context to retrieve required elements (layers, symbol tables) from layer_name: The name of the layer on which to operate symbol_table: The name of the table containing the kernel symbols tags: An optional list of pool tags to filter big page pool tags by Yields: A big page pool object """ kvo = context.layers[layer_name].config["kernel_virtual_offset"] ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo) big_page_table_offset = ntkrnlmp.get_symbol("PoolBigPageTable").address big_page_table = ntkrnlmp.object( object_type="unsigned long long", offset=big_page_table_offset ) big_page_table_size_offset = ntkrnlmp.get_symbol("PoolBigPageTableSize").address big_page_table_size = ntkrnlmp.object( object_type="unsigned long", offset=big_page_table_size_offset ) try: big_page_table_type = ntkrnlmp.get_type("_POOL_TRACKER_BIG_PAGES") except exceptions.SymbolError: # We have to manually load a symbol table is_vista_or_later = versions.is_vista_or_later(context, symbol_table) is_win10 = versions.is_win10(context, symbol_table) if is_win10: big_pools_json_filename = "bigpools-win10" elif is_vista_or_later: big_pools_json_filename = "bigpools-vista" else: big_pools_json_filename = "bigpools" if symbols.symbol_table_is_64bit(context, symbol_table): big_pools_json_filename += "-x64" else: big_pools_json_filename += "-x86" new_table_name = intermed.IntermediateSymbolTable.create( context=context, config_path=configuration.path_join( context.symbol_space[symbol_table].config_path, "bigpools" ), sub_path=os.path.join("windows", "bigpools"), filename=big_pools_json_filename, table_mapping={"nt_symbols": symbol_table}, class_types={ "_POOL_TRACKER_BIG_PAGES": extensions.pool.POOL_TRACKER_BIG_PAGES }, ) module = context.module(new_table_name, layer_name, offset=0) big_page_table_type = module.get_type("_POOL_TRACKER_BIG_PAGES") big_pools = ntkrnlmp.object( object_type="array", offset=big_page_table, subtype=big_page_table_type, count=big_page_table_size, absolute=True, ) for big_pool in big_pools: if big_pool.is_valid(): if (tags is None or big_pool.get_key() in tags) and ( show_free or not big_pool.is_free() ): yield big_pool
def _generator(self) -> Iterator[Tuple[int, Tuple[int, str]]]: # , str, int]]]: if self.config.get("tags"): tags = [tag for tag in self.config["tags"].split(",")] else: tags = None kernel = self.context.modules[self.config["kernel"]] for big_pool in self.list_big_pools( context=self.context, layer_name=kernel.layer_name, symbol_table=kernel.symbol_table_name, tags=tags, show_free=self.config.get("show-free"), ): num_bytes = big_pool.get_number_of_bytes() if not isinstance(num_bytes, interfaces.renderers.BaseAbsentValue): num_bytes = format_hints.Hex(num_bytes) if big_pool.is_free(): status = "Free" else: status = "Allocated" yield ( 0, ( format_hints.Hex(big_pool.Va), big_pool.get_key(), big_pool.get_pool_type(), num_bytes, status, ), )
[docs] def run(self): return renderers.TreeGrid( [ ("Allocation", format_hints.Hex), ("Tag", str), ("PoolType", str), ("NumberOfBytes", format_hints.Hex), ("Status", str), ], self._generator(), )