""" Created on 7 May 2013 @author: mike """ import math import struct from volatility.framework import exceptions, interfaces from volatility.framework.configuration import requirements class Intel(interfaces.layers.TranslationLayerInterface): """Translation Layer for the Intel IA32 memory mapping""" priority = 40 provides = {"type": "memory", "architecture": "ia32" } def __init__(self, context, config_path, name): super().__init__(context, config_path, name) self._base_layer = self._check_type(self.config["memory_layer"], str) self._page_map_offset = self._check_type(self.config["page_map_offset"], int) self._optimize_scan = False # All Intel address spaces work on 4096 byte pages self._page_size_in_bits = 12 # These can vary depending on the type of space self._entry_format = "> (position + 1) # Grab the base address of the table we'll be getting the next entry from base_address = self._mask(entry, self._maxphyaddr - 1, size + self._index_shift) # Create the offset for the next entry table_offset = base_address | (index << self._index_shift) # Read out the new entry from memory entry, = struct.unpack(self._entry_format, self._context.memory.read(self._base_layer, table_offset, struct.calcsize(self._entry_format))) # Now we're done if not self._page_is_valid(entry): raise exceptions.PagedInvalidAddressException(self.name, offset, position + 1, "Page Fault at entry {} in page entry".format(hex(entry))) page = self._mask(entry, self._maxphyaddr - 1, position + 1) | self._mask(offset, position, 0) return page, 1 << (position + 1) def is_valid(self, offset, length = 1): """Returns whether the address offset can be translated to a valid address""" try: # TODO: Consider reimplementing this, since calls to mapping can call is_valid return all([self._context.memory[self._base_layer].is_valid(mapped_offset) for _, mapped_offset, _, _ in self.mapping(offset, length)]) except exceptions.InvalidAddressException: return False def mapping(self, offset, length, ignore_errors = False): """Returns a sorted iterable of (offset, mapped_offset, length, layer) mappings This allows translation layers to provide maps of contiguous regions in one layer """ result = [] if length == 0: if ignore_errors and not self.is_valid(offset): raise StopIteration mapped_offset, _ = self._translate(offset) yield (offset, mapped_offset, length, self._base_layer) raise StopIteration while length > 0: if ignore_errors: while not self.is_valid(offset) and length > 0: length -= 1 << self._page_size_in_bits offset += 1 << self._page_size_in_bits if length <= 0: raise StopIteration chunk_offset, page_size = self._translate(offset) chunk_size = min(page_size - (chunk_offset % page_size), length) yield (offset, chunk_offset, chunk_size, self._base_layer) length -= chunk_size offset += chunk_size @property def dependencies(self): """Returns a list of the lower layer names that this layer is dependent upon""" # TODO: Add in the whole buffalo return [self._base_layer] @classmethod def get_requirements(cls): return [requirements.TranslationLayerRequirement(name = 'memory_layer', optional = False), requirements.TranslationLayerRequirement(name = 'swap_layer', optional = True), requirements.IntRequirement(name = 'page_map_offset', optional = False), requirements.IntRequirement(name = 'kernel_virtual_offset', optional = True)] def scan(self, context, scanner, progress_callback = None, min_address = None, max_address = None): min_address, max_address, scanner, total_size = self._pre_scan(context, min_address, max_address, progress_callback, scanner) scanned = set() previous = None range_start = current = min_address while current <= max_address: if progress_callback: progress_callback(round((current - min_address) * 100 / total_size, 3)) try: address, page_size = self._translate(current) if (previous, address) in scanned or not context.memory[self._base_layer].is_valid(address): if current - range_start > 0: chunk = self.read(range_start, current - range_start) for result in scanner(chunk, range_start): yield result range_start = current + page_size elif self._optimize_scan: scanned.add((previous, address)) previous = address current += page_size except exceptions.PagedInvalidAddressException as e: if current - range_start > 0: chunk = self.read(range_start, current - range_start) for result in scanner(chunk, range_start): yield result current += (1 << e.invalid_bits) range_start = current previous = None class IntelPAE(Intel): """Class for handling Physical Address Extensions for Intel architectures""" priority = 35 def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # These can vary depending on the type of space self._entry_format = "