Files
volatility3/volatility/framework/symbols/native.py
T

121 lines
5.9 KiB
Python

# This file was contributed to the Volatility Framework Version 3.
# Copyright (C) 2018 Volatility Foundation.
#
# THE LICENSED WORK IS PROVIDED UNDER THE TERMS OF THE Volatility Contributors
# Public License V1.0("LICENSE") AS FIRST COMPLETED BY: Volatility Foundation,
# Inc. ANY USE, PUBLIC DISPLAY, PUBLIC PERFORMANCE, REPRODUCTION OR DISTRIBUTION
# OF, OR PREPARATION OF SUBSEQUENT WORKS, DERIVATIVE WORKS OR DERIVED WORKS BASED
# ON, THE LICENSED WORK CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS LICENSE AND ITS
# TERMS, WHETHER OR NOT SUCH RECIPIENT READS THE TERMS OF THE LICENSE. "LICENSED
# WORK,” “RECIPIENT" AND “DISTRIBUTOR" ARE DEFINED IN THE LICENSE. A COPY OF THE
# LICENSE IS LOCATED IN THE TEXT FILE ENTITLED "LICENSE.txt" ACCOMPANYING THE
# CONTENTS OF THIS FILE. IF A COPY OF THE LICENSE DOES NOT ACCOMPANY THIS FILE, A
# COPY OF THE LICENSE MAY ALSO BE OBTAINED AT THE FOLLOWING WEB SITE:
# https://www.volatilityfoundation.org/license/vcpl_v1.0
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
# specific language governing rights and limitations under the License.
#
import copy
from typing import Any, Dict, Iterable, Optional, Type
from volatility.framework import constants, interfaces, objects
class NativeTable(interfaces.symbols.NativeTableInterface):
"""Symbol List that handles Native types"""
# FIXME: typing the native_dictionary as Tuple[interfaces.objects.ObjectInterface, str] throws many errors
def __init__(self, name: str, native_dictionary: Dict[str, Any]) -> None:
super().__init__(name, self)
self._native_dictionary = copy.deepcopy(native_dictionary)
self._overrides = {} # type: Dict[str, interfaces.objects.ObjectInterface]
for native_type in self._native_dictionary:
native_class, _native_struct = self._native_dictionary[native_type]
self._overrides[native_type] = native_class
# Create this once early, because it may get used a lot
self._types = set(self._native_dictionary).union(
{'enum', 'array', 'bitfield', 'void', 'string', 'bytes', 'function'})
def get_type_class(self, name: str) -> Type[interfaces.objects.ObjectInterface]:
ntype, _ = self._native_dictionary.get(name, (objects.Integer, None))
return ntype
@property
def types(self) -> Iterable[str]:
"""Returns an iterator of the symbol type names"""
return self._types
def get_type(self, type_name: str) -> interfaces.objects.Template:
"""Resolves a symbol name into an object template
This always construct a new python object, rather than using a cached value otherwise changes made later may
affect the cached copy. Calling clone after every native type construction was extremely slow.
"""
# NOTE: These need updating whenever the object init signatures change
prefix = ""
if constants.BANG in type_name:
name_split = type_name.split(constants.BANG)
if len(name_split) > 2:
raise ValueError("SymbolName cannot contain multiple {} separators".format(constants.BANG))
table_name, type_name = name_split
prefix = table_name + constants.BANG
additional = {} # type: Dict[str, Any]
obj = None # type: Optional[Type[interfaces.objects.ObjectInterface]]
if type_name == 'void' or type_name == 'function':
obj = objects.Void
elif type_name == 'array':
obj = objects.Array
additional = {"count": 0, "subtype": self.get_type('void')}
elif type_name == 'enum':
obj = objects.Enumeration
additional = {"base_type": self.get_type('void'), "choices": {}}
elif type_name == 'bitfield':
obj = objects.BitField
additional = {"start_bit": 0, "end_bit": 0, "base_type": self.get_type('void')}
elif type_name == 'string':
obj = objects.String
additional = {"max_length": 0}
elif type_name == 'bytes':
obj = objects.Bytes
additional = {"length": 0}
if obj is not None:
return objects.templates.ObjectTemplate(obj, type_name = prefix + type_name, **additional)
_native_type, native_format = self._native_dictionary[type_name]
if type_name == 'pointer':
additional = {'subtype': self.get_type('void')}
return objects.templates.ObjectTemplate(
self.get_type_class(type_name), # pylint: disable=W0142
type_name = prefix + type_name,
data_format = objects.DataFormatInfo(*native_format),
**additional)
std_ctypes = {
'int': (objects.Integer, (4, "little", True)),
'long': (objects.Integer, (4, "little", True)),
'unsigned long': (objects.Integer, (4, "little", False)),
'unsigned int': (objects.Integer, (4, "little", False)),
'char': (objects.Integer, (1, "little", True)),
'byte': (objects.Bytes, (1, "little", True)),
'unsigned char': (objects.Integer, (1, "little", False)),
'unsigned short int': (objects.Integer, (2, "little", False)),
'unsigned short': (objects.Integer, (2, "little", False)),
'unsigned be short': (objects.Integer, (2, "big", False)),
'short': (objects.Integer, (2, "little", True)),
'long long': (objects.Integer, (8, "little", True)),
'unsigned long long': (objects.Integer, (8, "little", True)),
'float': (objects.Float, (4, "little", True)),
'double': (objects.Float, (8, "little", True)),
'wchar': (objects.Integer, (2, "little", False))
}
native_types = std_ctypes.copy()
native_types['pointer'] = (objects.Pointer, (4, "little", False))
x86NativeTable = NativeTable("native", native_types)
native_types['pointer'] = (objects.Pointer, (8, "little", False))
x64NativeTable = NativeTable("native", native_types)