mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-06 01:37:39 +02:00
Merge branch 'volatilityfoundation:develop' into develop
This commit is contained in:
@@ -300,7 +300,7 @@ This will mean that when a specific structure is loaded from the symbol_space, i
|
||||
`StructType`, but instead is instantiated using the NewStructureClass, meaning new methods can be called directly on it.
|
||||
|
||||
If the situation really calls for an entirely new object, that isn't covered by one of the existing
|
||||
:py:class:`~volatility3.framework.objects.PrimativeObject` objects (such as
|
||||
:py:class:`~volatility3.framework.objects.PrimitiveObject` objects (such as
|
||||
:py:class:`~volatility3.framework.objects.Integer`,
|
||||
:py:class:`~volatility3.framework.objects.Boolean`,
|
||||
:py:class:`~volatility3.framework.objects.Float`,
|
||||
|
||||
@@ -145,7 +145,7 @@ Struct, Structure
|
||||
|
||||
Symbol
|
||||
This is used in many different contexts, as a short term for many things. Within Volatility, a symbol is a
|
||||
construct that usually encompasses a specific type :ref:`type<Type>` at a specfific :ref:`offset<Offset>`,
|
||||
construct that usually encompasses a specific type :ref:`type<Type>` at a specific :ref:`offset<Offset>`,
|
||||
representing a particular instance of that type within the memory of a compiled and running program. An example
|
||||
would be the location in memory of a list of active tcp endpoints maintained by the networking stack
|
||||
within an operating system.
|
||||
|
||||
@@ -206,9 +206,9 @@ information may not be provided.
|
||||
|
||||
The plugin then takes the process's ``BaseDllName`` value, and calls :py:meth:`~volatility3.framework.symbols.windows.extensions.UNICODE_STRING.get_string` on it. All structure attributes,
|
||||
as defined by the symbols, are directly accessible and use the case-style of the symbol library it came from (in Windows,
|
||||
attributes are CamelCase), such as ``entry.BaseDllName`` in this instance. Any attribtues not defined by the symbol but added
|
||||
attributes are CamelCase), such as ``entry.BaseDllName`` in this instance. Any attributes not defined by the symbol but added
|
||||
by Volatility extensions cannot be properties (in case they overlap with the attributes defined in the symbol libraries)
|
||||
and are therefore always methods and prepended with ``get_``, in this example ``BaseDllName.get_string()``.
|
||||
and are therefore always methods and pretended with ``get_``, in this example ``BaseDllName.get_string()``.
|
||||
|
||||
Finally, ``FullDllName`` is populated. These operations read from memory, and as such, the memory image may be unable to
|
||||
read the data at a particular offset. This will cause an exception to be thrown. In Volatility 3, exceptions are thrown
|
||||
|
||||
@@ -19,6 +19,7 @@ import os
|
||||
import sys
|
||||
import tempfile
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, Type, Union
|
||||
from urllib import parse, request
|
||||
|
||||
@@ -157,6 +158,10 @@ class CommandLine:
|
||||
help = "Write configuration JSON file out to config.json",
|
||||
default = False,
|
||||
action = 'store_true')
|
||||
parser.add_argument("--save-config",
|
||||
help = "Save configuration JSON file to a file",
|
||||
default = None,
|
||||
type = str)
|
||||
parser.add_argument("--clear-cache",
|
||||
help = "Clears out all short-term cached items",
|
||||
default = False,
|
||||
@@ -320,8 +325,13 @@ class CommandLine:
|
||||
self.file_handler_class_factory())
|
||||
|
||||
if args.write_config:
|
||||
vollog.debug("Writing out configuration data to config.json")
|
||||
with open("config.json", "w") as f:
|
||||
vollog.warning('Use of --write-config has been deprecated, replaced by --save-config <filename>')
|
||||
args.save_config = 'config.json'
|
||||
if args.save_config:
|
||||
vollog.debug("Writing out configuration data to {args.save_config}")
|
||||
if os.path.exists(os.path.abspath(args.save_config)):
|
||||
parser.error(f"Cannot write configuration: file {args.save_config} already exists")
|
||||
with open(args.save_config, "w") as f:
|
||||
json.dump(dict(constructed.build_configuration()), f, sort_keys = True, indent = 2)
|
||||
except exceptions.UnsatisfiedException as excp:
|
||||
self.process_unsatisfied_exceptions(excp)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
import csv
|
||||
import datetime
|
||||
import json
|
||||
import logging
|
||||
@@ -8,7 +9,7 @@ import random
|
||||
import string
|
||||
import sys
|
||||
from functools import wraps
|
||||
from typing import Callable, Any, List, Tuple, Dict
|
||||
from typing import Any, Callable, Dict, List, Tuple
|
||||
|
||||
from volatility3.framework import interfaces, renderers
|
||||
from volatility3.framework.renderers import format_hints
|
||||
@@ -66,7 +67,6 @@ def multitypedata_as_text(value: format_hints.MultiTypeData) -> str:
|
||||
|
||||
|
||||
def optional(func: Callable) -> Callable:
|
||||
|
||||
@wraps(func)
|
||||
def wrapped(x: Any) -> str:
|
||||
if isinstance(x, interfaces.renderers.BaseAbsentValue):
|
||||
@@ -80,7 +80,6 @@ def optional(func: Callable) -> Callable:
|
||||
|
||||
|
||||
def quoted_optional(func: Callable) -> Callable:
|
||||
|
||||
@wraps(func)
|
||||
def wrapped(x: Any) -> str:
|
||||
result = optional(func)(x)
|
||||
@@ -102,7 +101,7 @@ def display_disassembly(disasm: interfaces.renderers.Disassembly) -> str:
|
||||
disasm: Input disassembly objects
|
||||
|
||||
Returns:
|
||||
A string as rendererd by capstone where available, otherwise output as if it were just bytes
|
||||
A string as rendered by capstone where available, otherwise output as if it were just bytes
|
||||
"""
|
||||
|
||||
if CAPSTONE_PRESENT:
|
||||
@@ -193,16 +192,17 @@ class NoneRenderer(CLIRenderer):
|
||||
if not grid.populated:
|
||||
grid.populate(lambda x, y: True, True)
|
||||
|
||||
|
||||
class CSVRenderer(CLIRenderer):
|
||||
_type_renderers = {
|
||||
format_hints.Bin: quoted_optional(lambda x: f"0b{x:b}"),
|
||||
format_hints.Hex: quoted_optional(lambda x: f"0x{x:x}"),
|
||||
format_hints.HexBytes: quoted_optional(hex_bytes_as_text),
|
||||
format_hints.MultiTypeData: quoted_optional(multitypedata_as_text),
|
||||
interfaces.renderers.Disassembly: quoted_optional(display_disassembly),
|
||||
bytes: quoted_optional(lambda x: " ".join([f"{b:02x}" for b in x])),
|
||||
datetime.datetime: quoted_optional(lambda x: x.strftime("%Y-%m-%d %H:%M:%S.%f %Z")),
|
||||
'default': quoted_optional(lambda x: f"{x}")
|
||||
format_hints.Bin: optional(lambda x: f"0b{x:b}"),
|
||||
format_hints.Hex: optional(lambda x: f"0x{x:x}"),
|
||||
format_hints.HexBytes: optional(hex_bytes_as_text),
|
||||
format_hints.MultiTypeData: optional(multitypedata_as_text),
|
||||
interfaces.renderers.Disassembly: optional(display_disassembly),
|
||||
bytes: optional(lambda x: " ".join([f"{b:02x}" for b in x])),
|
||||
datetime.datetime: optional(lambda x: x.strftime("%Y-%m-%d %H:%M:%S.%f %Z")),
|
||||
'default': optional(lambda x: f"{x}")
|
||||
}
|
||||
|
||||
name = "csv"
|
||||
@@ -219,28 +219,28 @@ class CSVRenderer(CLIRenderer):
|
||||
"""
|
||||
outfd = sys.stdout
|
||||
|
||||
line = ['"TreeDepth"']
|
||||
header_list = ['TreeDepth']
|
||||
for column in grid.columns:
|
||||
# Ignore the type because namedtuples don't realize they have accessible attributes
|
||||
line.append("{}".format('"' + column.name + '"'))
|
||||
outfd.write(f"{','.join(line)}")
|
||||
header_list.append(f"{column.name}")
|
||||
|
||||
writer = csv.DictWriter(outfd, header_list)
|
||||
writer.writeheader()
|
||||
|
||||
def visitor(node: interfaces.renderers.TreeNode, accumulator):
|
||||
accumulator.write("\n")
|
||||
# Nodes always have a path value, giving them a path_depth of at least 1, we use max just in case
|
||||
accumulator.write(str(max(0, node.path_depth - 1)) + ",")
|
||||
line = []
|
||||
row = {'TreeDepth': str(max(0, node.path_depth - 1))}
|
||||
for column_index in range(len(grid.columns)):
|
||||
column = grid.columns[column_index]
|
||||
renderer = self._type_renderers.get(column.type, self._type_renderers['default'])
|
||||
line.append(renderer(node.values[column_index]))
|
||||
accumulator.write(f"{','.join(line)}")
|
||||
row[f'{column.name}'] = renderer(node.values[column_index])
|
||||
accumulator.writerow(row)
|
||||
return accumulator
|
||||
|
||||
if not grid.populated:
|
||||
grid.populate(visitor, outfd)
|
||||
grid.populate(visitor, writer)
|
||||
else:
|
||||
grid.visit(node = None, function = visitor, initial_accumulator = outfd)
|
||||
grid.visit(node = None, function = visitor, initial_accumulator = writer)
|
||||
|
||||
outfd.write("\n")
|
||||
|
||||
@@ -274,7 +274,8 @@ class PrettyTextRenderer(CLIRenderer):
|
||||
max_column_widths = dict([(column.name, len(column.name)) for column in grid.columns])
|
||||
|
||||
def visitor(
|
||||
node: interfaces.renderers.TreeNode, accumulator: List[Tuple[int, Dict[interfaces.renderers.Column, bytes]]]
|
||||
node: interfaces.renderers.TreeNode,
|
||||
accumulator: List[Tuple[int, Dict[interfaces.renderers.Column, bytes]]]
|
||||
) -> List[Tuple[int, Dict[interfaces.renderers.Column, bytes]]]:
|
||||
# Nodes always have a path value, giving them a path_depth of at least 1, we use max just in case
|
||||
max_column_widths[tree_indent_column] = max(max_column_widths.get(tree_indent_column, 0), node.path_depth)
|
||||
|
||||
@@ -85,6 +85,10 @@ class VolShell(cli.CommandLine):
|
||||
help = "Write configuration JSON file out to config.json",
|
||||
default = False,
|
||||
action = 'store_true')
|
||||
parser.add_argument("--save-config",
|
||||
help = "Save configuration JSON file to a file",
|
||||
default = None,
|
||||
type = str)
|
||||
parser.add_argument("--clear-cache",
|
||||
help = "Clears out all short-term cached items",
|
||||
default = False,
|
||||
@@ -234,8 +238,13 @@ class VolShell(cli.CommandLine):
|
||||
self.file_handler_class_factory())
|
||||
|
||||
if args.write_config:
|
||||
vollog.debug("Writing out configuration data to config.json")
|
||||
with open("config.json", "w") as f:
|
||||
vollog.warning('Use of --write-config has been deprecated, replaced by --save-config <filename>')
|
||||
args.save_config = 'config.json'
|
||||
if args.save_config:
|
||||
vollog.debug("Writing out configuration data to {args.save_config}")
|
||||
if os.path.exists(os.path.abspath(args.save_config)):
|
||||
parser.error(f"Cannot write configuration: file {args.save_config} already exists")
|
||||
with open(args.save_config, "w") as f:
|
||||
json.dump(dict(constructed.build_configuration()), f, sort_keys = True, indent = 2)
|
||||
except exceptions.UnsatisfiedException as excp:
|
||||
self.process_unsatisfied_exceptions(excp)
|
||||
|
||||
@@ -28,9 +28,9 @@ The self-referential indices for older versions of windows are listed below:
|
||||
"""
|
||||
import logging
|
||||
import struct
|
||||
from typing import Generator, List, Optional, Tuple, Type, Iterable
|
||||
from typing import Generator, Iterable, List, Optional, Tuple, Type
|
||||
|
||||
from volatility3.framework import interfaces, layers, constants
|
||||
from volatility3.framework import constants, interfaces, layers
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.layers import intel
|
||||
|
||||
@@ -116,10 +116,27 @@ class DtbSelfRefPae(DtbSelfReferential):
|
||||
mask = 0x3FFFFFFFFFF000,
|
||||
reserved_bits = 0x0)
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
dtb = super().__call__(*args, **kwargs)
|
||||
@staticmethod
|
||||
def _and_bytes(abytes, bbytes):
|
||||
return bytes([a & b for a, b in zip(abytes[::-1], bbytes[::-1])][::-1])
|
||||
|
||||
def __call__(self, data: bytes, data_offset: int, page_offset: int) -> Optional[Tuple[int, int]]:
|
||||
dtb = super().__call__(data, data_offset, page_offset)
|
||||
if dtb:
|
||||
return dtb[0] - 0x4000, dtb[1]
|
||||
# Find the top page
|
||||
top_pae_page = dtb[0] - 0x4000
|
||||
# The top page should map to the next four pages after it
|
||||
# Build what we expect the page table to be
|
||||
expected_table = b''.join([struct.pack(self.ptr_struct, top_pae_page + (i * 0x1000)) for i in range(1, 5)])
|
||||
# Mask off the page bits of top level page map
|
||||
page_table_mask = b"\x00\xf0\xff\xff\xff\xff\xff\xff" * 4
|
||||
page_table = data[top_pae_page - data_offset: top_pae_page - data_offset + (4 * self.ptr_size)]
|
||||
# Compare them
|
||||
anded_bytes = self._and_bytes(page_table, page_table_mask)
|
||||
if (anded_bytes == expected_table):
|
||||
return top_pae_page, dtb[1]
|
||||
# Return None since the dtb value *isn't* None
|
||||
return None
|
||||
return dtb
|
||||
|
||||
|
||||
@@ -202,30 +219,50 @@ class WindowsIntelStacker(interfaces.automagic.StackerLayerInterface):
|
||||
for description, tests, sections in cls.test_sets:
|
||||
vollog.debug(description)
|
||||
# There is a very high chance that the DTB will live in these very narrow segments, assuming we couldn't find them previously
|
||||
hits = context.layers[layer_name].scan(context,
|
||||
PageMapScanner(tests = tests),
|
||||
sections = sections,
|
||||
progress_callback = progress_callback)
|
||||
hits = base_layer.scan(context,
|
||||
PageMapScanner(tests = tests),
|
||||
sections = sections,
|
||||
progress_callback = progress_callback)
|
||||
|
||||
# Flatten the generator
|
||||
def sort_by_tests(x):
|
||||
"""Key used to sort by tests"""
|
||||
return tests.index(x[0]), x[1]
|
||||
|
||||
def get_max_pointer(page_table, test, ptr_size: int):
|
||||
"""Determines a pointer from a page_table"""
|
||||
max_ptr = 0
|
||||
for index in range(0, len(page_table), ptr_size):
|
||||
pointer = struct.unpack(test.ptr_struct, page_table[index:index + ptr_size])[0]
|
||||
# Make sure the pointer is valid, ignore large pages which would require more calculation
|
||||
if pointer & 0x1 and not pointer & 0x80:
|
||||
max_ptr = max(max_ptr, (pointer ^ (pointer & 0xfff)) % test.layer_type.maximum_address)
|
||||
return max_ptr
|
||||
|
||||
hits = sorted(list(hits), key = sort_by_tests)
|
||||
|
||||
if hits:
|
||||
# TODO: Decide which to use if there are multiple options
|
||||
test, page_map_offset = hits[0]
|
||||
vollog.debug(f"{test.__class__.__name__} test succeeded at {hex(page_map_offset)}")
|
||||
new_layer_name = context.layers.free_layer_name("IntelLayer")
|
||||
config_path = interfaces.configuration.path_join("IntelHelper", new_layer_name)
|
||||
context.config[interfaces.configuration.path_join(config_path, "memory_layer")] = layer_name
|
||||
context.config[interfaces.configuration.path_join(config_path, "page_map_offset")] = page_map_offset
|
||||
# TODO: Need to determine the layer type (chances are high it's x64, hence this default)
|
||||
layer = test.layer_type(context,
|
||||
config_path = config_path,
|
||||
name = new_layer_name,
|
||||
metadata = {'os': 'Windows'})
|
||||
for test, page_map_offset in hits:
|
||||
# Turn the page tables into integers and find the largest one
|
||||
page_table = base_layer.read(page_map_offset, 0x1000)
|
||||
ptr_size = struct.calcsize(test.ptr_struct)
|
||||
max_pointer = get_max_pointer(page_table, test, ptr_size)
|
||||
|
||||
if max_pointer <= base_layer.maximum_address:
|
||||
vollog.debug(f"{test.__class__.__name__} test succeeded at {hex(page_map_offset)}")
|
||||
new_layer_name = context.layers.free_layer_name("IntelLayer")
|
||||
config_path = interfaces.configuration.path_join("IntelHelper", new_layer_name)
|
||||
context.config[interfaces.configuration.path_join(config_path, "memory_layer")] = layer_name
|
||||
context.config[
|
||||
interfaces.configuration.path_join(config_path, "page_map_offset")] = page_map_offset
|
||||
layer = test.layer_type(context,
|
||||
config_path = config_path,
|
||||
name = new_layer_name,
|
||||
metadata = {'os': 'Windows'})
|
||||
break
|
||||
else:
|
||||
vollog.debug(
|
||||
f"Max pointer for hit with test {test.__class__.__name__} not met: {hex(max_pointer)} > {hex(base_layer.maximum_address)}")
|
||||
if layer is not None and config_path:
|
||||
break
|
||||
|
||||
if layer is not None and config_path:
|
||||
|
||||
@@ -9,7 +9,7 @@ volatility This includes default scanning block sizes, etc.
|
||||
import enum
|
||||
import os.path
|
||||
import sys
|
||||
from typing import Optional, Callable
|
||||
from typing import Callable, Optional
|
||||
|
||||
import volatility3.framework.constants.linux
|
||||
import volatility3.framework.constants.windows
|
||||
@@ -63,7 +63,7 @@ LOGLEVEL_VVVV = 6
|
||||
CACHE_PATH = os.path.join(os.path.expanduser("~"), ".cache", "volatility3")
|
||||
"""Default path to store cached data"""
|
||||
|
||||
if sys.platform == 'windows':
|
||||
if sys.platform == 'win32':
|
||||
CACHE_PATH = os.path.join(os.environ.get("APPDATA", os.path.expanduser("~")), "volatility3")
|
||||
os.makedirs(CACHE_PATH, exist_ok = True)
|
||||
|
||||
@@ -80,6 +80,7 @@ ProgressCallback = Optional[Callable[[float, str], None]]
|
||||
|
||||
OS_CATEGORIES = ['windows', 'mac', 'linux']
|
||||
|
||||
|
||||
class Parallelism(enum.IntEnum):
|
||||
"""An enumeration listing the different types of parallelism applied to
|
||||
volatility."""
|
||||
|
||||
@@ -141,7 +141,7 @@ class Context(interfaces.context.ContextInterface):
|
||||
layer_name: The layer within the context in which the module exists
|
||||
offset: The offset at which the module exists in the layer
|
||||
native_layer_name: The default native layer for objects constructed by the module
|
||||
size: The size, in bytes, that the module occupys from offset location within the layer named layer_name
|
||||
size: The size, in bytes, that the module occupies from offset location within the layer named layer_name
|
||||
"""
|
||||
if size:
|
||||
return SizedModule.create(self,
|
||||
|
||||
@@ -73,7 +73,7 @@ class HierarchicalDict(collections.abc.Mapping):
|
||||
separator: str = CONFIG_SEPARATOR) -> None:
|
||||
"""
|
||||
Args:
|
||||
initial_dict: A dictionary to populate the HierachicalDict with initially
|
||||
initial_dict: A dictionary to populate the HierarchicalDict with initially
|
||||
separator: A custom hierarchy separator (defaults to CONFIG_SEPARATOR)
|
||||
"""
|
||||
if not (isinstance(separator, str) and len(separator) == 1):
|
||||
|
||||
@@ -129,7 +129,7 @@ class ContextInterface(metaclass = ABCMeta):
|
||||
layer_name: The layer the module is associated with (which layer the module lives within)
|
||||
offset: The initial/base offset of the module (used as the offset for relative symbols)
|
||||
native_layer_name: The default native_layer_name to use when the module constructs objects
|
||||
size: The size, in bytes, that the module occupys from offset location within the layer named layer_name
|
||||
size: The size, in bytes, that the module occupies from offset location within the layer named layer_name
|
||||
|
||||
Returns:
|
||||
A module object
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
"""All plugins output a TreeGrid object which must then be rendered (eithe by a
|
||||
"""All plugins output a TreeGrid object which must then be rendered (either by a
|
||||
GUI, or as text output, html output or in some other form.
|
||||
|
||||
This module defines both the output format (:class:`TreeGrid`) and the
|
||||
|
||||
@@ -31,7 +31,7 @@ class BytesScanner(layers.ScannerInterface):
|
||||
|
||||
class RegExScanner(layers.ScannerInterface):
|
||||
"""A scanner that can be provided with a bytes-object regular expression pattern
|
||||
The scanner will scqn all blocks for the regular expression and report the absolute offset of any finds
|
||||
The scanner will scan all blocks for the regular expression and report the absolute offset of any finds
|
||||
|
||||
The default flags include DOTALL, since the searches are through binary data and the newline character should
|
||||
have no specific significance in such searches"""
|
||||
@@ -95,7 +95,7 @@ class MultiStringScanner(layers.ScannerInterface):
|
||||
else:
|
||||
suffixes.append(re.escape(bytes([entry])))
|
||||
else:
|
||||
# If we've fininshed one of the strings at this point, remember it for later
|
||||
# If we've finished one of the strings at this point, remember it for later
|
||||
finished = True
|
||||
|
||||
if len(suffixes) == 1:
|
||||
|
||||
@@ -206,7 +206,7 @@ class Bytes(PrimitiveObject, bytes):
|
||||
length: int = 1,
|
||||
**kwargs) -> 'Bytes':
|
||||
"""Creates the appropriate class and returns it so that the native type
|
||||
is inherritted.
|
||||
is inherited.
|
||||
|
||||
The only reason the kwargs is added, is so that the
|
||||
inheriting types can override __init__ without needing to
|
||||
@@ -704,7 +704,7 @@ class AggregateType(interfaces.objects.ObjectInterface):
|
||||
tmp_list[member] = (relative_offset, new_child)
|
||||
# If there's trouble with mutability, consider making update_vol return a clone with the changes
|
||||
# (there will be a few other places that will be necessary) and/or making these part of the
|
||||
# permanent dictionaries rather than the non-clonable ones
|
||||
# permanent dictionaries rather than the non-cloneable ones
|
||||
template.update_vol(members = tmp_list)
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# This file is Copyright 2022 Volatility Foundation and licensed under the Volatility Software License 1.0
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
"""All core mac plugins.
|
||||
|
||||
These modules should only be imported from volatility3.plugins NOT
|
||||
volatility3.framework.plugins
|
||||
"""
|
||||
|
||||
@@ -9,7 +9,7 @@ from volatility3.framework.symbols import mac
|
||||
|
||||
|
||||
class Ifconfig(plugins.PluginInterface):
|
||||
"""Lists loaded kernel modules"""
|
||||
"""Lists network interface information for all devices"""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from volatility3.framework.symbols import mac
|
||||
|
||||
class Mount(plugins.PluginInterface):
|
||||
"""A module containing a collection of plugins that produce data typically
|
||||
foundin Mac's mount command"""
|
||||
found in Mac's mount command"""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
import binascii
|
||||
import hashlib
|
||||
import logging
|
||||
from struct import unpack, pack
|
||||
from typing import List, Tuple, Optional
|
||||
from struct import pack, unpack
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from Crypto.Cipher import ARC4, DES, AES
|
||||
from Crypto.Cipher import AES, ARC4, DES
|
||||
from Crypto.Hash import MD5
|
||||
|
||||
from volatility3.framework import interfaces, renderers
|
||||
@@ -28,7 +28,7 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.PluginRequirement(name = 'hivelist', plugin = hivelist.HiveList, version = (1, 0, 0))
|
||||
]
|
||||
|
||||
@@ -63,7 +63,8 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
def get_hive_key(cls, hive: registry.RegistryHive, key: str):
|
||||
result = None
|
||||
try:
|
||||
result = hive.get_key(key)
|
||||
if hive:
|
||||
result = hive.get_key(key)
|
||||
except KeyError:
|
||||
vollog.info(
|
||||
f"Unable to load the required registry key {hive.get_name()}\\{key} from this memory image")
|
||||
@@ -132,7 +133,7 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
rc4_key = md5.digest()
|
||||
|
||||
rc4 = ARC4.new(rc4_key)
|
||||
hbootkey = rc4.encrypt(sam_data[0x80:0xA0]) # lgtm [py/weak-cryptographic-algorithm]
|
||||
hbootkey = rc4.encrypt(sam_data[0x80:0xA0]) # lgtm [py/weak-cryptographic-algorithm]
|
||||
return hbootkey
|
||||
elif revision == 3:
|
||||
# AES encrypted
|
||||
@@ -151,7 +152,7 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
des2 = DES.new(des_k2, DES.MODE_ECB)
|
||||
cipher = AES.new(hbootkey[:16], AES.MODE_CBC, salt)
|
||||
obfkey = cipher.decrypt(enc_hash)
|
||||
return des1.decrypt(obfkey[:8]) + des2.decrypt(obfkey[8:16]) # lgtm [py/weak-cryptographic-algorithm]
|
||||
return des1.decrypt(obfkey[:8]) + des2.decrypt(obfkey[8:16]) # lgtm [py/weak-cryptographic-algorithm]
|
||||
|
||||
@classmethod
|
||||
def get_user_hashes(cls, user: registry.CM_KEY_NODE, samhive: registry.RegistryHive,
|
||||
@@ -229,9 +230,9 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
md5.update(hbootkey[:0x10] + pack("<L", rid) + lmntstr)
|
||||
rc4_key = md5.digest()
|
||||
rc4 = ARC4.new(rc4_key)
|
||||
obfkey = rc4.encrypt(enc_hash) # lgtm [py/weak-cryptographic-algorithm]
|
||||
obfkey = rc4.encrypt(enc_hash) # lgtm [py/weak-cryptographic-algorithm]
|
||||
|
||||
return des1.decrypt(obfkey[:8]) + des2.decrypt(obfkey[8:]) # lgtm [py/weak-cryptographic-algorithm]
|
||||
return des1.decrypt(obfkey[:8]) + des2.decrypt(obfkey[8:]) # lgtm [py/weak-cryptographic-algorithm]
|
||||
|
||||
@classmethod
|
||||
def get_user_name(cls, user: registry.CM_KEY_NODE, samhive: registry.RegistryHive) -> Optional[bytes]:
|
||||
@@ -253,13 +254,9 @@ class Hashdump(interfaces.plugins.PluginInterface):
|
||||
# replaces the dump_hashes method in vol2
|
||||
def _generator(self, syshive: registry.RegistryHive, samhive: registry.RegistryHive):
|
||||
if syshive is None:
|
||||
vollog.debug("SYSTEM address is None: Did you use the correct profile?")
|
||||
yield (0, (renderers.NotAvailableValue(), renderers.NotAvailableValue(), renderers.NotAvailableValue(),
|
||||
renderers.NotAvailableValue()))
|
||||
vollog.debug("SYSTEM address is None: No system hive found")
|
||||
if samhive is None:
|
||||
vollog.debug("SAM address is None: Did you use the correct profile?")
|
||||
yield (0, (renderers.NotAvailableValue(), renderers.NotAvailableValue(), renderers.NotAvailableValue(),
|
||||
renderers.NotAvailableValue()))
|
||||
vollog.debug("SAM address is None: No SAM hive found")
|
||||
bootkey = self.get_bootkey(syshive)
|
||||
hbootkey = self.get_hbootkey(samhive, bootkey)
|
||||
if hbootkey:
|
||||
|
||||
@@ -53,7 +53,7 @@ class Malfind(interfaces.plugins.PluginInterface):
|
||||
"""
|
||||
|
||||
CHUNK_SIZE = 0x1000
|
||||
all_zero_page = "\x00" * CHUNK_SIZE
|
||||
all_zero_page = b"\x00" * CHUNK_SIZE
|
||||
|
||||
offset = 0
|
||||
vad_length = vad.get_end() - vad.get_start()
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
# This file is Copyright 2022 Volatility Foundation and licensed under the Volatility Software License 1.0
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
|
||||
import logging
|
||||
import hashlib
|
||||
|
||||
from typing import Iterator, List, Tuple
|
||||
|
||||
from volatility3.framework import constants, exceptions, interfaces, renderers, symbols
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.layers import scanners
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.symbols import intermed
|
||||
from volatility3.framework.symbols.windows.extensions import mbr
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
class MBRScan(interfaces.plugins.PluginInterface):
|
||||
"""Scans for and parses potential Master Boot Records (MBRs)"""
|
||||
|
||||
_required_framework_version = (2, 0, 1)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls)-> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel',
|
||||
architectures = ["Intel32", "Intel64"]),
|
||||
requirements.BooleanRequirement(name = 'full',
|
||||
description ="It analyzes and provides all the information in the partition entry and bootcode hexdump. (It returns a lot of information, so we recommend you render it in CSV.)",
|
||||
default = False,
|
||||
optional = True)
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def get_hash(cls, data:bytes) -> str:
|
||||
return hashlib.md5(data).hexdigest()
|
||||
|
||||
def _generator(self) -> Iterator[Tuple]:
|
||||
kernel = self.context.modules[self.config['kernel']]
|
||||
physical_layer_name = self.context.layers[kernel.layer_name].config.get('memory_layer', None)
|
||||
|
||||
# Decide of Memory Dump Architecture
|
||||
layer = self.context.layers[physical_layer_name]
|
||||
architecture = "intel" if not symbols.symbol_table_is_64bit(self.context, kernel.symbol_table_name) else "intel64"
|
||||
|
||||
# Read in the Symbol File
|
||||
symbol_table = intermed.IntermediateSymbolTable.create(context = self.context,
|
||||
config_path = self.config_path,
|
||||
sub_path = "windows",
|
||||
filename = "mbr",
|
||||
class_types = {
|
||||
'PARTITION_TABLE': mbr.PARTITION_TABLE,
|
||||
'PARTITION_ENTRY': mbr.PARTITION_ENTRY
|
||||
})
|
||||
|
||||
partition_table_object = symbol_table + constants.BANG + "PARTITION_TABLE"
|
||||
|
||||
# Define Signature and Data Length
|
||||
mbr_signature = b"\x55\xAA"
|
||||
mbr_length = 0x200
|
||||
bootcode_length = 0x1B8
|
||||
|
||||
# Scan the Layer for Raw Master Boot Record (MBR) and parse the fields
|
||||
for offset, _value in layer.scan(context = self.context, scanner = scanners.MultiStringScanner(patterns = [mbr_signature])):
|
||||
try:
|
||||
mbr_start_offset = offset - (mbr_length - len(mbr_signature))
|
||||
partition_table = self.context.object(partition_table_object, offset = mbr_start_offset, layer_name = layer.name)
|
||||
|
||||
# Extract only BootCode
|
||||
full_mbr = layer.read(mbr_start_offset, mbr_length, pad = True)
|
||||
bootcode = full_mbr[:bootcode_length]
|
||||
|
||||
all_zeros = None
|
||||
|
||||
if bootcode:
|
||||
all_zeros = bootcode.count(b"\x00") == len(bootcode)
|
||||
|
||||
if not all_zeros:
|
||||
|
||||
partition_entries = [
|
||||
partition_table.FirstEntry, partition_table.SecondEntry,
|
||||
partition_table.ThirdEntry, partition_table.FourthEntry
|
||||
]
|
||||
|
||||
if not self.config.get("full", True):
|
||||
yield (0, (
|
||||
format_hints.Hex(offset),
|
||||
partition_table.get_disk_signature(),
|
||||
self.get_hash(bootcode),
|
||||
self.get_hash(full_mbr),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
interfaces.renderers.Disassembly(bootcode, 0, architecture)
|
||||
))
|
||||
else:
|
||||
yield (0, (
|
||||
format_hints.Hex(offset),
|
||||
partition_table.get_disk_signature(),
|
||||
self.get_hash(bootcode),
|
||||
self.get_hash(full_mbr),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue(),
|
||||
interfaces.renderers.Disassembly(bootcode, 0, architecture),
|
||||
format_hints.HexBytes(bootcode)
|
||||
))
|
||||
|
||||
for partition_index, partition_entry_object in enumerate(partition_entries, start=1):
|
||||
|
||||
if not self.config.get("full", True):
|
||||
yield (1, (
|
||||
format_hints.Hex(offset),
|
||||
partition_table.get_disk_signature(),
|
||||
self.get_hash(bootcode),
|
||||
self.get_hash(full_mbr),
|
||||
partition_index,
|
||||
partition_entry_object.is_bootable(),
|
||||
partition_entry_object.get_partition_type(),
|
||||
format_hints.Hex(partition_entry_object.get_size_in_sectors()),
|
||||
renderers.NotApplicableValue()
|
||||
))
|
||||
else:
|
||||
yield (1, (
|
||||
format_hints.Hex(offset),
|
||||
partition_table.get_disk_signature(),
|
||||
self.get_hash(bootcode),
|
||||
self.get_hash(full_mbr),
|
||||
partition_index,
|
||||
partition_entry_object.is_bootable(),
|
||||
format_hints.Hex(partition_entry_object.get_bootable_flag()),
|
||||
partition_entry_object.get_partition_type(),
|
||||
format_hints.Hex(partition_entry_object.PartitionType),
|
||||
format_hints.Hex(partition_entry_object.get_starting_lba()),
|
||||
partition_entry_object.get_starting_cylinder(),
|
||||
partition_entry_object.get_starting_chs(),
|
||||
partition_entry_object.get_starting_sector(),
|
||||
partition_entry_object.get_ending_cylinder(),
|
||||
partition_entry_object.get_ending_chs(),
|
||||
partition_entry_object.get_ending_sector(),
|
||||
format_hints.Hex(partition_entry_object.get_size_in_sectors()),
|
||||
renderers.NotApplicableValue(),
|
||||
renderers.NotApplicableValue()
|
||||
))
|
||||
else:
|
||||
vollog.log(constants.LOGLEVEL_VVVV, f"Not a valid MBR: Data all zeroed out : {format_hints.Hex(offset)}")
|
||||
continue
|
||||
|
||||
except exceptions.PagedInvalidAddressException as excp:
|
||||
vollog.log(constants.LOGLEVEL_VVVV, f"Invalid address identified in guessed MBR: {hex(excp.invalid_address)}")
|
||||
continue
|
||||
|
||||
def run(self)-> renderers.TreeGrid:
|
||||
if not self.config.get("full", True):
|
||||
return renderers.TreeGrid([
|
||||
("Potential MBR at Physical Offset", format_hints.Hex),
|
||||
("Disk Signature", str),
|
||||
("Bootcode MD5", str),
|
||||
("Full MBR MD5", str),
|
||||
("PartitionIndex", int),
|
||||
("Bootable", bool),
|
||||
("PartitionType", str),
|
||||
("SectorInSize", format_hints.Hex),
|
||||
("Disasm", interfaces.renderers.Disassembly)
|
||||
], self._generator())
|
||||
else:
|
||||
return renderers.TreeGrid([
|
||||
("Potential MBR at Physical Offset", format_hints.Hex),
|
||||
("Disk Signature", str),
|
||||
("Bootcode MD5", str),
|
||||
("Full MBR MD5", str),
|
||||
("PartitionIndex", int),
|
||||
("Bootable", bool),
|
||||
("BootFlag", format_hints.Hex),
|
||||
("PartitionType", str),
|
||||
("PartitionTypeRaw", format_hints.Hex),
|
||||
("StartingLBA", format_hints.Hex),
|
||||
("StartingCylinder", int),
|
||||
("StartingCHS", int),
|
||||
("StartingSector", int),
|
||||
("EndingCylinder", int),
|
||||
("EndingCHS", int),
|
||||
("EndingSector", int),
|
||||
("SectorInSize", format_hints.Hex),
|
||||
("Disasm", interfaces.renderers.Disassembly),
|
||||
("Bootcode", format_hints.HexBytes)
|
||||
], self._generator())
|
||||
@@ -55,14 +55,14 @@ class Privs(interfaces.plugins.PluginInterface):
|
||||
try:
|
||||
process_token = task.Token.dereference().cast("_TOKEN")
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.log(constants.LOGLEVEL_VVV, 'Skeep invalid token.')
|
||||
vollog.log(constants.LOGLEVEL_VVV, 'Skip invalid token.')
|
||||
continue
|
||||
|
||||
for value, present, enabled, default in process_token.privileges():
|
||||
# Skip privileges whose bit positions cannot be
|
||||
# translated to a privilege name
|
||||
if not self.privilege_info.get(int(value)):
|
||||
vollog.log(constants.LOGLEVEL_VVV, f'Skeep invalid privilege ({value}).')
|
||||
vollog.log(constants.LOGLEVEL_VVV, f'Skip invalid privilege ({value}).')
|
||||
continue
|
||||
|
||||
name, desc = self.privilege_info.get(int(value))
|
||||
|
||||
@@ -85,7 +85,7 @@ class PsScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
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
|
||||
proc: the process object with phisical address
|
||||
proc: the process object with physical address
|
||||
|
||||
Returns:
|
||||
A process object on virtual address layer
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# This file is Copyright 2020 Volatility Foundation and licensed under the Volatility Software License 1.0
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
import volatility3.framework.symbols.windows.extensions.pool
|
||||
|
||||
from volatility3.framework.symbols import intermed
|
||||
from volatility3.framework.symbols.windows import extensions
|
||||
from volatility3.framework.symbols.windows.extensions import registry, pool
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# This file is Copyright 2022 Volatility Foundation and licensed under the Volatility Software License 1.0
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
|
||||
from volatility3.framework import objects
|
||||
|
||||
class PARTITION_TABLE(objects.StructType):
|
||||
|
||||
def get_disk_signature(self) -> str:
|
||||
"""Get Disk Signature (GUID)."""
|
||||
return "{0:02x}-{1:02x}-{2:02x}-{3:02x}".format(
|
||||
self.DiskSignature[0],
|
||||
self.DiskSignature[1],
|
||||
self.DiskSignature[2],
|
||||
self.DiskSignature[3]
|
||||
)
|
||||
|
||||
class PARTITION_ENTRY(objects.StructType):
|
||||
|
||||
def get_bootable_flag(self) -> int:
|
||||
"""Get Bootable Flag."""
|
||||
return self.BootableFlag
|
||||
|
||||
def is_bootable(self) -> bool:
|
||||
"""Check Bootable Partition."""
|
||||
return False if not (self.get_bootable_flag() == 0x80) else True
|
||||
|
||||
def get_partition_type(self) -> str:
|
||||
"""Get Partition Type."""
|
||||
return self.PartitionType.lookup() if self.PartitionType.is_valid_choice else "Not Defined PartitionType"
|
||||
|
||||
def get_starting_chs(self) -> int:
|
||||
"""Get Starting CHS (Cylinder Header Sector) Address."""
|
||||
return self.StartingCHS[0]
|
||||
|
||||
def get_ending_chs(self) -> int:
|
||||
"""Get Ending CHS (Cylinder Header Sector) Address."""
|
||||
return self.EndingCHS[0]
|
||||
|
||||
def get_starting_sector(self) -> int:
|
||||
"""Get Starting Sector."""
|
||||
return self.StartingCHS[1] % 64
|
||||
|
||||
def get_ending_sector(self) -> int:
|
||||
"""Get Ending Sector."""
|
||||
return self.EndingCHS[1] % 64
|
||||
|
||||
def get_starting_cylinder(self) -> int:
|
||||
"""Get Starting Cylinder."""
|
||||
return (self.StartingCHS[1] - self.get_starting_sector()) * 4 + self.StartingCHS[2]
|
||||
|
||||
def get_ending_cylinder(self) -> int:
|
||||
"""Get Ending Cylinder."""
|
||||
return (self.EndingCHS[1] - self.get_ending_sector()) * 4 + self.EndingCHS[2]
|
||||
|
||||
def get_starting_lba(self) -> int:
|
||||
"""Get Starting LBA (Logical Block Addressing)."""
|
||||
return self.StartingLBA
|
||||
|
||||
def get_size_in_sectors(self) -> int:
|
||||
"""Get Size in Sectors."""
|
||||
return self.SizeInSectors
|
||||
@@ -0,0 +1,240 @@
|
||||
{
|
||||
"metadata": {
|
||||
"producer": {
|
||||
"version": "0.0.1",
|
||||
"name": "Donghyun Kim (@digitalisx99)",
|
||||
"comment": "Using structures defined in File System Forensic Analysis pg 88+",
|
||||
"datetime": "2022-03-05T10:53:00"
|
||||
},
|
||||
"format": "6.1.0"
|
||||
},
|
||||
"base_types": {
|
||||
"unsigned long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned long long": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": true,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": true,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned char": {
|
||||
"kind": "int",
|
||||
"size": 1,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"wchar": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": true,
|
||||
"endian": "little"
|
||||
}
|
||||
},
|
||||
"symbols": {},
|
||||
"enums": {
|
||||
"PartitionTypes": {
|
||||
"base": "unsigned char",
|
||||
"constants": {
|
||||
"Empty": 0,
|
||||
"FAT12,CHS": 1,
|
||||
"FAT16 16-32MB,CHS": 4,
|
||||
"Microsoft Extended": 5,
|
||||
"FAT16 32MB,CHS": 6,
|
||||
"NTFS": 7,
|
||||
"FAT32,CHS": 11,
|
||||
"FAT32,LBA": 12,
|
||||
"FAT16, 32MB-2GB,LBA": 14,
|
||||
"Microsoft Extended, LBA": 15,
|
||||
"Hidden FAT12,CHS": 17,
|
||||
"Hidden FAT16,16-32MB,CHS": 20,
|
||||
"Hidden FAT16,32MB-2GB,CHS": 22,
|
||||
"AST SmartSleep Partition": 24,
|
||||
"Hidden FAT32,CHS": 27,
|
||||
"Hidden FAT32,LBA": 28,
|
||||
"Hidden FAT16,32MB-2GB,LBA": 30,
|
||||
"PQservice": 39,
|
||||
"Plan 9 partition": 57,
|
||||
"PartitionMagic recovery partition": 60,
|
||||
"Microsoft MBR,Dynamic Disk": 66,
|
||||
"GoBack partition": 68,
|
||||
"Novell": 81,
|
||||
"CP/M": 82,
|
||||
"Unix System V": 99,
|
||||
"PC-ARMOUR protected partition": 100,
|
||||
"Solaris x86 or Linux Swap": 130,
|
||||
"Linux": 131,
|
||||
"Hibernation": 132,
|
||||
"Linux Extended": 133,
|
||||
"NTFS Volume Set": 134,
|
||||
"NTFS Volume Set": 135,
|
||||
"BSD/OS": 159,
|
||||
"Hibernation": 160,
|
||||
"Hibernation": 161,
|
||||
"FreeBSD": 165,
|
||||
"OpenBSD": 166,
|
||||
"Mac OSX": 168,
|
||||
"NetBSD": 169,
|
||||
"Mac OSX Boot": 171,
|
||||
"MacOS X HFS": 175,
|
||||
"BSDI": 183,
|
||||
"BSDI Swap": 184,
|
||||
"Boot Wizard hidden": 187,
|
||||
"Solaris 8 boot partition": 190,
|
||||
"CP/M-86": 216,
|
||||
"Dell PowerEdge Server utilities (FAT fs)": 222,
|
||||
"DG/UX virtual disk manager partition": 223,
|
||||
"BeOS BFS": 235,
|
||||
"EFI GPT Disk": 238,
|
||||
"EFI System Partition": 239,
|
||||
"VMWare File System": 251,
|
||||
"VMWare Swap": 252
|
||||
},
|
||||
"size": 1
|
||||
}
|
||||
},
|
||||
"user_types": {
|
||||
"PARTITION_ENTRY":{
|
||||
"fields": {
|
||||
"BootableFlag": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
},
|
||||
"StartingCHS": {
|
||||
"offset": 1,
|
||||
"type": {
|
||||
"count": 3,
|
||||
"kind": "array",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PartitionType": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "enum",
|
||||
"name": "PartitionTypes"
|
||||
}
|
||||
},
|
||||
"EndingCHS": {
|
||||
"offset": 5,
|
||||
"type": {
|
||||
"count": 3,
|
||||
"kind": "array",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
}
|
||||
},
|
||||
"StartingLBA": {
|
||||
"offset": 8,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
}
|
||||
},
|
||||
"SizeInSectors": {
|
||||
"offset": 12,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 16
|
||||
},
|
||||
"PARTITION_TABLE":{
|
||||
"fields":{
|
||||
"DiskSignature": {
|
||||
"offset": 440,
|
||||
"type": {
|
||||
"count": 4,
|
||||
"kind": "array",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Unused": {
|
||||
"offset": 444,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned short"
|
||||
}
|
||||
},
|
||||
"FirstEntry":{
|
||||
"offset": 446,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "PARTITION_ENTRY"
|
||||
}
|
||||
},
|
||||
"SecondEntry":{
|
||||
"offset": 462,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "PARTITION_ENTRY"
|
||||
}
|
||||
},
|
||||
"ThirdEntry":{
|
||||
"offset": 478,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "PARTITION_ENTRY"
|
||||
}
|
||||
},
|
||||
"FourthEntry":{
|
||||
"offset": 494,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "PARTITION_ENTRY"
|
||||
}
|
||||
},
|
||||
"Signature":{
|
||||
"offset": 510,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned short"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 512
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,7 +134,7 @@
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"UpdateSequenceOffset": {
|
||||
"offset": 4,
|
||||
@@ -192,7 +192,7 @@
|
||||
"name": "unsigned int"
|
||||
}
|
||||
},
|
||||
"AlocatedSize": {
|
||||
"AllocatedSize": {
|
||||
"offset": 28,
|
||||
"type":{
|
||||
"kind": "base",
|
||||
@@ -270,7 +270,8 @@
|
||||
"offset": 8,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char" }
|
||||
"name": "unsigned char"
|
||||
}
|
||||
},
|
||||
"NameLength": {
|
||||
"offset": 9,
|
||||
@@ -322,7 +323,8 @@
|
||||
"offset": 8,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned short" }
|
||||
"name": "unsigned short"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
|
||||
Reference in New Issue
Block a user