mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-08 10:47:38 +02:00
Merge branch 'develop' into 816-port-cmdscan-and-console-plugins-from-vol2-to-vol3-please
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# PYTHON_ARGCOMPLETE_OK
|
||||
|
||||
# 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
|
||||
|
||||
@@ -22,6 +22,13 @@ import traceback
|
||||
from typing import Any, Dict, List, Tuple, Type, Union
|
||||
from urllib import parse, request
|
||||
|
||||
try:
|
||||
import argcomplete
|
||||
|
||||
HAS_ARGCOMPLETE = True
|
||||
except ImportError:
|
||||
HAS_ARGCOMPLETE = False
|
||||
|
||||
from volatility3.cli import text_filter
|
||||
import volatility3.plugins
|
||||
import volatility3.symbols
|
||||
@@ -351,6 +358,10 @@ class CommandLine:
|
||||
# Hand the plugin requirements over to the CLI (us) and let it construct the config tree
|
||||
|
||||
# Run the argparser
|
||||
if HAS_ARGCOMPLETE:
|
||||
# The autocompletion line must be after the partial_arg handling, so that it doesn't trip it
|
||||
# before all the plugins have been added
|
||||
argcomplete.autocomplete(parser)
|
||||
args = parser.parse_args()
|
||||
if args.plugin is None:
|
||||
parser.error("Please select a plugin to run")
|
||||
|
||||
@@ -21,8 +21,6 @@ class HelpfulSubparserAction(argparse._SubParsersAction):
|
||||
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
# We don't want the action self-check to kick in, so we remove the choices list, the check happens in __call__
|
||||
self.choices = None
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
@@ -100,3 +98,20 @@ class HelpfulArgParser(argparse.ArgumentParser):
|
||||
|
||||
# return the number of arguments matched
|
||||
return len(match.group(1))
|
||||
|
||||
def _check_value(self, action: argparse.Action, value: Any) -> None:
|
||||
"""This is called to ensure a value is correct/valid
|
||||
|
||||
In normal operation, it would check that a value provided is valid and return None
|
||||
If it was not valid, it would throw an ArgumentError
|
||||
|
||||
When people provide a partial plugin name, we want to look for a matching plugin name
|
||||
which happens in the HelpfulSubparserAction's __call_method
|
||||
|
||||
To get there without tripping the check_value failure, we have to prevent the exception
|
||||
being thrown when the value is a HelpfulSubparserAction. This therefore affects no other
|
||||
checks for normal parameters.
|
||||
"""
|
||||
if not isinstance(action, HelpfulSubparserAction):
|
||||
super()._check_value(action, value)
|
||||
return None
|
||||
|
||||
@@ -21,6 +21,14 @@ from volatility3.framework import (
|
||||
plugins,
|
||||
)
|
||||
|
||||
try:
|
||||
import argcomplete
|
||||
|
||||
HAS_ARGCOMPLETE = True
|
||||
except ImportError:
|
||||
HAS_ARGCOMPLETE = False
|
||||
|
||||
|
||||
# Make sure we log everything
|
||||
|
||||
rootlog = logging.getLogger()
|
||||
@@ -276,6 +284,10 @@ class VolShell(cli.CommandLine):
|
||||
# Hand the plugin requirements over to the CLI (us) and let it construct the config tree
|
||||
|
||||
# Run the argparser
|
||||
if HAS_ARGCOMPLETE:
|
||||
# The autocompletion line must be after the partial_arg handling, so that it doesn't trip it
|
||||
# before all the plugins have been added
|
||||
argcomplete.autocomplete(parser)
|
||||
args = parser.parse_args()
|
||||
|
||||
vollog.log(
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
# We use the SemVer 2.0.0 versioning scheme
|
||||
VERSION_MAJOR = 2 # Number of releases of the library with a breaking change
|
||||
VERSION_MINOR = 7 # Number of changes that only add to the interface
|
||||
VERSION_PATCH = 2 # Number of changes that do not change the interface
|
||||
VERSION_MINOR = 8 # Number of changes that only add to the interface
|
||||
VERSION_PATCH = 0 # Number of changes that do not change the interface
|
||||
VERSION_SUFFIX = ""
|
||||
|
||||
# TODO: At version 2.0.0, remove the symbol_shift feature
|
||||
|
||||
PACKAGE_VERSION = (
|
||||
".".join([str(x) for x in [VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH]])
|
||||
+ VERSION_SUFFIX
|
||||
|
||||
@@ -7,6 +7,27 @@ from typing import Optional, Union
|
||||
from volatility3.framework import interfaces, objects, constants
|
||||
|
||||
|
||||
def rol(value: int, count: int, max_bits: int = 64) -> int:
|
||||
"""A rotate-left instruction in Python"""
|
||||
max_bits_mask = (1 << max_bits) - 1
|
||||
return (value << count % max_bits) & max_bits_mask | (
|
||||
(value & max_bits_mask) >> (max_bits - (count % max_bits))
|
||||
)
|
||||
|
||||
|
||||
def bswap_32(value: int) -> int:
|
||||
value = ((value << 8) & 0xFF00FF00) | ((value >> 8) & 0x00FF00FF)
|
||||
|
||||
return ((value << 16) | (value >> 16)) & 0xFFFFFFFF
|
||||
|
||||
|
||||
def bswap_64(value: int) -> int:
|
||||
low = bswap_32((value >> 32))
|
||||
high = bswap_32((value & 0xFFFFFFFF))
|
||||
|
||||
return ((high << 32) | low) & 0xFFFFFFFFFFFFFFFF
|
||||
|
||||
|
||||
def array_to_string(
|
||||
array: "objects.Array", count: Optional[int] = None, errors: str = "replace"
|
||||
) -> interfaces.objects.ObjectInterface:
|
||||
|
||||
@@ -0,0 +1,738 @@
|
||||
# This file is Copyright 2024 Volatility Foundation and licensed under the Volatility Software License 1.0
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
from dataclasses import dataclass, field
|
||||
from abc import ABC, abstractmethod
|
||||
import logging
|
||||
|
||||
from typing import Iterator, List, Tuple
|
||||
from volatility3 import framework
|
||||
from volatility3.framework import (
|
||||
constants,
|
||||
interfaces,
|
||||
renderers,
|
||||
exceptions,
|
||||
)
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.symbols import linux
|
||||
from volatility3.plugins.linux import lsmod
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Proto:
|
||||
name: str
|
||||
hooks: Tuple[str] = field(default_factory=tuple)
|
||||
|
||||
|
||||
PROTO_NOT_IMPLEMENTED = Proto(name="UNSPEC")
|
||||
|
||||
NF_INET_HOOKS = ("PRE_ROUTING", "LOCAL_IN", "FORWARD", "LOCAL_OUT", "POST_ROUTING")
|
||||
NF_DEC_HOOKS = (
|
||||
"PRE_ROUTING",
|
||||
"LOCAL_IN",
|
||||
"FORWARD",
|
||||
"LOCAL_OUT",
|
||||
"POST_ROUTING",
|
||||
"HELLO",
|
||||
"ROUTE",
|
||||
)
|
||||
NF_ARP_HOOKS = ("IN", "OUT", "FORWARD")
|
||||
NF_NETDEV_HOOKS = ("INGRESS", "EGRESS")
|
||||
LARGEST_HOOK_NUMBER = max(
|
||||
len(NF_INET_HOOKS), len(NF_DEC_HOOKS), len(NF_ARP_HOOKS), len(NF_NETDEV_HOOKS)
|
||||
)
|
||||
|
||||
|
||||
class AbstractNetfilter(ABC):
|
||||
"""Netfilter Abstract Base Classes handling details across various
|
||||
Netfilter implementations, including constants, helpers, and common
|
||||
routines.
|
||||
"""
|
||||
|
||||
PROTO_HOOKS = (
|
||||
PROTO_NOT_IMPLEMENTED, # NFPROTO_UNSPEC
|
||||
Proto(name="INET", hooks=NF_INET_HOOKS), # From kernels 3.14
|
||||
Proto(name="IPV4", hooks=NF_INET_HOOKS),
|
||||
Proto(name="ARP", hooks=NF_ARP_HOOKS),
|
||||
PROTO_NOT_IMPLEMENTED,
|
||||
Proto(name="NETDEV", hooks=NF_NETDEV_HOOKS),
|
||||
PROTO_NOT_IMPLEMENTED,
|
||||
Proto(name="BRIDGE", hooks=NF_INET_HOOKS),
|
||||
PROTO_NOT_IMPLEMENTED,
|
||||
PROTO_NOT_IMPLEMENTED,
|
||||
Proto(name="IPV6", hooks=NF_INET_HOOKS),
|
||||
PROTO_NOT_IMPLEMENTED,
|
||||
Proto(name="DECNET", hooks=NF_DEC_HOOKS), # Removed in kernel 6.1
|
||||
)
|
||||
NF_MAX_HOOKS = LARGEST_HOOK_NUMBER + 1
|
||||
|
||||
def __init__(
|
||||
self, context: interfaces.context.ContextInterface, kernel_module_name: str
|
||||
):
|
||||
self._context = context
|
||||
self.vmlinux = context.modules[kernel_module_name]
|
||||
self.layer_name = self.vmlinux.layer_name
|
||||
|
||||
# Set data sizes
|
||||
self.ptr_size = self.vmlinux.get_type("pointer").size
|
||||
self.list_head_size = self.vmlinux.get_type("list_head").size
|
||||
|
||||
lsmod_required_version = Netfilter._required_lsmod_version
|
||||
lsmod_current_version = lsmod.Lsmod._version
|
||||
if not requirements.VersionRequirement.matches_required(
|
||||
lsmod_required_version, lsmod_current_version
|
||||
):
|
||||
raise exceptions.PluginRequirementException(
|
||||
f"linux.lsmod.Lsmod version not suitable: required {lsmod_required_version} found {lsmod_current_version}"
|
||||
)
|
||||
|
||||
linuxutils_required_version = Netfilter._required_linuxutils_version
|
||||
linuxutils_current_version = linux.LinuxUtilities._version
|
||||
if not requirements.VersionRequirement.matches_required(
|
||||
linuxutils_required_version, linuxutils_current_version
|
||||
):
|
||||
raise exceptions.PluginRequirementException(
|
||||
f"linux.LinuxUtilities version not suitable: required {linuxutils_required_version} found {linuxutils_current_version}"
|
||||
)
|
||||
|
||||
modules = lsmod.Lsmod.list_modules(context, kernel_module_name)
|
||||
self.handlers = linux.LinuxUtilities.generate_kernel_handler_info(
|
||||
context, kernel_module_name, modules
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def run_all(
|
||||
cls, context: interfaces.context.ContextInterface, kernel_module_name: str
|
||||
) -> Iterator[Tuple[int, str, str, int, int, str, bool]]:
|
||||
"""It calls each subclass symtab_checks() to test the required
|
||||
conditions to that specific kernel implementation.
|
||||
|
||||
Args:
|
||||
context: The volatility3 context on which to operate
|
||||
kernel_module_name: The name of the table containing the kernel symbols
|
||||
|
||||
Yields:
|
||||
The kmsg records. Same as _run()
|
||||
"""
|
||||
vmlinux = context.modules[kernel_module_name]
|
||||
|
||||
implementation_inst = None # type: ignore
|
||||
for subclass in framework.class_subclasses(cls):
|
||||
if not subclass.symtab_checks(vmlinux=vmlinux):
|
||||
vollog.log(
|
||||
constants.LOGLEVEL_VVVV,
|
||||
"Netfilter implementation '%s' doesn't match this memory dump",
|
||||
subclass.__name__,
|
||||
)
|
||||
continue
|
||||
|
||||
vollog.log(
|
||||
constants.LOGLEVEL_VVVV,
|
||||
"Netfilter implementation '%s' matches!",
|
||||
subclass.__name__,
|
||||
)
|
||||
implementation_inst = subclass(
|
||||
context=context, kernel_module_name=kernel_module_name
|
||||
)
|
||||
# More than one class could be executed for an specific kernel version
|
||||
# For instance: Netfilter Ingress hooks
|
||||
yield from implementation_inst._run()
|
||||
|
||||
if implementation_inst is None:
|
||||
vollog.error("Unsupported Netfilter kernel implementation")
|
||||
|
||||
def _run(self) -> Iterator[Tuple[int, str, str, int, int, str, bool]]:
|
||||
"""Iterates over namespaces and protocols, executing various callbacks that
|
||||
allow customization of the code to the specific data structure used in a
|
||||
particular kernel implementation
|
||||
|
||||
get_hooks_container(net, proto_name, hook_name)
|
||||
It returns the data structure used in a specific kernel implementation
|
||||
to store the hooks for a respective namespace and protocol, basically:
|
||||
For Ingress hooks:
|
||||
network_namespace[] -> net_device[] -> nf_hooks_ingress[]
|
||||
For egress hooks:
|
||||
network_namespace[] -> net_device[] -> nf_hooks_egress[]
|
||||
For all the other Netfilter hooks:
|
||||
<= 4.2.8
|
||||
nf_hooks[]
|
||||
>= 4.3
|
||||
network_namespace[] -> nf.hooks[]
|
||||
|
||||
get_hook_ops(hook_container, proto_idx, hook_idx)
|
||||
Give the 'hook_container' got in get_hooks_container(), it
|
||||
returns an iterable of 'nf_hook_ops' elements for a respective protocol
|
||||
and hook type.
|
||||
|
||||
Returns:
|
||||
netns [int]: Network namespace id
|
||||
proto_name [str]: Protocol name
|
||||
hook_name [str]: Hook name
|
||||
priority [int]: Priority
|
||||
hook_ops_hook [int]: Hook address
|
||||
module_name [str]: Linux kernel module name
|
||||
hooked [bool]: hooked?
|
||||
"""
|
||||
for netns, net in self.get_net_namespaces():
|
||||
for proto_idx, proto_name, hook_idx, hook_name in self._proto_hook_loop():
|
||||
hooks_container = self.get_hooks_container(net, proto_name, hook_name)
|
||||
|
||||
for hook_container in hooks_container:
|
||||
for hook_ops in self.get_hook_ops(
|
||||
hook_container, proto_idx, hook_idx
|
||||
):
|
||||
if not hook_ops:
|
||||
continue
|
||||
|
||||
priority = int(hook_ops.priority)
|
||||
hook_ops_hook = hook_ops.hook
|
||||
module_name = self.get_module_name_for_address(hook_ops_hook)
|
||||
hooked = module_name is not None
|
||||
|
||||
yield netns, proto_name, hook_name, priority, hook_ops_hook, module_name, hooked
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def symtab_checks(cls, vmlinux: interfaces.context.ModuleInterface) -> bool:
|
||||
"""This method on each sublasss will be called to evaluate if the kernel
|
||||
being analyzed fulfill the type & symbols requirements for the implementation.
|
||||
The first class returning True will be instantiated and called via the
|
||||
run() method.
|
||||
|
||||
Returns:
|
||||
bool: True if the kernel being analyzed fulfill the class requirements.
|
||||
"""
|
||||
|
||||
def _proto_hook_loop(self) -> Iterator[Tuple[int, str, int, str]]:
|
||||
"""Flattens the protocol families and hooks"""
|
||||
for proto_idx, proto in enumerate(AbstractNetfilter.PROTO_HOOKS):
|
||||
if proto == PROTO_NOT_IMPLEMENTED:
|
||||
continue
|
||||
if proto.name not in self.subscribed_protocols():
|
||||
# This protocol is not managed in this object
|
||||
continue
|
||||
for hook_idx, hook_name in enumerate(proto.hooks):
|
||||
yield proto_idx, proto.name, hook_idx, hook_name
|
||||
|
||||
def build_nf_hook_ops_array(self, nf_hook_entries):
|
||||
"""Function helper to build the nf_hook_ops array when it is not part of the
|
||||
struct 'nf_hook_entries' definition.
|
||||
|
||||
nf_hook_ops was stored adjacent in memory to the nf_hook_entry array, in the
|
||||
new struct 'nf_hook_entries'. However, this 'nf_hooks_ops' array 'orig_ops' is
|
||||
not part of the 'nf_hook_entries' struct. So, we need to calculate the offset.
|
||||
|
||||
struct nf_hook_entries {
|
||||
u16 num_hook_entries; /* plus padding */
|
||||
struct nf_hook_entry hooks[];
|
||||
//const struct nf_hook_ops *orig_ops[];
|
||||
}
|
||||
"""
|
||||
nf_hook_entry_size = self.vmlinux.get_type("nf_hook_entry").size
|
||||
orig_ops_addr = (
|
||||
nf_hook_entries.hooks.vol.offset
|
||||
+ nf_hook_entry_size * nf_hook_entries.num_hook_entries
|
||||
)
|
||||
orig_ops = self._context.object(
|
||||
object_type=self.get_symbol_fullname("array"),
|
||||
offset=orig_ops_addr,
|
||||
subtype=self.vmlinux.get_type("pointer"),
|
||||
layer_name=self.layer_name,
|
||||
count=nf_hook_entries.num_hook_entries,
|
||||
)
|
||||
|
||||
return orig_ops
|
||||
|
||||
def subscribed_protocols(self) -> Tuple[str]:
|
||||
"""Allows to select which PROTO_HOOKS protocols will be processed by the
|
||||
Netfiler subclass.
|
||||
"""
|
||||
|
||||
# Most implementation handlers respond to these protocols, except for
|
||||
# the ingress hook, which specifically handles the 'NETDEV' protocol.
|
||||
# However, there is no corresponding Netfilter hook implementation for
|
||||
# the INET protocol in the kernel. AFAIU, this is used as
|
||||
# 'NFPROTO_INET = NFPROTO_IPV4 || NFPROTO_IPV6'
|
||||
# in other parts of the kernel source code.
|
||||
return ("IPV4", "ARP", "BRIDGE", "IPV6", "DECNET")
|
||||
|
||||
def get_module_name_for_address(self, addr) -> str:
|
||||
"""Helper to obtain the module and symbol name in the format needed for the
|
||||
output of this plugin.
|
||||
"""
|
||||
module_name, symbol_name = linux.LinuxUtilities.lookup_module_address(
|
||||
self.vmlinux, self.handlers, addr
|
||||
)
|
||||
|
||||
if module_name == "UNKNOWN":
|
||||
module_name = None
|
||||
|
||||
if symbol_name != "N/A":
|
||||
module_name = f"[{symbol_name}]"
|
||||
|
||||
return module_name
|
||||
|
||||
def get_net_namespaces(self):
|
||||
"""Common function to retrieve the different namespaces.
|
||||
From 4.3 on, all the implementations use network namespaces.
|
||||
"""
|
||||
nethead = self.vmlinux.object_from_symbol("net_namespace_list")
|
||||
symbol_net_name = self.get_symbol_fullname("net")
|
||||
for net in nethead.to_list(symbol_net_name, "list"):
|
||||
net_ns_id = net.ns.inum
|
||||
yield net_ns_id, net
|
||||
|
||||
def get_hooks_container(self, net, proto_name, hook_name):
|
||||
"""Returns the data structure used in a specific kernel implementation to store
|
||||
the hooks for a respective namespace and protocol.
|
||||
|
||||
Except for kernels < 4.3, all the implementations use network namespaces.
|
||||
Also the data structure which contains the hooks, even though it changes its
|
||||
implementation and/or data type, it is always in this location.
|
||||
"""
|
||||
yield net.nf.hooks
|
||||
|
||||
def get_hook_ops(self, hook_container, proto_idx, hook_idx):
|
||||
"""Given the hook_container obtained from get_hooks_container(), it
|
||||
returns an iterable of 'nf_hook_ops' elements for a corresponding protocol
|
||||
and hook type.
|
||||
|
||||
This is the most variable/unstable part of all Netfilter hook designs, it
|
||||
changes almost in every single implementation.
|
||||
"""
|
||||
raise NotImplementedError("You must implement this method")
|
||||
|
||||
def get_symbol_fullname(self, symbol_basename: str) -> str:
|
||||
"""Given a short symbol or type name, it returns its full name"""
|
||||
return self.vmlinux.symbol_table_name + constants.BANG + symbol_basename
|
||||
|
||||
@staticmethod
|
||||
def get_member_type(
|
||||
vol_type: interfaces.objects.Template, member_name: str
|
||||
) -> List[str]:
|
||||
"""Returns a list of types/subtypes belonging to the given type member.
|
||||
|
||||
Args:
|
||||
vol_type (interfaces.objects.Template): A vol3 type object
|
||||
member_name (str): The member name
|
||||
|
||||
Returns:
|
||||
list: A list of types/subtypes
|
||||
"""
|
||||
_size, vol_obj = vol_type.vol.members[member_name]
|
||||
type_name = vol_obj.type_name
|
||||
type_basename = type_name.split(constants.BANG)[1]
|
||||
member_type = [type_basename]
|
||||
cur_type = vol_obj
|
||||
while hasattr(cur_type, "subtype"):
|
||||
subtype_name = cur_type.subtype.type_name
|
||||
subtype_basename = subtype_name.split(constants.BANG)[1]
|
||||
member_type.append(subtype_basename)
|
||||
cur_type = cur_type.subtype
|
||||
|
||||
return member_type
|
||||
|
||||
|
||||
class NetfilterImp_to_4_3(AbstractNetfilter):
|
||||
"""At this point, Netfilter hooks were implemented as a linked list of struct
|
||||
'nf_hook_ops' type. One linked list per protocol per hook type.
|
||||
It was like that until 4.2.8.
|
||||
|
||||
struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def symtab_checks(cls, vmlinux) -> bool:
|
||||
return vmlinux.has_symbol("nf_hooks")
|
||||
|
||||
def get_net_namespaces(self):
|
||||
# In kernels <= 4.2.8 netfilter hooks are not implemented per namespaces
|
||||
netns, net = renderers.NotAvailableValue(), renderers.NotAvailableValue()
|
||||
yield netns, net
|
||||
|
||||
def get_hooks_container(self, net, proto_name, hook_name):
|
||||
nf_hooks = self.vmlinux.object_from_symbol("nf_hooks")
|
||||
if not nf_hooks:
|
||||
return
|
||||
|
||||
yield nf_hooks
|
||||
|
||||
def get_hook_ops(self, hook_container, proto_idx, hook_idx):
|
||||
list_head = hook_container[proto_idx][hook_idx]
|
||||
nf_hooks_ops_name = self.get_symbol_fullname("nf_hook_ops")
|
||||
return list_head.to_list(nf_hooks_ops_name, "list")
|
||||
|
||||
|
||||
class NetfilterImp_4_3_to_4_9(AbstractNetfilter):
|
||||
"""Netfilter hooks were added to network namepaces in 4.3.
|
||||
It is still implemented as a linked list of 'struct nf_hook_ops' type but inside a
|
||||
network namespace. One linked list per protocol per hook type.
|
||||
|
||||
struct net { ... struct netns_nf nf; ... }
|
||||
struct netns_nf { ...
|
||||
struct list_head hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; ... }
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def symtab_checks(cls, vmlinux) -> bool:
|
||||
return (
|
||||
vmlinux.has_symbol("net_namespace_list")
|
||||
and vmlinux.has_type("netns_nf")
|
||||
and vmlinux.get_type("netns_nf").has_member("hooks")
|
||||
and cls.get_member_type(vmlinux.get_type("netns_nf"), "hooks")
|
||||
== ["array", "array", "list_head"]
|
||||
)
|
||||
|
||||
def get_hook_ops(self, hook_container, proto_idx, hook_idx):
|
||||
list_head = hook_container[proto_idx][hook_idx]
|
||||
nf_hooks_ops_name = self.get_symbol_fullname("nf_hook_ops")
|
||||
return list_head.to_list(nf_hooks_ops_name, "list")
|
||||
|
||||
|
||||
class NetfilterImp_4_9_to_4_14(AbstractNetfilter):
|
||||
"""In this range of kernel versions, the doubly-linked lists of netfilter hooks were
|
||||
replaced by an array of arrays of 'nf_hook_entry' pointers in a singly-linked lists.
|
||||
struct net { ... struct netns_nf nf; ... }
|
||||
struct netns_nf { ..
|
||||
struct nf_hook_entry __rcu *hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; ... }
|
||||
|
||||
Also in v4.10 the struct nf_hook_entry changed, a hook function pointer was added to
|
||||
it. However, for simplicity of this design, we will still take the hook address from
|
||||
the 'nf_hook_ops'. As per v5.0-rc2, the hook address is duplicated in both sides.
|
||||
- v4.9:
|
||||
struct nf_hook_entry {
|
||||
struct nf_hook_entry *next;
|
||||
struct nf_hook_ops ops;
|
||||
const struct nf_hook_ops *orig_ops; };
|
||||
- v4.10:
|
||||
struct nf_hook_entry {
|
||||
struct nf_hook_entry *next;
|
||||
nf_hookfn *hook;
|
||||
void *priv;
|
||||
const struct nf_hook_ops *orig_ops; };
|
||||
(*) Even though the hook address is in the struct 'nf_hook_entry', we use the
|
||||
original 'nf_hook_ops' hook address value, the one which was filled by the user, to
|
||||
make it uniform to all the implementations.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def symtab_checks(cls, vmlinux) -> bool:
|
||||
hooks_type = ["array", "array", "pointer", "nf_hook_entry"]
|
||||
return (
|
||||
vmlinux.has_symbol("net_namespace_list")
|
||||
and vmlinux.has_type("netns_nf")
|
||||
and vmlinux.get_type("netns_nf").has_member("hooks")
|
||||
and cls.get_member_type(vmlinux.get_type("netns_nf"), "hooks") == hooks_type
|
||||
)
|
||||
|
||||
def _get_hook_ops(self, hook_container, proto_idx, hook_idx):
|
||||
list_head = hook_container[proto_idx][hook_idx]
|
||||
nf_hooks_ops_name = self.get_symbol_fullname("nf_hook_ops")
|
||||
return list_head.to_list(nf_hooks_ops_name, "list")
|
||||
|
||||
def get_hook_ops(self, hook_container, proto_idx, hook_idx):
|
||||
nf_hook_entry_list = hook_container[proto_idx][hook_idx]
|
||||
while nf_hook_entry_list:
|
||||
yield nf_hook_entry_list.orig_ops
|
||||
nf_hook_entry_list = nf_hook_entry_list.next
|
||||
|
||||
|
||||
class NetfilterImp_4_14_to_4_16(AbstractNetfilter):
|
||||
"""'nf_hook_ops' was removed from struct 'nf_hook_entry'. Instead, it was stored
|
||||
adjacent in memory to the 'nf_hook_entry' array, in the new struct 'nf_hook_entries'
|
||||
However, 'orig_ops' is not part of the 'nf_hook_entries' struct definition. So, we
|
||||
have to craft it by hand.
|
||||
|
||||
struct net { ... struct netns_nf nf; ... }
|
||||
struct netns_nf {
|
||||
struct nf_hook_entries *hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; ... }
|
||||
struct nf_hook_entries {
|
||||
u16 num_hook_entries; /* plus padding */
|
||||
struct nf_hook_entry hooks[];
|
||||
//const struct nf_hook_ops *orig_ops[]; }
|
||||
struct nf_hook_entry {
|
||||
nf_hookfn *hook;
|
||||
void *priv; }
|
||||
|
||||
(*) Even though the hook address is in the struct 'nf_hook_entry', we use the
|
||||
original 'nf_hook_ops' hook address value, the one which was filled by the user, to
|
||||
make it uniform to all the implementations.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def symtab_checks(cls, vmlinux) -> bool:
|
||||
hooks_type = ["array", "array", "pointer", "nf_hook_entries"]
|
||||
return (
|
||||
vmlinux.has_symbol("net_namespace_list")
|
||||
and vmlinux.has_type("netns_nf")
|
||||
and vmlinux.get_type("netns_nf").has_member("hooks")
|
||||
and cls.get_member_type(vmlinux.get_type("netns_nf"), "hooks") == hooks_type
|
||||
)
|
||||
|
||||
def get_nf_hook_entries(self, nf_hooks_addr, proto_idx, hook_idx):
|
||||
"""This allows to support different hook array implementations from this version
|
||||
on. For instance, in kernels >= 4.16 this multi-dimensional array is split in
|
||||
one-dimensional array of pointers to 'nf_hooks_entries' per each protocol."""
|
||||
return nf_hooks_addr[proto_idx][hook_idx]
|
||||
|
||||
def get_hook_ops(self, hook_container, proto_idx, hook_idx):
|
||||
nf_hook_entries = self.get_nf_hook_entries(hook_container, proto_idx, hook_idx)
|
||||
if not nf_hook_entries:
|
||||
return
|
||||
|
||||
nf_hook_ops_name = self.get_symbol_fullname("nf_hook_ops")
|
||||
nf_hook_ops_ptr_arr = self.build_nf_hook_ops_array(nf_hook_entries)
|
||||
for nf_hook_ops_ptr in nf_hook_ops_ptr_arr:
|
||||
nf_hook_ops = nf_hook_ops_ptr.dereference().cast(nf_hook_ops_name)
|
||||
yield nf_hook_ops
|
||||
|
||||
|
||||
class NetfilterImp_4_16_to_latest(NetfilterImp_4_14_to_4_16):
|
||||
"""The multidimensional array of nf_hook_entries was split in a one-dimensional
|
||||
array per each protocol.
|
||||
|
||||
struct net {
|
||||
struct netns_nf nf; ... }
|
||||
struct netns_nf {
|
||||
struct nf_hook_entries * hooks_ipv4[NF_INET_NUMHOOKS];
|
||||
struct nf_hook_entries * hooks_ipv6[NF_INET_NUMHOOKS];
|
||||
struct nf_hook_entries * hooks_arp[NF_ARP_NUMHOOKS];
|
||||
struct nf_hook_entries * hooks_bridge[NF_INET_NUMHOOKS];
|
||||
struct nf_hook_entries * hooks_decnet[NF_DN_NUMHOOKS]; ... }
|
||||
struct nf_hook_entries {
|
||||
u16 num_hook_entries; /* plus padding */
|
||||
struct nf_hook_entry hooks[];
|
||||
//const struct nf_hook_ops *orig_ops[]; }
|
||||
struct nf_hook_entry {
|
||||
nf_hookfn *hook;
|
||||
void *priv; }
|
||||
|
||||
(*) Even though the hook address is in the struct nf_hook_entry, we use the original
|
||||
nf_hook_ops hook address value, the one which was filled by the user, to make it
|
||||
uniform to all the implementations.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def symtab_checks(cls, vmlinux) -> bool:
|
||||
return (
|
||||
vmlinux.has_symbol("net_namespace_list")
|
||||
and vmlinux.has_type("netns_nf")
|
||||
and vmlinux.get_type("netns_nf").has_member("hooks_ipv4")
|
||||
)
|
||||
|
||||
def get_hooks_container(self, net, proto_name, hook_name):
|
||||
try:
|
||||
if proto_name == "IPV4":
|
||||
net_nf_hooks = net.nf.hooks_ipv4
|
||||
elif proto_name == "ARP":
|
||||
net_nf_hooks = net.nf.hooks_arp
|
||||
elif proto_name == "BRIDGE":
|
||||
net_nf_hooks = net.nf.hooks_bridge
|
||||
elif proto_name == "IPV6":
|
||||
net_nf_hooks = net.nf.hooks_ipv6
|
||||
elif proto_name == "DECNET":
|
||||
net_nf_hooks = net.nf.hooks_decnet
|
||||
else:
|
||||
return
|
||||
|
||||
yield net_nf_hooks
|
||||
|
||||
except AttributeError:
|
||||
# Protocol family disabled at kernel compilation
|
||||
# CONFIG_NETFILTER_FAMILY_ARP=n ||
|
||||
# CONFIG_NETFILTER_FAMILY_BRIDGE=n ||
|
||||
# CONFIG_DECNET=n
|
||||
pass
|
||||
|
||||
def _get_nf_hook_entries_ptr(self, nf_hooks_addr, proto_idx, hook_idx):
|
||||
nf_hook_entries_ptr = nf_hooks_addr[hook_idx]
|
||||
return nf_hook_entries_ptr
|
||||
|
||||
def get_nf_hook_entries(self, nf_hooks_addr, proto_idx, hook_idx):
|
||||
return nf_hooks_addr[hook_idx]
|
||||
|
||||
|
||||
class AbstractNetfilterNetDev(AbstractNetfilter):
|
||||
"""Base class to handle the Netfilter NetDev hooks.
|
||||
It won't be executed. It has some common functions to all Netfilter NetDev hook
|
||||
implementions.
|
||||
|
||||
Netfilter NetDev hooks are set per network device which belongs to a network
|
||||
namespace.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def symtab_checks(cls, vmlinux) -> bool:
|
||||
return False
|
||||
|
||||
def subscribed_protocols(self):
|
||||
return ("NETDEV",)
|
||||
|
||||
def get_hooks_container(self, net, proto_name, hook_name):
|
||||
net_device_type = self.vmlinux.get_type("net_device")
|
||||
net_device_name = self.get_symbol_fullname("net_device")
|
||||
for net_device in net.dev_base_head.to_list(net_device_name, "dev_list"):
|
||||
if hook_name == "INGRESS":
|
||||
if net_device_type.has_member("nf_hooks_ingress"):
|
||||
# CONFIG_NETFILTER_INGRESS=y
|
||||
yield net_device.nf_hooks_ingress
|
||||
|
||||
elif hook_name == "EGRESS":
|
||||
if net_device_type.has_member("nf_hooks_egress"):
|
||||
# CONFIG_NETFILTER_EGRESS=y
|
||||
yield net_device.nf_hooks_egress
|
||||
|
||||
|
||||
class NetfilterNetDevImp_4_2_to_4_9(AbstractNetfilterNetDev):
|
||||
"""This is the first version of Netfilter Ingress hooks which was implemented using
|
||||
a doubly-linked list of 'nf_hook_ops'.
|
||||
struct list_head nf_hooks_ingress;
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def symtab_checks(cls, vmlinux) -> bool:
|
||||
hooks_type = ["list_head"]
|
||||
return (
|
||||
vmlinux.has_symbol("net_namespace_list")
|
||||
and vmlinux.has_type("net_device")
|
||||
and vmlinux.get_type("net_device").has_member("nf_hooks_ingress")
|
||||
and cls.get_member_type(vmlinux.get_type("net_device"), "nf_hooks_ingress")
|
||||
== hooks_type
|
||||
)
|
||||
|
||||
def get_hook_ops(self, hook_container, proto_idx, hook_idx):
|
||||
nf_hooks_ingress = hook_container
|
||||
nf_hook_ops_name = self.get_symbol_fullname("nf_hook_ops")
|
||||
return nf_hooks_ingress.to_list(nf_hook_ops_name, "list")
|
||||
|
||||
|
||||
class NetfilterNetDevImp_4_9_to_4_14(AbstractNetfilterNetDev):
|
||||
"""In 4.9 it was changed to a simple singly-linked list.
|
||||
struct nf_hook_entry * nf_hooks_ingress;
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def symtab_checks(cls, vmlinux) -> bool:
|
||||
hooks_type = ["pointer", "nf_hook_entry"]
|
||||
return (
|
||||
vmlinux.has_symbol("net_namespace_list")
|
||||
and vmlinux.has_type("net_device")
|
||||
and vmlinux.get_type("net_device").has_member("nf_hooks_ingress")
|
||||
and cls.get_member_type(vmlinux.get_type("net_device"), "nf_hooks_ingress")
|
||||
== hooks_type
|
||||
)
|
||||
|
||||
def get_hook_ops(self, hook_container, proto_idx, hook_idx):
|
||||
nf_hooks_ingress_ptr = hook_container
|
||||
if not nf_hooks_ingress_ptr:
|
||||
return
|
||||
|
||||
while nf_hooks_ingress_ptr:
|
||||
nf_hook_entry = nf_hooks_ingress_ptr.dereference()
|
||||
orig_ops = nf_hook_entry.orig_ops.dereference()
|
||||
yield orig_ops
|
||||
nf_hooks_ingress_ptr = nf_hooks_ingress_ptr.next
|
||||
|
||||
|
||||
class NetfilterNetDevImp_4_14_to_latest(AbstractNetfilterNetDev):
|
||||
"""In 4.14 the hook list was converted to an array of pointers inside the struct
|
||||
'nf_hook_entries':
|
||||
struct nf_hook_entries * nf_hooks_ingress;
|
||||
struct nf_hook_entries {
|
||||
u16 num_hook_entries;
|
||||
struct nf_hook_entry hooks[];
|
||||
//const struct nf_hook_ops *orig_ops[]; }
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def symtab_checks(cls, vmlinux) -> bool:
|
||||
hooks_type = ["pointer", "nf_hook_entries"]
|
||||
return (
|
||||
vmlinux.has_symbol("net_namespace_list")
|
||||
and vmlinux.has_type("net_device")
|
||||
and vmlinux.get_type("net_device").has_member("nf_hooks_ingress")
|
||||
and cls.get_member_type(vmlinux.get_type("net_device"), "nf_hooks_ingress")
|
||||
== hooks_type
|
||||
)
|
||||
|
||||
def get_hook_ops(self, hook_container, proto_idx, hook_idx):
|
||||
nf_hook_entries = hook_container
|
||||
if not nf_hook_entries:
|
||||
return
|
||||
|
||||
nf_hook_ops_name = self.get_symbol_fullname("nf_hook_ops")
|
||||
nf_hook_ops_ptr_arr = self.build_nf_hook_ops_array(nf_hook_entries)
|
||||
for nf_hook_ops_ptr in nf_hook_ops_ptr_arr:
|
||||
nf_hook_ops = nf_hook_ops_ptr.dereference().cast(nf_hook_ops_name)
|
||||
yield nf_hook_ops
|
||||
|
||||
|
||||
class Netfilter(interfaces.plugins.PluginInterface):
|
||||
"""Lists Netfilter hooks."""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
|
||||
_version = (1, 0, 0)
|
||||
|
||||
_required_linuxutils_version = (2, 1, 0)
|
||||
_required_lsmod_version = (2, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.ModuleRequirement(
|
||||
name="kernel",
|
||||
description="Linux kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="lsmod", plugin=lsmod.Lsmod, version=cls._required_lsmod_version
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="linuxutils",
|
||||
component=linux.LinuxUtilities,
|
||||
version=cls._required_linuxutils_version,
|
||||
),
|
||||
]
|
||||
|
||||
def _format_fields(self, fields):
|
||||
(
|
||||
netns,
|
||||
proto_name,
|
||||
hook_name,
|
||||
priority,
|
||||
hook_func,
|
||||
module_name,
|
||||
hooked,
|
||||
) = fields
|
||||
return (
|
||||
netns,
|
||||
proto_name,
|
||||
hook_name,
|
||||
priority,
|
||||
format_hints.Hex(hook_func),
|
||||
module_name,
|
||||
str(hooked),
|
||||
)
|
||||
|
||||
def _generator(self):
|
||||
kernel_module_name = self.config["kernel"]
|
||||
for fields in AbstractNetfilter.run_all(
|
||||
context=self.context, kernel_module_name=kernel_module_name
|
||||
):
|
||||
yield (0, self._format_fields(fields))
|
||||
|
||||
def run(self):
|
||||
headers = [
|
||||
("Net NS", int),
|
||||
("Proto", str),
|
||||
("Hook", str),
|
||||
("Priority", int),
|
||||
("Handler", format_hints.Hex),
|
||||
("Module", str),
|
||||
("Is Hooked", str),
|
||||
]
|
||||
return renderers.TreeGrid(headers, self._generator())
|
||||
@@ -105,7 +105,9 @@ class Timeliner(interfaces.plugins.PluginInterface):
|
||||
data = item[1]
|
||||
|
||||
def sortable(timestamp):
|
||||
max_date = datetime.datetime(day=1, month=12, year=datetime.MAXYEAR)
|
||||
max_date = datetime.datetime(
|
||||
day=1, month=12, year=datetime.MAXYEAR, tzinfo=datetime.timezone.utc
|
||||
)
|
||||
if isinstance(timestamp, interfaces.renderers.BaseAbsentValue):
|
||||
return max_date
|
||||
return timestamp
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0
|
||||
# This file is Copyright 2024 Volatility Foundation and licensed under the Volatility Software License 1.0
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
import contextlib
|
||||
import datetime
|
||||
import logging
|
||||
import ntpath
|
||||
import re
|
||||
from typing import List, Optional, Type
|
||||
|
||||
@@ -14,7 +13,7 @@ from volatility3.framework.renderers import conversion, format_hints
|
||||
from volatility3.framework.symbols import intermed
|
||||
from volatility3.framework.symbols.windows.extensions import pe
|
||||
from volatility3.plugins import timeliner
|
||||
from volatility3.plugins.windows import info, pslist, psscan
|
||||
from volatility3.plugins.windows import info, pslist, psscan, pedump
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
@@ -23,7 +22,7 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
"""Lists the loaded modules in a particular windows memory image."""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
_version = (2, 0, 1)
|
||||
_version = (3, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
@@ -76,67 +75,11 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
default=False,
|
||||
optional=True,
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="pedump", component=pedump.PEDump, version=(1, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def dump_pe(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
pe_table_name: str,
|
||||
dll_entry: interfaces.objects.ObjectInterface,
|
||||
open_method: Type[interfaces.plugins.FileHandlerInterface],
|
||||
layer_name: str = None,
|
||||
prefix: str = "",
|
||||
) -> Optional[interfaces.plugins.FileHandlerInterface]:
|
||||
"""Extracts the complete data for a process as a FileInterface
|
||||
|
||||
Args:
|
||||
context: the context to operate upon
|
||||
pe_table_name: the name for the symbol table containing the PE format symbols
|
||||
dll_entry: the object representing the module
|
||||
layer_name: the layer that the DLL lives within
|
||||
open_method: class for constructing output files
|
||||
|
||||
Returns:
|
||||
An open FileHandlerInterface object containing the complete data for the DLL or None in the case of failure
|
||||
"""
|
||||
try:
|
||||
try:
|
||||
name = dll_entry.FullDllName.get_string()
|
||||
except exceptions.InvalidAddressException:
|
||||
name = "UnreadableDLLName"
|
||||
|
||||
if layer_name is None:
|
||||
layer_name = dll_entry.vol.layer_name
|
||||
|
||||
file_handle = open_method(
|
||||
"{}{}.{:#x}.{:#x}.dmp".format(
|
||||
prefix,
|
||||
ntpath.basename(name),
|
||||
dll_entry.vol.offset,
|
||||
dll_entry.DllBase,
|
||||
)
|
||||
)
|
||||
|
||||
dos_header = context.object(
|
||||
pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER",
|
||||
offset=dll_entry.DllBase,
|
||||
layer_name=layer_name,
|
||||
)
|
||||
|
||||
for offset, data in dos_header.reconstruct():
|
||||
file_handle.seek(offset)
|
||||
file_handle.write(data)
|
||||
except (
|
||||
IOError,
|
||||
exceptions.VolatilityException,
|
||||
OverflowError,
|
||||
ValueError,
|
||||
) as excp:
|
||||
vollog.debug(f"Unable to dump dll at offset {dll_entry.DllBase}: {excp}")
|
||||
return None
|
||||
return file_handle
|
||||
|
||||
def _generator(self, procs):
|
||||
pe_table_name = intermed.IntermediateSymbolTable.create(
|
||||
self.context, self.config_path, "windows", "pe", class_types=pe.class_types
|
||||
@@ -204,7 +147,7 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
|
||||
file_output = "Disabled"
|
||||
if self.config["dump"]:
|
||||
file_handle = self.dump_pe(
|
||||
file_output = pedump.PEDump.dump_ldr_entry(
|
||||
self.context,
|
||||
pe_table_name,
|
||||
entry,
|
||||
@@ -212,10 +155,10 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
proc_layer_name,
|
||||
prefix=f"pid.{proc_id}.",
|
||||
)
|
||||
file_output = "Error outputting file"
|
||||
if file_handle:
|
||||
file_handle.close()
|
||||
file_output = file_handle.preferred_filename
|
||||
|
||||
if not file_output:
|
||||
file_output = "Error outputting file"
|
||||
|
||||
try:
|
||||
dllbase = format_hints.Hex(entry.DllBase)
|
||||
except exceptions.InvalidAddressException:
|
||||
|
||||
@@ -14,6 +14,7 @@ class FileScan(interfaces.plugins.PluginInterface):
|
||||
"""Scans for file objects present in a particular windows memory image."""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
_version = (1, 0, 1)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
@@ -67,10 +68,10 @@ class FileScan(interfaces.plugins.PluginInterface):
|
||||
except exceptions.InvalidAddressException:
|
||||
continue
|
||||
|
||||
yield (0, (format_hints.Hex(fileobj.vol.offset), file_name, fileobj.Size))
|
||||
yield (0, (format_hints.Hex(fileobj.vol.offset), file_name))
|
||||
|
||||
def run(self):
|
||||
return renderers.TreeGrid(
|
||||
[("Offset", format_hints.Hex), ("Name", str), ("Size", int)],
|
||||
[("Offset", format_hints.Hex), ("Name", str)],
|
||||
self._generator(),
|
||||
)
|
||||
|
||||
@@ -25,7 +25,7 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
"""Lists process open handles."""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
_version = (1, 0, 1)
|
||||
_version = (1, 0, 2)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -142,6 +142,7 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
pointers in the _HANDLE_TABLE_ENTRY which allows us to find the
|
||||
associated _OBJECT_HEADER.
|
||||
"""
|
||||
DEFAULT_SAR_VALUE = 0x10 # to be used only when decoding fails
|
||||
|
||||
if self._sar_value is None:
|
||||
if not has_capstone:
|
||||
@@ -175,10 +176,11 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
virtual_layer_name, func_addr_to_read, num_bytes_to_read
|
||||
)
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.debug(
|
||||
f"Failed to read {hex(num_bytes_to_read)} bytes at symbol {hex(func_addr_to_read)}"
|
||||
vollog.warning(
|
||||
f"Failed to read {hex(num_bytes_to_read)} bytes at symbol {hex(func_addr_to_read)}. Unable to decode SAR value. Failing back to a common value of {hex(DEFAULT_SAR_VALUE)}"
|
||||
)
|
||||
return None
|
||||
self._sar_value = DEFAULT_SAR_VALUE
|
||||
return self._sar_value
|
||||
|
||||
md = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_64)
|
||||
|
||||
@@ -198,9 +200,10 @@ class Handles(interfaces.plugins.PluginInterface):
|
||||
break
|
||||
|
||||
if self._sar_value is None:
|
||||
vollog.debug(
|
||||
f"Failed to to locate SAR value having parsed {instruction_count} instructions"
|
||||
vollog.warning(
|
||||
f"Failed to to locate SAR value having parsed {instruction_count} instructions, failing back to a common value of {hex(DEFAULT_SAR_VALUE)}"
|
||||
)
|
||||
self._sar_value = DEFAULT_SAR_VALUE
|
||||
|
||||
return self._sar_value
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.interfaces import plugins
|
||||
from volatility3.framework.renderers import TreeGrid
|
||||
from volatility3.framework.symbols import intermed
|
||||
from volatility3.framework.symbols.windows import extensions
|
||||
from volatility3.framework.symbols.windows.extensions import kdbg, pe
|
||||
|
||||
|
||||
class Info(plugins.PluginInterface):
|
||||
@@ -94,16 +94,16 @@ class Info(plugins.PluginInterface):
|
||||
"windows",
|
||||
"kdbg",
|
||||
native_types=native_types,
|
||||
class_types=extensions.kdbg.class_types,
|
||||
class_types=kdbg.class_types,
|
||||
)
|
||||
|
||||
kdbg = context.object(
|
||||
kdbg_obj = context.object(
|
||||
kdbg_table_name + constants.BANG + "_KDDEBUGGER_DATA64",
|
||||
offset=ntkrnlmp.offset + kdbg_offset,
|
||||
layer_name=layer_name,
|
||||
)
|
||||
|
||||
return kdbg
|
||||
return kdbg_obj
|
||||
|
||||
@classmethod
|
||||
def get_kuser_structure(
|
||||
@@ -173,7 +173,7 @@ class Info(plugins.PluginInterface):
|
||||
interfaces.configuration.path_join(config_path, "pe"),
|
||||
"windows",
|
||||
"pe",
|
||||
class_types=extensions.pe.class_types,
|
||||
class_types=pe.class_types,
|
||||
)
|
||||
|
||||
dos_header = context.object(
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
# This file is Copyright 2024 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
|
||||
|
||||
from typing import Iterator, List, Tuple
|
||||
|
||||
from volatility3.framework import (
|
||||
renderers,
|
||||
interfaces,
|
||||
constants,
|
||||
)
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.objects import utility
|
||||
from volatility3.framework.renderers import format_hints
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class KPCRs(interfaces.plugins.PluginInterface):
|
||||
"""Print KPCR structure for each processor"""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.ModuleRequirement(
|
||||
name="kernel",
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def list_kpcrs(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
kernel_module_name: str,
|
||||
layer_name: str,
|
||||
symbol_table: str,
|
||||
) -> interfaces.objects.ObjectInterface:
|
||||
"""Returns the KPCR structure for each processor
|
||||
|
||||
Args:
|
||||
context: The context to retrieve required elements (layers, symbol tables) from
|
||||
kernel_module_name: The name of the kernel module on which to operate
|
||||
layer_name: The name of the layer on which to operate
|
||||
symbol_table: The name of the table containing the kernel symbols
|
||||
|
||||
Returns:
|
||||
The _KPCR structure for each processor
|
||||
"""
|
||||
|
||||
kernel = context.modules[kernel_module_name]
|
||||
cpu_count_offset = kernel.get_symbol("KeNumberProcessors").address
|
||||
cpu_count = kernel.object(
|
||||
object_type="unsigned int", layer_name=layer_name, offset=cpu_count_offset
|
||||
)
|
||||
processor_block = kernel.object(
|
||||
object_type="pointer",
|
||||
layer_name=layer_name,
|
||||
offset=kernel.get_symbol("KiProcessorBlock").address,
|
||||
)
|
||||
processor_pointers = utility.array_of_pointers(
|
||||
context=context,
|
||||
array=processor_block,
|
||||
count=cpu_count,
|
||||
subtype=symbol_table + constants.BANG + "_KPRCB",
|
||||
)
|
||||
for pointer in processor_pointers:
|
||||
kprcb = pointer.dereference()
|
||||
reloff = kernel.get_type("_KPCR").relative_child_offset("Prcb")
|
||||
kpcr = context.object(
|
||||
symbol_table + constants.BANG + "_KPCR",
|
||||
offset=kprcb.vol.offset - reloff,
|
||||
layer_name=layer_name,
|
||||
)
|
||||
yield kpcr
|
||||
|
||||
def _generator(self) -> Iterator[Tuple]:
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
layer_name = kernel.layer_name
|
||||
symbol_table = kernel.symbol_table_name
|
||||
|
||||
for kpcr in self.list_kpcrs(
|
||||
self.context, self.config["kernel"], layer_name, symbol_table
|
||||
):
|
||||
yield (
|
||||
0,
|
||||
(
|
||||
format_hints.Hex(kpcr.vol.offset),
|
||||
format_hints.Hex(kpcr.CurrentPrcb),
|
||||
),
|
||||
)
|
||||
|
||||
def run(self):
|
||||
return renderers.TreeGrid(
|
||||
[
|
||||
("Offset", format_hints.Hex),
|
||||
("PRCB Offset", format_hints.Hex),
|
||||
],
|
||||
self._generator(),
|
||||
)
|
||||
@@ -47,14 +47,6 @@ class LdrModules(interfaces.plugins.PluginInterface):
|
||||
self.context, self.config_path, "windows", "pe", class_types=pe.class_types
|
||||
)
|
||||
|
||||
def filter_function(x: interfaces.objects.ObjectInterface) -> bool:
|
||||
try:
|
||||
return not (x.get_private_memory() == 0 and x.ControlArea)
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
filter_func = filter_function
|
||||
|
||||
for proc in procs:
|
||||
proc_layer_name = proc.add_process_layer()
|
||||
|
||||
@@ -69,7 +61,7 @@ class LdrModules(interfaces.plugins.PluginInterface):
|
||||
|
||||
# Build dictionary of mapped files, where the VAD start address is the key and value is the file name of the mapped file
|
||||
mapped_files = {}
|
||||
for vad in vadinfo.VadInfo.list_vads(proc, filter_func=filter_func):
|
||||
for vad in vadinfo.VadInfo.list_vads(proc):
|
||||
dos_header = self.context.object(
|
||||
pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER",
|
||||
offset=vad.get_start(),
|
||||
|
||||
@@ -6,7 +6,7 @@ from typing import Iterable
|
||||
|
||||
from volatility3.framework import interfaces
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.plugins.windows import poolscanner, dlllist, pslist, modules
|
||||
from volatility3.plugins.windows import poolscanner, modules, pedump
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
@@ -35,12 +35,6 @@ class ModScan(modules.Modules):
|
||||
requirements.VersionRequirement(
|
||||
name="modules", component=modules.Modules, version=(2, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(2, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="dlllist", component=dlllist.DllList, version=(2, 0, 0)
|
||||
),
|
||||
requirements.BooleanRequirement(
|
||||
name="dump",
|
||||
description="Extract listed modules",
|
||||
@@ -58,6 +52,9 @@ class ModScan(modules.Modules):
|
||||
optional=True,
|
||||
default=None,
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="pedump", component=pedump.PEDump, version=(1, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -9,7 +9,7 @@ from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.symbols import intermed
|
||||
from volatility3.framework.symbols.windows.extensions import pe
|
||||
from volatility3.plugins.windows import pslist, dlllist
|
||||
from volatility3.plugins.windows import pslist, pedump
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
@@ -35,9 +35,6 @@ class Modules(interfaces.plugins.PluginInterface):
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(2, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="dlllist", component=dlllist.DllList, version=(2, 0, 0)
|
||||
),
|
||||
requirements.BooleanRequirement(
|
||||
name="dump",
|
||||
description="Extract listed modules",
|
||||
@@ -55,6 +52,9 @@ class Modules(interfaces.plugins.PluginInterface):
|
||||
optional=True,
|
||||
default=None,
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="pedump", component=pedump.PEDump, version=(1, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
def dump_module(self, session_layers, pe_table_name, mod):
|
||||
@@ -63,16 +63,15 @@ class Modules(interfaces.plugins.PluginInterface):
|
||||
)
|
||||
file_output = f"Cannot find a viable session layer for {mod.DllBase:#x}"
|
||||
if session_layer_name:
|
||||
file_handle = dlllist.DllList.dump_pe(
|
||||
file_output = pedump.PEDump.dump_ldr_entry(
|
||||
self.context,
|
||||
pe_table_name,
|
||||
mod,
|
||||
self.open,
|
||||
layer_name=session_layer_name,
|
||||
)
|
||||
file_output = "Error outputting file"
|
||||
if file_handle:
|
||||
file_output = file_handle.preferred_filename
|
||||
if not file_output:
|
||||
file_output = "Error outputting file"
|
||||
|
||||
return file_output
|
||||
|
||||
|
||||
@@ -218,6 +218,7 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
(10, 0, 18362, 0): "netscan-win10-18362-x64",
|
||||
(10, 0, 18363, 0): "netscan-win10-18363-x64",
|
||||
(10, 0, 19041, 0): "netscan-win10-19041-x64",
|
||||
(10, 0, 20348, 0): "netscan-win10-20348-x64",
|
||||
}
|
||||
|
||||
# we do not need to check for tcpip's specific FileVersion in every case
|
||||
|
||||
@@ -35,7 +35,7 @@ class NetStat(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
name="netscan", component=netscan.NetScan, version=(1, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="modules", component=modules.Modules, version=(1, 0, 0)
|
||||
name="modules", component=modules.Modules, version=(2, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="pdbutil", component=pdbutil.PDBUtility, version=(1, 0, 0)
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
# This file is Copyright 2024 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 ntpath
|
||||
from typing import List, Type, Optional
|
||||
|
||||
from volatility3.framework import constants, exceptions, interfaces, renderers
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.symbols import intermed
|
||||
from volatility3.framework.symbols.windows.extensions import pe
|
||||
from volatility3.plugins.windows import pslist, modules
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PEDump(interfaces.plugins.PluginInterface):
|
||||
"""Allows extracting PE Files from a specific address in a specific address space"""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@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.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(2, 0, 0)
|
||||
),
|
||||
requirements.ListRequirement(
|
||||
name="pid",
|
||||
element_type=int,
|
||||
description="Process IDs to include (all other processes are excluded)",
|
||||
optional=True,
|
||||
),
|
||||
requirements.IntRequirement(
|
||||
name="base",
|
||||
description="Base address to reconstruct a PE file",
|
||||
optional=False,
|
||||
),
|
||||
requirements.BooleanRequirement(
|
||||
name="kernel_module",
|
||||
description="Extract from kernel address space.",
|
||||
default=False,
|
||||
optional=True,
|
||||
),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def dump_pe(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
pe_table_name: str,
|
||||
layer_name: str,
|
||||
open_method: Type[interfaces.plugins.FileHandlerInterface],
|
||||
file_name: str,
|
||||
base: int,
|
||||
) -> Optional[str]:
|
||||
"""
|
||||
Returns the filename of the dump file or None
|
||||
"""
|
||||
try:
|
||||
file_handle = open_method(file_name)
|
||||
|
||||
dos_header = context.object(
|
||||
pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER",
|
||||
offset=base,
|
||||
layer_name=layer_name,
|
||||
)
|
||||
|
||||
for offset, data in dos_header.reconstruct():
|
||||
file_handle.seek(offset)
|
||||
file_handle.write(data)
|
||||
except (
|
||||
IOError,
|
||||
exceptions.VolatilityException,
|
||||
OverflowError,
|
||||
ValueError,
|
||||
) as excp:
|
||||
vollog.debug(f"Unable to dump PE file at offset {base}: {excp}")
|
||||
return None
|
||||
finally:
|
||||
file_handle.close()
|
||||
|
||||
return file_handle.preferred_filename
|
||||
|
||||
@classmethod
|
||||
def dump_ldr_entry(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
pe_table_name: str,
|
||||
ldr_entry: interfaces.objects.ObjectInterface,
|
||||
open_method: Type[interfaces.plugins.FileHandlerInterface],
|
||||
layer_name: str = None,
|
||||
prefix: str = "",
|
||||
) -> Optional[str]:
|
||||
"""Extracts the PE file referenced an LDR_DATA_TABLE_ENTRY (DLL, kernel module) instance
|
||||
|
||||
Args:
|
||||
context: the context to operate upon
|
||||
pe_table_name: the name for the symbol table containing the PE format symbols
|
||||
ldr_entry: the object representing the module
|
||||
open_method: class for constructing output files
|
||||
layer_name: the layer that the DLL lives within
|
||||
prefix: optional string to prepend to filename
|
||||
Returns:
|
||||
The output file name or None in the case of failure
|
||||
"""
|
||||
try:
|
||||
name = ldr_entry.FullDllName.get_string()
|
||||
except exceptions.InvalidAddressException:
|
||||
name = "UnreadableDLLName"
|
||||
|
||||
if layer_name is None:
|
||||
layer_name = ldr_entry.vol.layer_name
|
||||
|
||||
file_name = "{}{}.{:#x}.{:#x}.dmp".format(
|
||||
prefix,
|
||||
ntpath.basename(name),
|
||||
ldr_entry.vol.offset,
|
||||
ldr_entry.DllBase,
|
||||
)
|
||||
|
||||
return cls.dump_pe(
|
||||
context,
|
||||
pe_table_name,
|
||||
layer_name,
|
||||
open_method,
|
||||
file_name,
|
||||
ldr_entry.DllBase,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def dump_pe_at_base(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
pe_table_name: str,
|
||||
layer_name: str,
|
||||
open_method: Type[interfaces.plugins.FileHandlerInterface],
|
||||
proc_offset: int,
|
||||
pid: int,
|
||||
base: int,
|
||||
) -> Optional[str]:
|
||||
file_name = "PE.{:#x}.{:d}.{:#x}.dmp".format(
|
||||
proc_offset,
|
||||
pid,
|
||||
base,
|
||||
)
|
||||
|
||||
return PEDump.dump_pe(
|
||||
context, pe_table_name, layer_name, open_method, file_name, base
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def dump_kernel_pe_at_base(cls, context, kernel, pe_table_name, open_method, base):
|
||||
session_layers = modules.Modules.get_session_layers(
|
||||
context, kernel.layer_name, kernel.symbol_table_name
|
||||
)
|
||||
|
||||
session_layer_name = modules.Modules.find_session_layer(
|
||||
context, session_layers, base
|
||||
)
|
||||
|
||||
if session_layer_name:
|
||||
system_pid = 4
|
||||
|
||||
file_output = PEDump.dump_pe_at_base(
|
||||
context,
|
||||
pe_table_name,
|
||||
session_layer_name,
|
||||
open_method,
|
||||
0,
|
||||
system_pid,
|
||||
base,
|
||||
)
|
||||
|
||||
if file_output:
|
||||
yield system_pid, "Kernel", file_output
|
||||
else:
|
||||
vollog.warning(
|
||||
"Unable to find a session layer with the provided base address mapped in the kernel."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def dump_processes(
|
||||
cls, context, kernel, pe_table_name, open_method, filter_func, base
|
||||
):
|
||||
""" """
|
||||
|
||||
for proc in pslist.PsList.list_processes(
|
||||
context=context,
|
||||
layer_name=kernel.layer_name,
|
||||
symbol_table=kernel.symbol_table_name,
|
||||
filter_func=filter_func,
|
||||
):
|
||||
pid = proc.UniqueProcessId
|
||||
proc_name = proc.ImageFileName.cast(
|
||||
"string",
|
||||
max_length=proc.ImageFileName.vol.count,
|
||||
errors="replace",
|
||||
)
|
||||
proc_layer_name = proc.add_process_layer()
|
||||
|
||||
file_output = PEDump.dump_pe_at_base(
|
||||
context,
|
||||
pe_table_name,
|
||||
proc_layer_name,
|
||||
open_method,
|
||||
proc.vol.offset,
|
||||
pid,
|
||||
base,
|
||||
)
|
||||
|
||||
if file_output:
|
||||
yield pid, proc_name, file_output
|
||||
|
||||
def _generator(self):
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
|
||||
pe_table_name = intermed.IntermediateSymbolTable.create(
|
||||
self.context, self.config_path, "windows", "pe", class_types=pe.class_types
|
||||
)
|
||||
|
||||
if self.config["kernel_module"] and self.config["pid"]:
|
||||
vollog.error("Only --kernel_module or --pid should be set. Not both")
|
||||
return
|
||||
|
||||
if not self.config["kernel_module"] and not self.config["pid"]:
|
||||
vollog.error("--kernel_module or --pid must be set")
|
||||
return
|
||||
|
||||
if self.config["kernel_module"]:
|
||||
pe_files = self.dump_kernel_pe_at_base(
|
||||
self.context, kernel, pe_table_name, self.open, self.config["base"]
|
||||
)
|
||||
else:
|
||||
filter_func = pslist.PsList.create_pid_filter(self.config.get("pid", None))
|
||||
pe_files = self.dump_processes(
|
||||
self.context,
|
||||
kernel,
|
||||
pe_table_name,
|
||||
self.open,
|
||||
filter_func,
|
||||
self.config["base"],
|
||||
)
|
||||
|
||||
for pid, proc_name, file_output in pe_files:
|
||||
yield (
|
||||
0,
|
||||
(
|
||||
pid,
|
||||
proc_name,
|
||||
file_output,
|
||||
),
|
||||
)
|
||||
|
||||
def run(self):
|
||||
return renderers.TreeGrid(
|
||||
[
|
||||
("PID", int),
|
||||
("Process", str),
|
||||
("File output", str),
|
||||
],
|
||||
self._generator(),
|
||||
)
|
||||
@@ -0,0 +1,104 @@
|
||||
# This file is Copyright 2024 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 contextlib
|
||||
|
||||
from volatility3.framework import interfaces, exceptions
|
||||
from volatility3.framework import renderers
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.objects import utility
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.plugins.windows import pslist
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ProcessGhosting(interfaces.plugins.PluginInterface):
|
||||
"""Lists processes whose DeletePending bit is set or whose FILE_OBJECT is set to 0"""
|
||||
|
||||
_required_framework_version = (2, 4, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
# 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.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
def _generator(self, procs):
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
|
||||
if not kernel.get_type("_EPROCESS").has_member("ImageFilePointer"):
|
||||
vollog.warning(
|
||||
"This plugin only supports Windows 10 builds when the ImageFilePointer member of _EPROCESS is present"
|
||||
)
|
||||
return
|
||||
|
||||
for proc in procs:
|
||||
delete_pending = renderers.UnreadableValue()
|
||||
process_name = utility.array_to_string(proc.ImageFileName)
|
||||
|
||||
# if it is 0 then its a side effect of process ghosting
|
||||
if proc.ImageFilePointer.vol.offset != 0:
|
||||
try:
|
||||
file_object = proc.ImageFilePointer
|
||||
delete_pending = file_object.DeletePending
|
||||
except exceptions.InvalidAddressException:
|
||||
file_object = 0
|
||||
|
||||
# ImageFilePointer equal to 0 means process ghosting or similar techniques were used
|
||||
else:
|
||||
file_object = 0
|
||||
|
||||
if isinstance(delete_pending, int) and delete_pending not in [0, 1]:
|
||||
vollog.debug(
|
||||
f"Invalid delete_pending value {delete_pending} found for {process_name} {proc.UniqueProcessId}"
|
||||
)
|
||||
|
||||
# delete_pending besides 0 or 1 = smear
|
||||
if file_object == 0 or delete_pending == 1:
|
||||
path = renderers.UnreadableValue()
|
||||
if file_object:
|
||||
with contextlib.suppress(exceptions.InvalidAddressException):
|
||||
path = file_object.FileName.String
|
||||
|
||||
yield (
|
||||
0,
|
||||
(
|
||||
proc.UniqueProcessId,
|
||||
process_name,
|
||||
format_hints.Hex(file_object),
|
||||
delete_pending,
|
||||
path,
|
||||
),
|
||||
)
|
||||
|
||||
def run(self):
|
||||
filter_func = pslist.PsList.create_active_process_filter()
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
|
||||
return renderers.TreeGrid(
|
||||
[
|
||||
("PID", int),
|
||||
("Process", str),
|
||||
("FILE_OBJECT", format_hints.Hex),
|
||||
("DeletePending", str),
|
||||
("Path", str),
|
||||
],
|
||||
self._generator(
|
||||
pslist.PsList.list_processes(
|
||||
context=self.context,
|
||||
layer_name=kernel.layer_name,
|
||||
symbol_table=kernel.symbol_table_name,
|
||||
filter_func=filter_func,
|
||||
)
|
||||
),
|
||||
)
|
||||
@@ -136,6 +136,29 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
filter_func = lambda x: x.UniqueProcessId not in filter_list
|
||||
return filter_func
|
||||
|
||||
@classmethod
|
||||
def create_active_process_filter(
|
||||
cls,
|
||||
) -> Callable[[interfaces.objects.ObjectInterface], bool]:
|
||||
"""A factory for producing a filter function that only returns
|
||||
active, userland processes. This prevents plugins from operating on terminated
|
||||
processes that are still in the process list due to smear or handle leaks as well
|
||||
as kernel processes (System, Registry, etc.). Use of this filter for plugins searching
|
||||
for system state anomalies significantly reduces false positive in smeared and terminated
|
||||
processes.
|
||||
Returns:
|
||||
Filter function for passing to the `list_processes` method
|
||||
"""
|
||||
|
||||
return lambda x: not (
|
||||
x.is_valid()
|
||||
and x.ActiveThreads > 0
|
||||
and x.UniqueProcessId != 4
|
||||
and x.InheritedFromUniqueProcessId != 4
|
||||
and x.ExitTime.QuadPart == 0
|
||||
and x.get_handle_count() != renderers.UnreadableValue()
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def create_name_filter(
|
||||
cls, name_list: List[str] = None, exclude: bool = False
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
import datetime, logging, string
|
||||
|
||||
from volatility3.framework import constants, exceptions
|
||||
from volatility3.framework.interfaces import plugins
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.renderers import format_hints, TreeGrid
|
||||
from volatility3.plugins.windows import (
|
||||
handles,
|
||||
info,
|
||||
pslist,
|
||||
psscan,
|
||||
sessions,
|
||||
thrdscan,
|
||||
)
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PsXView(plugins.PluginInterface):
|
||||
"""Lists all processes found via four of the methods described in \"The Art of Memory Forensics,\" which may help
|
||||
identify processes that are trying to hide themselves. I recommend using -r pretty if you are looking at this
|
||||
plugin's output in a terminal."""
|
||||
|
||||
# I've omitted the desktop thread scanning method because Volatility3 doesn't appear to have the funcitonality
|
||||
# which the original plugin used to do it.
|
||||
|
||||
# The sessions method is omitted because it begins with the list of processes found by Pslist anyway.
|
||||
|
||||
# Lastly, I've omitted the pspcid method because I could not for the life of me get it to work. I saved the
|
||||
# code I do have from it, and will happily share it if anyone else wants to add it.
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
valid_proc_name_chars = set(
|
||||
string.ascii_lowercase + string.ascii_uppercase + "." + " "
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
return [
|
||||
requirements.ModuleRequirement(
|
||||
name="kernel",
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="info", component=info.Info, version=(1, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="pslist", component=pslist.PsList, version=(2, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="psscan", component=psscan.PsScan, version=(1, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="thrdscan", component=thrdscan.ThrdScan, version=(1, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="handles", component=handles.Handles, version=(1, 0, 0)
|
||||
),
|
||||
requirements.BooleanRequirement(
|
||||
name="physical-offsets",
|
||||
description="List processes with physical offsets instead of virtual offsets.",
|
||||
optional=True,
|
||||
),
|
||||
]
|
||||
|
||||
def _proc_name_to_string(self, proc):
|
||||
return proc.ImageFileName.cast(
|
||||
"string", max_length=proc.ImageFileName.vol.count, errors="replace"
|
||||
)
|
||||
|
||||
def _is_valid_proc_name(self, str):
|
||||
for c in str:
|
||||
if not c in self.valid_proc_name_chars:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _filter_garbage_procs(self, proc_list):
|
||||
return [
|
||||
p
|
||||
for p in proc_list
|
||||
if p.is_valid() and self._is_valid_proc_name(self._proc_name_to_string(p))
|
||||
]
|
||||
|
||||
def _translate_offset(self, offset):
|
||||
if not self.config["physical-offsets"]:
|
||||
return offset
|
||||
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
layer_name = kernel.layer_name
|
||||
|
||||
try:
|
||||
_original_offset, _original_length, offset, _length, _layer_name = list(
|
||||
self.context.layers[layer_name].mapping(offset=offset, length=0)
|
||||
)[0]
|
||||
except exceptions.PagedInvalidAddressException:
|
||||
vollog.debug(f"Page fault: unable to translate {offset:0x}")
|
||||
|
||||
return offset
|
||||
|
||||
def _proc_list_to_dict(self, tasks):
|
||||
tasks = self._filter_garbage_procs(tasks)
|
||||
return {self._translate_offset(proc.vol.offset): proc for proc in tasks}
|
||||
|
||||
def _check_pslist(self, tasks):
|
||||
return self._proc_list_to_dict(tasks)
|
||||
|
||||
def _check_psscan(self, layer_name, symbol_table):
|
||||
res = psscan.PsScan.scan_processes(
|
||||
context=self.context, layer_name=layer_name, symbol_table=symbol_table
|
||||
)
|
||||
|
||||
return self._proc_list_to_dict(res)
|
||||
|
||||
def _check_thrdscan(self):
|
||||
ret = []
|
||||
|
||||
for ethread in thrdscan.ThrdScan.scan_threads(
|
||||
self.context, module_name="kernel"
|
||||
):
|
||||
process = None
|
||||
try:
|
||||
process = ethread.owning_process()
|
||||
if not process.is_valid():
|
||||
continue
|
||||
|
||||
ret.append(process)
|
||||
except AttributeError:
|
||||
vollog.log(
|
||||
constants.LOGLEVEL_VVV,
|
||||
"Unable to find the owning process of ethread",
|
||||
)
|
||||
|
||||
return self._proc_list_to_dict(ret)
|
||||
|
||||
def _check_csrss_handles(self, tasks, layer_name, symbol_table):
|
||||
ret = []
|
||||
|
||||
for p in tasks:
|
||||
name = self._proc_name_to_string(p)
|
||||
if name == "csrss.exe":
|
||||
try:
|
||||
if p.has_member("ObjectTable"):
|
||||
handles_plugin = handles.Handles(
|
||||
context=self.context, config_path=self.config_path
|
||||
)
|
||||
hndls = list(handles_plugin.handles(p.ObjectTable))
|
||||
for h in hndls:
|
||||
if (
|
||||
h.get_object_type(
|
||||
handles_plugin.get_type_map(
|
||||
self.context, layer_name, symbol_table
|
||||
)
|
||||
)
|
||||
== "Process"
|
||||
):
|
||||
ret.append(h.Body.cast("_EPROCESS"))
|
||||
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.log(
|
||||
constants.LOGLEVEL_VVV, "Cannot access eprocess object table"
|
||||
)
|
||||
|
||||
return self._proc_list_to_dict(ret)
|
||||
|
||||
def _generator(self):
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
|
||||
layer_name = kernel.layer_name
|
||||
symbol_table = kernel.symbol_table_name
|
||||
|
||||
kdbg_list_processes = list(
|
||||
pslist.PsList.list_processes(
|
||||
context=self.context, layer_name=layer_name, symbol_table=symbol_table
|
||||
)
|
||||
)
|
||||
|
||||
# get processes from each source
|
||||
processes = {}
|
||||
|
||||
processes["pslist"] = self._check_pslist(kdbg_list_processes)
|
||||
processes["psscan"] = self._check_psscan(layer_name, symbol_table)
|
||||
processes["thrdscan"] = self._check_thrdscan()
|
||||
processes["csrss"] = self._check_csrss_handles(
|
||||
kdbg_list_processes, layer_name, symbol_table
|
||||
)
|
||||
|
||||
# print results
|
||||
|
||||
# list of lists of offsets
|
||||
offsets = [list(processes[source].keys()) for source in processes]
|
||||
|
||||
# flatten to one list
|
||||
offsets = sum(offsets, [])
|
||||
|
||||
# remove duplicates
|
||||
offsets = set(offsets)
|
||||
|
||||
for offset in offsets:
|
||||
proc = None
|
||||
|
||||
in_sources = {src: False for src in processes}
|
||||
|
||||
for source in processes:
|
||||
if offset in processes[source]:
|
||||
in_sources[source] = True
|
||||
if not proc:
|
||||
proc = processes[source][offset]
|
||||
|
||||
pid = proc.UniqueProcessId
|
||||
name = self._proc_name_to_string(proc)
|
||||
|
||||
exit_time = proc.get_exit_time()
|
||||
if type(exit_time) != datetime.datetime:
|
||||
exit_time = ""
|
||||
else:
|
||||
exit_time = str(exit_time)
|
||||
|
||||
yield (
|
||||
0,
|
||||
(
|
||||
format_hints.Hex(offset),
|
||||
name,
|
||||
pid,
|
||||
in_sources["pslist"],
|
||||
in_sources["psscan"],
|
||||
in_sources["thrdscan"],
|
||||
in_sources["csrss"],
|
||||
exit_time,
|
||||
),
|
||||
)
|
||||
|
||||
def run(self):
|
||||
offset_type = "(Physical)" if self.config["physical-offsets"] else "(Virtual)"
|
||||
offset_str = "Offset" + offset_type
|
||||
|
||||
return TreeGrid(
|
||||
[
|
||||
(offset_str, format_hints.Hex),
|
||||
("Name", str),
|
||||
("PID", int),
|
||||
("pslist", bool),
|
||||
("psscan", bool),
|
||||
("thrdscan", bool),
|
||||
("csrss", bool),
|
||||
("Exit Time", str),
|
||||
],
|
||||
self._generator(),
|
||||
)
|
||||
@@ -17,11 +17,12 @@ from volatility3.framework.layers.registry import RegistryHive
|
||||
from volatility3.framework.renderers import conversion, format_hints
|
||||
from volatility3.framework.symbols import intermed
|
||||
from volatility3.plugins.windows.registry import hivelist
|
||||
from volatility3.plugins import timeliner
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UserAssist(interfaces.plugins.PluginInterface):
|
||||
class UserAssist(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
"""Print userassist registry keys and information."""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
@@ -285,6 +286,10 @@ class UserAssist(interfaces.plugins.PluginInterface):
|
||||
hive_offsets = [self.config.get("offset", None)]
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
|
||||
self._reg_table_name = intermed.IntermediateSymbolTable.create(
|
||||
self.context, self._config_path, "windows", "registry"
|
||||
)
|
||||
|
||||
# get all the user hive offsets or use the one specified
|
||||
for hive in hivelist.HiveList.list_hives(
|
||||
context=self.context,
|
||||
@@ -335,11 +340,17 @@ class UserAssist(interfaces.plugins.PluginInterface):
|
||||
)
|
||||
yield result
|
||||
|
||||
def run(self):
|
||||
self._reg_table_name = intermed.IntermediateSymbolTable.create(
|
||||
self.context, self._config_path, "windows", "registry"
|
||||
)
|
||||
def generate_timeline(self):
|
||||
for row in self._generator():
|
||||
_depth, row_data = row
|
||||
# check the name and the timestamp to not be empty
|
||||
if isinstance(row_data[5], str) and not isinstance(
|
||||
row_data[10], renderers.NotApplicableValue
|
||||
):
|
||||
description = f"UserAssist: {row_data[5]} {row_data[2]} ({row_data[7]})"
|
||||
yield (description, timeliner.TimeLinerType.MODIFIED, row_data[10])
|
||||
|
||||
def run(self):
|
||||
return renderers.TreeGrid(
|
||||
[
|
||||
("Hive Offset", renderers.format_hints.Hex),
|
||||
|
||||
@@ -0,0 +1,610 @@
|
||||
# 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 logging
|
||||
import os
|
||||
from datetime import datetime
|
||||
from itertools import count
|
||||
from typing import Iterator, List, Optional, Tuple
|
||||
|
||||
from volatility3.framework import constants, exceptions, interfaces, renderers, symbols
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.objects.utility import array_to_string
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.symbols import intermed
|
||||
from volatility3.framework.symbols.windows import versions
|
||||
from volatility3.framework.symbols.windows.extensions import pe, shimcache
|
||||
from volatility3.plugins import timeliner
|
||||
from volatility3.plugins.windows import modules, pslist, vadinfo
|
||||
|
||||
# from volatility3.plugins.windows import pslist, vadinfo, modules
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ShimcacheMem(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
"""Reads Shimcache entries from the ahcache.sys AVL tree"""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
|
||||
# These checks must be completed from newest -> oldest OS version.
|
||||
_win_version_file_map: List[Tuple[versions.OsDistinguisher, bool, str]] = [
|
||||
(versions.is_win10, True, "shimcache-win10-x64"),
|
||||
(versions.is_win10, False, "shimcache-win10-x86"),
|
||||
(versions.is_windows_8_or_later, True, "shimcache-win8-x64"),
|
||||
(versions.is_windows_8_or_later, False, "shimcache-win8-x86"),
|
||||
(versions.is_windows_7, True, "shimcache-win7-x64"),
|
||||
(versions.is_windows_7, False, "shimcache-win7-x86"),
|
||||
(versions.is_vista_or_later, True, "shimcache-vista-x64"),
|
||||
(versions.is_vista_or_later, False, "shimcache-vista-x86"),
|
||||
(versions.is_2003, False, "shimcache-2003-x86"),
|
||||
(versions.is_2003, True, "shimcache-2003-x64"),
|
||||
(versions.is_windows_xp_sp3, False, "shimcache-xp-sp3-x86"),
|
||||
(versions.is_windows_xp_sp2, False, "shimcache-xp-sp2-x86"),
|
||||
(versions.is_xp_or_2003, True, "shimcache-xp-2003-x64"),
|
||||
(versions.is_xp_or_2003, False, "shimcache-xp-2003-x86"),
|
||||
]
|
||||
|
||||
NT_KRNL_MODS = ["ntoskrnl.exe", "ntkrnlpa.exe", "ntkrnlmp.exe", "ntkrpamp.exe"]
|
||||
|
||||
def generate_timeline(
|
||||
self,
|
||||
) -> Iterator[Tuple[str, timeliner.TimeLinerType, datetime]]:
|
||||
for _, (_, last_modified, last_update, _, _, file_path) in self._generator():
|
||||
if isinstance(last_update, datetime):
|
||||
yield f"Shimcache: File {file_path} executed", timeliner.TimeLinerType.ACCESSED, last_update
|
||||
if isinstance(last_modified, datetime):
|
||||
yield f"Shimcache: File {file_path} modified", timeliner.TimeLinerType.MODIFIED, last_modified
|
||||
|
||||
@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.PluginRequirement(
|
||||
name="pslist", plugin=pslist.PsList, version=(2, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="vadinfo", component=vadinfo.VadInfo, version=(2, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="modules", component=modules.Modules, version=(2, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def create_shimcache_table(
|
||||
context: interfaces.context.ContextInterface,
|
||||
symbol_table: str,
|
||||
config_path: str,
|
||||
) -> str:
|
||||
"""Creates a shimcache symbol table
|
||||
|
||||
Args:
|
||||
context: The context to retrieve required elements (layers, symbol tables) from
|
||||
symbol_table: The name of an existing symbol table containing the kernel symbols
|
||||
config_path: The configuration path within the context of the symbol table to create
|
||||
|
||||
Returns:
|
||||
The name of the constructed shimcache table
|
||||
"""
|
||||
native_types = context.symbol_space[symbol_table].natives
|
||||
is_64bit = symbols.symbol_table_is_64bit(context, symbol_table)
|
||||
table_mapping = {"nt_symbols": symbol_table}
|
||||
|
||||
try:
|
||||
symbol_filename = next(
|
||||
filename
|
||||
for version_check, for_64bit, filename in ShimcacheMem._win_version_file_map
|
||||
if is_64bit == for_64bit
|
||||
and version_check(context=context, symbol_table=symbol_table)
|
||||
)
|
||||
except StopIteration:
|
||||
raise NotImplementedError("This version of Windows is not supported!")
|
||||
|
||||
vollog.debug(f"Using shimcache table {symbol_filename}")
|
||||
|
||||
return intermed.IntermediateSymbolTable.create(
|
||||
context,
|
||||
config_path,
|
||||
os.path.join("windows", "shimcache"),
|
||||
symbol_filename,
|
||||
class_types=shimcache.class_types,
|
||||
native_types=native_types,
|
||||
table_mapping=table_mapping,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def find_shimcache_win_xp(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
layer_name: str,
|
||||
kernel_symbol_table: str,
|
||||
shimcache_symbol_table: str,
|
||||
) -> Iterator[shimcache.SHIM_CACHE_ENTRY]:
|
||||
"""Attempts to find the shimcache in a Windows XP memory image
|
||||
|
||||
:param context: The context to retrieve required elements (layers, symbol tables) from
|
||||
:param layer_name: The name of the memory layer on which to operate.
|
||||
:param kernel_symbol_table: The name of an existing symbol table containing the kernel symbols
|
||||
:param shimcache_symbol_table: The name of a symbol table containing the hand-crafted shimcache symbols
|
||||
"""
|
||||
|
||||
SHIM_NUM_ENTRIES_OFFSET = 0x8
|
||||
SHIM_MAX_ENTRIES = 0x60 # 96 max entries in XP shim cache
|
||||
SHIM_LRU_OFFSET = 0x10
|
||||
SHIM_HEADER_SIZE = 0x190
|
||||
SHIM_CACHE_ENTRY_SIZE = 0x228
|
||||
|
||||
seen = set()
|
||||
|
||||
for process in pslist.PsList.list_processes(
|
||||
context, layer_name, kernel_symbol_table
|
||||
):
|
||||
pid = process.UniqueProcessId
|
||||
vollog.debug("checking process %d" % pid)
|
||||
for vad in vadinfo.VadInfo.list_vads(
|
||||
process, lambda x: x.get_tag() == b"Vad " and x.Protection == 4
|
||||
):
|
||||
try:
|
||||
proc_layer_name = process.add_process_layer()
|
||||
proc_layer = context.layers[proc_layer_name]
|
||||
except exceptions.InvalidAddressException:
|
||||
continue
|
||||
|
||||
try:
|
||||
if proc_layer.read(vad.get_start(), 4) != b"\xEF\xBE\xAD\xDE":
|
||||
if pid == 624:
|
||||
vollog.debug("VAD magic bytes don't match DEADBEEF")
|
||||
continue
|
||||
except exceptions.InvalidAddressException:
|
||||
continue
|
||||
|
||||
num_entries = context.object(
|
||||
shimcache_symbol_table + constants.BANG + "unsigned int",
|
||||
proc_layer_name,
|
||||
vad.get_start() + SHIM_NUM_ENTRIES_OFFSET,
|
||||
)
|
||||
|
||||
if num_entries > SHIM_MAX_ENTRIES:
|
||||
continue
|
||||
|
||||
cache_idx_ptr = vad.get_start() + SHIM_LRU_OFFSET
|
||||
|
||||
for _ in range(num_entries):
|
||||
cache_idx_val = proc_layer.context.object(
|
||||
shimcache_symbol_table + constants.BANG + "unsigned long",
|
||||
proc_layer_name,
|
||||
cache_idx_ptr,
|
||||
)
|
||||
|
||||
cache_idx_ptr += 4
|
||||
|
||||
if cache_idx_val > SHIM_MAX_ENTRIES - 1:
|
||||
continue
|
||||
|
||||
shim_entry_offset = (
|
||||
vad.get_start()
|
||||
+ SHIM_HEADER_SIZE
|
||||
+ (SHIM_CACHE_ENTRY_SIZE * cache_idx_val)
|
||||
)
|
||||
|
||||
if not proc_layer.is_valid(shim_entry_offset):
|
||||
continue
|
||||
|
||||
physical_addr = proc_layer.translate(shim_entry_offset)
|
||||
|
||||
if physical_addr in seen:
|
||||
continue
|
||||
seen.add(physical_addr)
|
||||
|
||||
shim_entry = proc_layer.context.object(
|
||||
shimcache_symbol_table + constants.BANG + "SHIM_CACHE_ENTRY",
|
||||
proc_layer_name,
|
||||
shim_entry_offset,
|
||||
)
|
||||
if not proc_layer.is_valid(shim_entry.vol.offset):
|
||||
continue
|
||||
if not shim_entry.is_valid():
|
||||
continue
|
||||
|
||||
yield shim_entry
|
||||
|
||||
@classmethod
|
||||
def find_shimcache_win_2k3_to_7(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
config_path: str,
|
||||
kernel_layer_name: str,
|
||||
nt_symbol_table: str,
|
||||
shimcache_symbol_table: str,
|
||||
) -> Iterator[shimcache.SHIM_CACHE_ENTRY]:
|
||||
"""Implements the algorithm to search for the shim cache on Windows 2000
|
||||
(x64) through Windows 7 / 2008 R2. The algorithm consists of the following:
|
||||
|
||||
1) Find the NT kernel module's .data and PAGE sections
|
||||
2) Iterate over every 4/8 bytes (depending on OS bitness) in the .data
|
||||
section and test for the following:
|
||||
a) offset represents a valid RTL_AVL_TABLE object
|
||||
b) RTL_AVL_TABLE is preceeded by an ERESOURCE object
|
||||
c) RTL_AVL_TABLE is followed by the beginning of the SHIM LRU list
|
||||
|
||||
:param context: The context to retrieve required elements (layers, symbol tables) from
|
||||
:param layer_name: The name of the memory layer on which to operate.
|
||||
:param kernel_symbol_table: The name of an existing symbol table containing the kernel symbols
|
||||
:param shimcache_symbol_table: The name of a symbol table containing the hand-crafted shimcache symbols
|
||||
"""
|
||||
|
||||
data_sec = cls.get_module_section_range(
|
||||
context,
|
||||
config_path,
|
||||
kernel_layer_name,
|
||||
nt_symbol_table,
|
||||
cls.NT_KRNL_MODS,
|
||||
".data",
|
||||
)
|
||||
mod_page = cls.get_module_section_range(
|
||||
context,
|
||||
config_path,
|
||||
kernel_layer_name,
|
||||
nt_symbol_table,
|
||||
cls.NT_KRNL_MODS,
|
||||
"PAGE",
|
||||
)
|
||||
|
||||
# We require both in order to accurately handle AVL table
|
||||
if not (data_sec and mod_page):
|
||||
return None
|
||||
|
||||
data_sec_offset, data_sec_size = data_sec
|
||||
mod_page_offset, mod_page_size = mod_page
|
||||
|
||||
addr_size = 8 if symbols.symbol_table_is_64bit(context, nt_symbol_table) else 4
|
||||
|
||||
shim_head = None
|
||||
for offset in range(
|
||||
data_sec_offset, data_sec_offset + data_sec_size, addr_size
|
||||
):
|
||||
shim_head = cls.try_get_shim_head_at_offset(
|
||||
context,
|
||||
shimcache_symbol_table,
|
||||
nt_symbol_table,
|
||||
kernel_layer_name,
|
||||
mod_page_offset,
|
||||
mod_page_offset + mod_page_size,
|
||||
offset,
|
||||
)
|
||||
|
||||
if shim_head:
|
||||
break
|
||||
|
||||
if not shim_head:
|
||||
return
|
||||
|
||||
for shim_entry in shim_head.ListEntry.to_list(
|
||||
shimcache_symbol_table + constants.BANG + "SHIM_CACHE_ENTRY", "ListEntry"
|
||||
):
|
||||
yield shim_entry
|
||||
|
||||
@classmethod
|
||||
def try_get_shim_head_at_offset(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
symbol_table: str,
|
||||
kernel_symbol_table: str,
|
||||
layer_name: str,
|
||||
mod_page_start: int,
|
||||
mod_page_end: int,
|
||||
offset: int,
|
||||
) -> Optional[shimcache.SHIM_CACHE_ENTRY]:
|
||||
"""Attempts to construct a SHIM_CACHE_HEAD within a layer of the given context,
|
||||
using the provided offset within that layer, as well as the start and end offsets
|
||||
of the kernel module's `PAGE` section start and end offsets.
|
||||
|
||||
If a number of validity checks are passed, this method will return the `SHIM_CACHE_HEAD`
|
||||
object. Otherwise, `None` is returned.
|
||||
"""
|
||||
# print("checking RTL_AVL_TABLE at offset %s" % hex(offset))
|
||||
rtl_avl_table = context.object(
|
||||
symbol_table + constants.BANG + "_RTL_AVL_TABLE", layer_name, offset
|
||||
)
|
||||
if not rtl_avl_table.is_valid(mod_page_start, mod_page_end):
|
||||
return None
|
||||
|
||||
vollog.debug(f"Candidate RTL_AVL_TABLE found at offset {hex(offset)}")
|
||||
|
||||
ersrc_size = context.symbol_space.get_type(
|
||||
kernel_symbol_table + constants.BANG + "_ERESOURCE"
|
||||
).size
|
||||
ersrc_alignment = (
|
||||
0x20
|
||||
if symbols.symbol_table_is_64bit(context, kernel_symbol_table)
|
||||
else 0x10
|
||||
# 0x20 if context.symbol_space.get_type("pointer").size == 8 else 0x10
|
||||
)
|
||||
vollog.debug(
|
||||
f"ERESOURCE size: {hex(ersrc_size)}, ERESOURCE alignment: {hex(ersrc_alignment)}"
|
||||
)
|
||||
|
||||
eresource_rel_off = ersrc_size + ((offset - ersrc_size) % ersrc_alignment)
|
||||
eresource_offset = offset - eresource_rel_off
|
||||
|
||||
vollog.debug("Constructing ERESOURCE at %s" % hex(eresource_offset))
|
||||
eresource = context.object(
|
||||
kernel_symbol_table + constants.BANG + "_ERESOURCE",
|
||||
layer_name,
|
||||
eresource_offset,
|
||||
)
|
||||
if not eresource.is_valid():
|
||||
vollog.debug("ERESOURCE Invalid")
|
||||
return None
|
||||
|
||||
shim_head_offset = offset + rtl_avl_table.vol.size
|
||||
|
||||
if not context.layers[layer_name].is_valid(shim_head_offset):
|
||||
return None
|
||||
|
||||
shim_head = context.object(
|
||||
symbol_table + constants.BANG + "SHIM_CACHE_ENTRY",
|
||||
layer_name,
|
||||
shim_head_offset,
|
||||
)
|
||||
|
||||
if not shim_head.is_valid():
|
||||
vollog.debug("shim head invalid")
|
||||
return None
|
||||
else:
|
||||
vollog.debug("returning shim head")
|
||||
return shim_head
|
||||
|
||||
@classmethod
|
||||
def find_shimcache_win_8_or_later(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
config_path: str,
|
||||
kernel_layer_name: str,
|
||||
nt_symbol_table: str,
|
||||
shimcache_symbol_table: str,
|
||||
) -> Iterator[shimcache.SHIM_CACHE_ENTRY]:
|
||||
"""Attempts to locate and yield shimcache entries from a Windows 8 or later memory image.
|
||||
|
||||
:param context: The context to retrieve required elements (layers, symbol tables) from
|
||||
:param layer_name: The name of the memory layer on which to operate.
|
||||
:param kernel_symbol_table: The name of an existing symbol table containing the kernel symbols
|
||||
:param shimcache_symbol_table: The name of a symbol table containing the hand-crafted shimcache symbols
|
||||
"""
|
||||
|
||||
is_8_1_or_later = versions.is_windows_8_1_or_later(
|
||||
context, nt_symbol_table
|
||||
) or versions.is_win10(context, nt_symbol_table)
|
||||
|
||||
module_names = ["ahcache.sys"] if is_8_1_or_later else cls.NT_KRNL_MODS
|
||||
vollog.debug(f"Searching for modules {module_names}")
|
||||
|
||||
data_sec = cls.get_module_section_range(
|
||||
context,
|
||||
config_path,
|
||||
kernel_layer_name,
|
||||
nt_symbol_table,
|
||||
module_names,
|
||||
".data",
|
||||
)
|
||||
mod_page = cls.get_module_section_range(
|
||||
context,
|
||||
config_path,
|
||||
kernel_layer_name,
|
||||
nt_symbol_table,
|
||||
module_names,
|
||||
"PAGE",
|
||||
)
|
||||
|
||||
if not (data_sec and mod_page):
|
||||
return None
|
||||
|
||||
mod_page_offset, mod_page_size = mod_page
|
||||
data_sec_offset, data_sec_size = data_sec
|
||||
|
||||
# iterate over ahcache kernel module's .data section in search of *two* SHIM handles
|
||||
shim_heads = []
|
||||
|
||||
vollog.debug(f"PAGE offset: {hex(mod_page_offset)}")
|
||||
vollog.debug(f".data offset: {hex(data_sec_offset)}")
|
||||
|
||||
handle_type = context.symbol_space.get_type(
|
||||
shimcache_symbol_table + constants.BANG + "SHIM_CACHE_HANDLE"
|
||||
)
|
||||
for offset in range(
|
||||
data_sec_offset,
|
||||
data_sec_offset + data_sec_size,
|
||||
8 if symbols.symbol_table_is_64bit(context, nt_symbol_table) else 4,
|
||||
):
|
||||
vollog.debug(f"Building shim handle pointer at {hex(offset)}")
|
||||
shim_handle = context.object(
|
||||
object_type=shimcache_symbol_table + constants.BANG + "pointer",
|
||||
layer_name=kernel_layer_name,
|
||||
subtype=handle_type,
|
||||
offset=offset,
|
||||
)
|
||||
|
||||
if shim_handle.is_valid(mod_page_offset, mod_page_offset + mod_page_size):
|
||||
if shim_handle.head is not None:
|
||||
vollog.debug(
|
||||
f"Found valid shim handle @ {hex(shim_handle.vol.offset)}"
|
||||
)
|
||||
shim_heads.append(shim_handle.head)
|
||||
if len(shim_heads) == 2:
|
||||
break
|
||||
|
||||
if len(shim_heads) != 2:
|
||||
vollog.debug("Failed to identify two valid SHIM_CACHE_HANDLE structures")
|
||||
return
|
||||
|
||||
# On Windows 8 x64, the frist cache contains the shim cache
|
||||
# On Windows 8 x86, 8.1 x86/x64, and 10, the second cache contains the shim cache.
|
||||
if (
|
||||
not symbols.symbol_table_is_64bit(context, nt_symbol_table)
|
||||
and not is_8_1_or_later
|
||||
):
|
||||
valid_head = shim_heads[1]
|
||||
elif not is_8_1_or_later:
|
||||
valid_head = shim_heads[0]
|
||||
else:
|
||||
valid_head = shim_heads[1]
|
||||
|
||||
for shim_entry in valid_head.ListEntry.to_list(
|
||||
shimcache_symbol_table + constants.BANG + "SHIM_CACHE_ENTRY", "ListEntry"
|
||||
):
|
||||
if shim_entry.is_valid():
|
||||
yield shim_entry
|
||||
|
||||
def _generator(self):
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
|
||||
shimcache_table_name = self.create_shimcache_table(
|
||||
self.context, kernel.symbol_table_name, self.config_path
|
||||
)
|
||||
|
||||
c = count()
|
||||
|
||||
if versions.is_windows_8_or_later(self._context, kernel.symbol_table_name):
|
||||
vollog.info("Finding shimcache entries for Windows 8.0+")
|
||||
entries = self.find_shimcache_win_8_or_later(
|
||||
self.context,
|
||||
self.config_path,
|
||||
kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
shimcache_table_name,
|
||||
)
|
||||
|
||||
elif (
|
||||
versions.is_2003(self.context, kernel.symbol_table_name)
|
||||
or versions.is_vista_or_later(self.context, kernel.symbol_table_name)
|
||||
or versions.is_windows_7(self.context, kernel.symbol_table_name)
|
||||
):
|
||||
vollog.info("Finding shimcache entries for Windows 2k3/Vista/7")
|
||||
entries = self.find_shimcache_win_2k3_to_7(
|
||||
self.context,
|
||||
self.config_path,
|
||||
kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
shimcache_table_name,
|
||||
)
|
||||
|
||||
elif versions.is_windows_xp_sp2(
|
||||
self._context, kernel.symbol_table_name
|
||||
) or versions.is_windows_xp_sp3(self.context, kernel.symbol_table_name):
|
||||
vollog.info("Finding shimcache entries for WinXP")
|
||||
entries = self.find_shimcache_win_xp(
|
||||
self._context,
|
||||
kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
shimcache_table_name,
|
||||
)
|
||||
else:
|
||||
vollog.warn("Cannot parse shimcache entries for this version of Windows")
|
||||
return
|
||||
|
||||
for entry in entries:
|
||||
try:
|
||||
vollog.debug(f"SHIM_CACHE_ENTRY type: {entry.__class__}")
|
||||
shim_entry = (
|
||||
entry.last_modified,
|
||||
entry.last_update,
|
||||
entry.exec_flag,
|
||||
(
|
||||
format_hints.Hex(entry.file_size)
|
||||
if isinstance(entry.file_size, int)
|
||||
else entry.file_size
|
||||
),
|
||||
entry.file_path,
|
||||
)
|
||||
except exceptions.InvalidAddressException:
|
||||
continue
|
||||
|
||||
yield (
|
||||
0,
|
||||
(next(c), *shim_entry),
|
||||
)
|
||||
|
||||
def run(self):
|
||||
return renderers.TreeGrid(
|
||||
[
|
||||
("Order", int),
|
||||
("Last Modified", datetime),
|
||||
("Last Update", datetime),
|
||||
("Exec Flag", bool),
|
||||
("File Size", format_hints.Hex),
|
||||
("File Path", str),
|
||||
],
|
||||
self._generator(),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_module_section_range(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
config_path: str,
|
||||
layer_name: str,
|
||||
symbol_table: str,
|
||||
module_list: List[str],
|
||||
section_name: str,
|
||||
) -> Optional[Tuple[int, int]]:
|
||||
"""Locates the size and offset of the first found module section
|
||||
specified by name from the list of modules.
|
||||
|
||||
:param context: The context to operate on
|
||||
:param layer_name: The memory layer to read from
|
||||
:param module_list: A list of module names to search for the given section
|
||||
:param section_name: The name of the section to search for.
|
||||
|
||||
:return: The offset and size of the module, if found; Otherwise, returns `None`
|
||||
"""
|
||||
|
||||
try:
|
||||
krnl_mod = next(
|
||||
module
|
||||
for module in modules.Modules.list_modules(
|
||||
context, layer_name, symbol_table
|
||||
)
|
||||
if module.BaseDllName.String in module_list
|
||||
)
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
pe_table_name = intermed.IntermediateSymbolTable.create(
|
||||
context,
|
||||
interfaces.configuration.path_join(config_path, "pe"),
|
||||
"windows",
|
||||
"pe",
|
||||
class_types=pe.class_types,
|
||||
)
|
||||
|
||||
# code taken from Win32KBase._section_chunks (win32_core.py)
|
||||
dos_header = context.object(
|
||||
pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER",
|
||||
layer_name,
|
||||
offset=krnl_mod.DllBase,
|
||||
)
|
||||
|
||||
if not dos_header:
|
||||
return None
|
||||
|
||||
nt_header = dos_header.get_nt_header()
|
||||
|
||||
try:
|
||||
section = next(
|
||||
sec
|
||||
for sec in nt_header.get_sections()
|
||||
if section_name.lower() == array_to_string(sec.Name).lower()
|
||||
)
|
||||
except StopIteration:
|
||||
return None
|
||||
|
||||
section_offset = krnl_mod.DllBase + section.VirtualAddress
|
||||
section_size = section.Misc.VirtualSize
|
||||
|
||||
return section_offset, section_size
|
||||
@@ -0,0 +1,103 @@
|
||||
# This file is Copyright 2024 Volatility Foundation and licensed under the Volatility Software License 1.0
|
||||
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
|
||||
#
|
||||
|
||||
# This module attempts to locate skeleton-key like function hooks.
|
||||
# It does this by locating the CSystems array through a variety of methods,
|
||||
# and then validating the entry for RC4 HMAC (0x17 / 23)
|
||||
#
|
||||
# For a thorough walkthrough on how the R&D was performed to develop this plugin,
|
||||
# please see our blogpost here:
|
||||
#
|
||||
# https://volatility-labs.blogspot.com/2021/10/memory-forensics-r-illustrated.html
|
||||
|
||||
import logging
|
||||
|
||||
from volatility3.framework import symbols, interfaces
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.plugins.windows import svclist, svcscan
|
||||
from volatility3.framework.symbols.windows import versions
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SvcDiff(svcscan.SvcScan):
|
||||
"""Compares services found through list walking versus scanning to find rootkits"""
|
||||
|
||||
_required_framework_version = (2, 4, 0)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._enumeration_method = self.service_diff
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
# 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.VersionRequirement(
|
||||
name="svclist", component=svclist.SvcList, version=(1, 0, 0)
|
||||
),
|
||||
requirements.VersionRequirement(
|
||||
name="svcscan", component=svcscan.SvcScan, version=(3, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def service_diff(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
layer_name: str,
|
||||
symbol_table: str,
|
||||
service_table_name: str,
|
||||
service_binary_dll_map,
|
||||
filter_func,
|
||||
):
|
||||
"""
|
||||
On Windows 10 version 15063+ 64bit Windows memory samples, walk the services list
|
||||
and scan for services then report differences
|
||||
"""
|
||||
if not symbols.symbol_table_is_64bit(
|
||||
context, symbol_table
|
||||
) or not versions.is_win10_15063_or_later(
|
||||
context=context, symbol_table=symbol_table
|
||||
):
|
||||
vollog.warning(
|
||||
"This plugin only supports Windows 10 version 15063+ 64bit Windows memory samples"
|
||||
)
|
||||
return
|
||||
|
||||
from_scan = set()
|
||||
from_list = set()
|
||||
records = {}
|
||||
|
||||
# collect unique service names from scanning
|
||||
for service in svcscan.SvcScan.service_scan(
|
||||
context,
|
||||
layer_name,
|
||||
symbol_table,
|
||||
service_table_name,
|
||||
service_binary_dll_map,
|
||||
filter_func,
|
||||
):
|
||||
from_scan.add(service[6])
|
||||
records[service[6]] = service
|
||||
|
||||
# collect services from listing walking
|
||||
for service in svclist.SvcList.service_list(
|
||||
context,
|
||||
layer_name,
|
||||
symbol_table,
|
||||
service_table_name,
|
||||
service_binary_dll_map,
|
||||
filter_func,
|
||||
):
|
||||
from_list.add(service[6])
|
||||
|
||||
# report services found from scanning but not list walking
|
||||
for hidden_service in from_scan - from_list:
|
||||
yield records[hidden_service]
|
||||
@@ -0,0 +1,115 @@
|
||||
# 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 logging
|
||||
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from volatility3.framework import interfaces, exceptions, symbols
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.symbols.windows import versions
|
||||
from volatility3.plugins.windows import svcscan, pslist
|
||||
from volatility3.framework.layers import scanners
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SvcList(svcscan.SvcScan):
|
||||
"""Lists services contained with the services.exe doubly linked list of services"""
|
||||
|
||||
_version = (1, 0, 0)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._enumeration_method = self.service_list
|
||||
|
||||
@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.PluginRequirement(
|
||||
name="svcscan", plugin=svcscan.SvcScan, version=(3, 0, 0)
|
||||
),
|
||||
requirements.ModuleRequirement(
|
||||
name="kernel",
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def _get_exe_range(cls, proc) -> Optional[Tuple[int, int]]:
|
||||
"""
|
||||
Returns a tuple of starting,ending address for
|
||||
the VAD containing services.exe
|
||||
"""
|
||||
|
||||
vad_root = proc.get_vad_root()
|
||||
for vad in vad_root.traverse():
|
||||
filename = vad.get_file_name()
|
||||
if isinstance(filename, str) and filename.lower().endswith(
|
||||
"\\services.exe"
|
||||
):
|
||||
return [(vad.get_start(), vad.get_size())]
|
||||
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def service_list(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
layer_name: str,
|
||||
symbol_table: str,
|
||||
service_table_name: str,
|
||||
service_binary_dll_map,
|
||||
filter_func,
|
||||
):
|
||||
if not symbols.symbol_table_is_64bit(
|
||||
context, symbol_table
|
||||
) or not versions.is_win10_15063_or_later(
|
||||
context=context, symbol_table=symbol_table
|
||||
):
|
||||
vollog.warning(
|
||||
"This plugin only supports Windows 10 version 15063+ 64bit Windows memory samples"
|
||||
)
|
||||
return
|
||||
|
||||
for proc in pslist.PsList.list_processes(
|
||||
context=context,
|
||||
layer_name=layer_name,
|
||||
symbol_table=symbol_table,
|
||||
filter_func=filter_func,
|
||||
):
|
||||
try:
|
||||
layer_name = proc.add_process_layer()
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.warning(
|
||||
"Unable to access memory of services.exe running with PID: {}".format(
|
||||
proc.UniqueProcessId
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
layer = context.layers[layer_name]
|
||||
|
||||
exe_range = cls._get_exe_range(proc)
|
||||
if not exe_range:
|
||||
vollog.warning(
|
||||
"Could not find the application executable VAD for services.exe. Unable to proceed."
|
||||
)
|
||||
continue
|
||||
|
||||
for offset in layer.scan(
|
||||
context=context,
|
||||
scanner=scanners.BytesScanner(needle=b"Sc27"),
|
||||
sections=exe_range,
|
||||
):
|
||||
for record in cls.enumerate_vista_or_later_header(
|
||||
context,
|
||||
service_table_name,
|
||||
service_binary_dll_map,
|
||||
layer_name,
|
||||
offset,
|
||||
):
|
||||
yield record
|
||||
@@ -19,7 +19,7 @@ from volatility3.framework.layers import scanners
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.symbols import intermed
|
||||
from volatility3.framework.symbols.windows import versions
|
||||
from volatility3.framework.symbols.windows.extensions import services
|
||||
from volatility3.framework.symbols.windows.extensions import services as services_types
|
||||
from volatility3.plugins.windows import poolscanner, pslist, vadyarascan
|
||||
from volatility3.plugins.windows.registry import hivelist
|
||||
|
||||
@@ -39,7 +39,11 @@ class SvcScan(interfaces.plugins.PluginInterface):
|
||||
"""Scans for windows services."""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
_version = (2, 0, 0)
|
||||
_version = (3, 0, 0)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._enumeration_method = self.service_scan
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
@@ -106,7 +110,7 @@ class SvcScan(interfaces.plugins.PluginInterface):
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def create_service_table(
|
||||
def _create_service_table(
|
||||
context: interfaces.context.ContextInterface,
|
||||
symbol_table: str,
|
||||
config_path: str,
|
||||
@@ -140,18 +144,21 @@ class SvcScan(interfaces.plugins.PluginInterface):
|
||||
config_path,
|
||||
os.path.join("windows", "services"),
|
||||
symbol_filename,
|
||||
class_types=services.class_types,
|
||||
class_types=services_types.class_types,
|
||||
native_types=native_types,
|
||||
)
|
||||
|
||||
def _get_service_key(self, kernel) -> Optional[objects.StructType]:
|
||||
@staticmethod
|
||||
def _get_service_key(
|
||||
context, config_path: str, layer_name: str, symbol_table: str
|
||||
) -> Optional[objects.StructType]:
|
||||
for hive in hivelist.HiveList.list_hives(
|
||||
context=self.context,
|
||||
context=context,
|
||||
base_config_path=interfaces.configuration.path_join(
|
||||
self.config_path, "hivelist"
|
||||
config_path, "hivelist"
|
||||
),
|
||||
layer_name=kernel.layer_name,
|
||||
symbol_table=kernel.symbol_table_name,
|
||||
layer_name=layer_name,
|
||||
symbol_table=symbol_table,
|
||||
filter_string="machine\\system",
|
||||
):
|
||||
# Get ControlSet\Services.
|
||||
@@ -232,30 +239,55 @@ class SvcScan(interfaces.plugins.PluginInterface):
|
||||
for service_key in services
|
||||
}
|
||||
|
||||
def _generator(self):
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
@classmethod
|
||||
def enumerate_vista_or_later_header(
|
||||
cls,
|
||||
context,
|
||||
service_table_name,
|
||||
service_binary_dll_map,
|
||||
proc_layer_name,
|
||||
offset,
|
||||
):
|
||||
if offset % 8:
|
||||
return
|
||||
|
||||
service_table_name = self.create_service_table(
|
||||
self.context, kernel.symbol_table_name, self.config_path
|
||||
service_header = context.object(
|
||||
service_table_name + constants.BANG + "_SERVICE_HEADER",
|
||||
offset=offset,
|
||||
layer_name=proc_layer_name,
|
||||
)
|
||||
|
||||
# Building the dictionary ahead of time is much better for performance
|
||||
# vs looking up each service's DLL individually.
|
||||
services_key = self._get_service_key(kernel)
|
||||
service_binary_dll_map = (
|
||||
self._get_service_binary_map(services_key)
|
||||
if services_key is not None
|
||||
else {}
|
||||
)
|
||||
if not service_header.is_valid():
|
||||
return
|
||||
|
||||
relative_tag_offset = self.context.symbol_space.get_type(
|
||||
# since we walk the s-list backwards, if we've seen
|
||||
# an object, then we've also seen all objects that
|
||||
# exist before it, thus we can break at that time.
|
||||
for service_record in service_header.ServiceRecord.traverse():
|
||||
service_info = service_binary_dll_map.get(
|
||||
service_record.get_name(),
|
||||
ServiceBinaryInfo(
|
||||
renderers.UnreadableValue(), renderers.UnreadableValue()
|
||||
),
|
||||
)
|
||||
yield cls.get_record_tuple(service_record, service_info)
|
||||
|
||||
@classmethod
|
||||
def service_scan(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
layer_name: str,
|
||||
symbol_table: str,
|
||||
service_table_name: str,
|
||||
service_binary_dll_map,
|
||||
filter_func,
|
||||
):
|
||||
relative_tag_offset = context.symbol_space.get_type(
|
||||
service_table_name + constants.BANG + "_SERVICE_RECORD"
|
||||
).relative_child_offset("Tag")
|
||||
|
||||
filter_func = pslist.PsList.create_name_filter(["services.exe"])
|
||||
|
||||
is_vista_or_later = versions.is_vista_or_later(
|
||||
context=self.context, symbol_table=kernel.symbol_table_name
|
||||
context=context, symbol_table=symbol_table
|
||||
)
|
||||
|
||||
if is_vista_or_later:
|
||||
@@ -266,9 +298,9 @@ class SvcScan(interfaces.plugins.PluginInterface):
|
||||
seen = []
|
||||
|
||||
for task in pslist.PsList.list_processes(
|
||||
context=self.context,
|
||||
layer_name=kernel.layer_name,
|
||||
symbol_table=kernel.symbol_table_name,
|
||||
context=context,
|
||||
layer_name=layer_name,
|
||||
symbol_table=symbol_table,
|
||||
filter_func=filter_func,
|
||||
):
|
||||
proc_id = "Unknown"
|
||||
@@ -283,15 +315,15 @@ class SvcScan(interfaces.plugins.PluginInterface):
|
||||
)
|
||||
continue
|
||||
|
||||
layer = self.context.layers[proc_layer_name]
|
||||
layer = context.layers[proc_layer_name]
|
||||
|
||||
for offset in layer.scan(
|
||||
context=self.context,
|
||||
context=context,
|
||||
scanner=scanners.BytesScanner(needle=service_tag),
|
||||
sections=vadyarascan.VadYaraScan.get_vad_maps(task),
|
||||
):
|
||||
if not is_vista_or_later:
|
||||
service_record = self.context.object(
|
||||
service_record = context.object(
|
||||
service_table_name + constants.BANG + "_SERVICE_RECORD",
|
||||
offset=offset - relative_tag_offset,
|
||||
layer_name=proc_layer_name,
|
||||
@@ -306,37 +338,60 @@ class SvcScan(interfaces.plugins.PluginInterface):
|
||||
renderers.UnreadableValue(), renderers.UnreadableValue()
|
||||
),
|
||||
)
|
||||
yield (
|
||||
0,
|
||||
self.get_record_tuple(service_record, service_info),
|
||||
)
|
||||
yield cls.get_record_tuple(service_record, service_info)
|
||||
else:
|
||||
service_header = self.context.object(
|
||||
service_table_name + constants.BANG + "_SERVICE_HEADER",
|
||||
offset=offset,
|
||||
layer_name=proc_layer_name,
|
||||
)
|
||||
|
||||
if not service_header.is_valid():
|
||||
continue
|
||||
|
||||
# since we walk the s-list backwards, if we've seen
|
||||
# an object, then we've also seen all objects that
|
||||
# exist before it, thus we can break at that time.
|
||||
for service_record in service_header.ServiceRecord.traverse():
|
||||
for service_record in cls.enumerate_vista_or_later_header(
|
||||
context,
|
||||
service_table_name,
|
||||
service_binary_dll_map,
|
||||
proc_layer_name,
|
||||
offset,
|
||||
):
|
||||
if service_record in seen:
|
||||
break
|
||||
seen.append(service_record)
|
||||
service_info = service_binary_dll_map.get(
|
||||
service_record.get_name(),
|
||||
ServiceBinaryInfo(
|
||||
renderers.UnreadableValue(), renderers.UnreadableValue()
|
||||
),
|
||||
)
|
||||
yield (
|
||||
0,
|
||||
self.get_record_tuple(service_record, service_info),
|
||||
)
|
||||
yield service_record
|
||||
|
||||
@classmethod
|
||||
def get_prereq_info(cls, context, config_path, layer_name: str, symbol_table: str):
|
||||
"""
|
||||
Data structures and information needed to analyze service information
|
||||
"""
|
||||
|
||||
service_table_name = cls._create_service_table(
|
||||
context, symbol_table, config_path
|
||||
)
|
||||
|
||||
services_key = cls._get_service_key(
|
||||
context, config_path, layer_name, symbol_table
|
||||
)
|
||||
|
||||
service_binary_dll_map = (
|
||||
cls._get_service_binary_map(services_key)
|
||||
if services_key is not None
|
||||
else {}
|
||||
)
|
||||
|
||||
filter_func = pslist.PsList.create_name_filter(["services.exe"])
|
||||
|
||||
return service_table_name, service_binary_dll_map, filter_func
|
||||
|
||||
def _generator(self):
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
|
||||
service_table_name, service_binary_dll_map, filter_func = self.get_prereq_info(
|
||||
self.context, self.config_path, kernel.layer_name, kernel.symbol_table_name
|
||||
)
|
||||
|
||||
for record in self._enumeration_method(
|
||||
self.context,
|
||||
kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
service_table_name,
|
||||
service_binary_dll_map,
|
||||
filter_func,
|
||||
):
|
||||
yield (0, record)
|
||||
|
||||
def run(self):
|
||||
return renderers.TreeGrid(
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
##
|
||||
import logging
|
||||
import datetime
|
||||
from typing import Iterable
|
||||
from typing import Callable, Iterable
|
||||
|
||||
from volatility3.framework import renderers, interfaces, exceptions
|
||||
from volatility3.framework.configuration import requirements
|
||||
@@ -19,7 +19,11 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface)
|
||||
|
||||
# version 2.6.0 adds support for scanning for 'Ethread' structures by pool tags
|
||||
_required_framework_version = (2, 6, 0)
|
||||
_version = (1, 0, 0)
|
||||
_version = (1, 1, 0)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.implementation = self.scan_threads
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls):
|
||||
@@ -38,8 +42,7 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface)
|
||||
def scan_threads(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
layer_name: str,
|
||||
symbol_table: str,
|
||||
module_name: str,
|
||||
) -> Iterable[interfaces.objects.ObjectInterface]:
|
||||
"""Scans for threads using the poolscanner module and constraints.
|
||||
|
||||
@@ -52,6 +55,10 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface)
|
||||
A list of _ETHREAD objects found by scanning memory for the "Thre" / "Thr\\xE5" pool signatures
|
||||
"""
|
||||
|
||||
module = context.modules[module_name]
|
||||
layer_name = module.layer_name
|
||||
symbol_table = module.symbol_table_name
|
||||
|
||||
constraints = poolscanner.PoolScanner.builtin_constraints(
|
||||
symbol_table, [b"Thr\xe5", b"Thre"]
|
||||
)
|
||||
@@ -76,7 +83,7 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface)
|
||||
ethread.get_exit_time()
|
||||
) # datetime.datetime object / volatility3.framework.renderers.UnparsableValue object
|
||||
except exceptions.InvalidAddressException:
|
||||
vollog.debug("Thread invalid address {:#x}".format(thread.vol.offset))
|
||||
vollog.debug("Thread invalid address {:#x}".format(ethread.vol.offset))
|
||||
return None
|
||||
|
||||
return (
|
||||
@@ -88,18 +95,19 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface)
|
||||
thread_exit_time,
|
||||
)
|
||||
|
||||
def _generator(self):
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
def _generator(self, filter_func: Callable):
|
||||
kernel_name = self.config["kernel"]
|
||||
|
||||
for ethread in self.scan_threads(
|
||||
self.context, kernel.layer_name, kernel.symbol_table_name
|
||||
):
|
||||
for ethread in self.implementation(self.context, kernel_name):
|
||||
info = self.gather_thread_info(ethread)
|
||||
|
||||
if info:
|
||||
yield (0, info)
|
||||
|
||||
def generate_timeline(self):
|
||||
for row in self._generator():
|
||||
filt_func = self.filter_func(self.config)
|
||||
|
||||
for row in self._generator(filt_func):
|
||||
_depth, row_data = row
|
||||
row_dict = {}
|
||||
(
|
||||
@@ -126,7 +134,14 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface)
|
||||
row_dict["ExitTime"],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def filter_func(cls, config: interfaces.configuration.HierarchicalDict) -> Callable:
|
||||
"""Returns a function that can filter this plugin's implementation method based on the config"""
|
||||
return lambda x: False
|
||||
|
||||
def run(self):
|
||||
filt_func = self.filter_func(self.config)
|
||||
|
||||
return renderers.TreeGrid(
|
||||
[
|
||||
("Offset", format_hints.Hex),
|
||||
@@ -136,5 +151,5 @@ class ThrdScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface)
|
||||
("CreateTime", datetime.datetime),
|
||||
("ExitTime", datetime.datetime),
|
||||
],
|
||||
self._generator(),
|
||||
self._generator(filt_func),
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#
|
||||
|
||||
import logging
|
||||
from typing import List, Generator
|
||||
from typing import Callable, Iterable, List, Generator
|
||||
|
||||
from volatility3.framework import interfaces, constants
|
||||
from volatility3.framework.configuration import requirements
|
||||
@@ -18,6 +18,10 @@ class Threads(thrdscan.ThrdScan):
|
||||
_required_framework_version = (2, 4, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.implementation = self.list_process_threads
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
# Since we're calling the plugin, make sure we have the plugin's requirements
|
||||
@@ -34,7 +38,7 @@ class Threads(thrdscan.ThrdScan):
|
||||
optional=True,
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="thrdscan", plugin=thrdscan.ThrdScan, version=(1, 0, 0)
|
||||
name="thrdscan", plugin=thrdscan.ThrdScan, version=(1, 1, 0)
|
||||
),
|
||||
]
|
||||
|
||||
@@ -60,18 +64,27 @@ class Threads(thrdscan.ThrdScan):
|
||||
seen.add(thread.vol.offset)
|
||||
yield thread
|
||||
|
||||
def _generator(self):
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
@classmethod
|
||||
def filter_func(cls, config: interfaces.configuration.HierarchicalDict) -> Callable:
|
||||
return pslist.PsList.create_pid_filter(config.get("pid", None))
|
||||
|
||||
filter_func = pslist.PsList.create_pid_filter(self.config.get("pid", None))
|
||||
@classmethod
|
||||
def list_process_threads(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
module_name: str,
|
||||
filter_func: Callable,
|
||||
) -> Iterable[interfaces.objects.ObjectInterface]:
|
||||
"""Runs through all processes and lists threads for each process"""
|
||||
module = context.modules[module_name]
|
||||
layer_name = module.layer_name
|
||||
symbol_table_name = module.symbol_table_name
|
||||
|
||||
for proc in pslist.PsList.list_processes(
|
||||
context=self.context,
|
||||
layer_name=kernel.layer_name,
|
||||
symbol_table=kernel.symbol_table_name,
|
||||
context=context,
|
||||
layer_name=layer_name,
|
||||
symbol_table=symbol_table_name,
|
||||
filter_func=filter_func,
|
||||
):
|
||||
for thread in self.list_threads(kernel, proc):
|
||||
info = self.gather_thread_info(thread)
|
||||
if info:
|
||||
yield (0, info)
|
||||
for thread in cls.list_threads(module, proc):
|
||||
yield thread
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
# This file is Copyright 2024 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
|
||||
|
||||
from typing import Iterator, List, Tuple, Iterable
|
||||
|
||||
from volatility3.framework import (
|
||||
renderers,
|
||||
interfaces,
|
||||
constants,
|
||||
symbols,
|
||||
)
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.renderers import format_hints
|
||||
from volatility3.framework.symbols.windows import versions
|
||||
from volatility3.plugins.windows import ssdt, kpcrs
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Timers(interfaces.plugins.PluginInterface):
|
||||
"""Print kernel timers and associated module DPCs"""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
_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.PluginRequirement(
|
||||
name="ssdt", plugin=ssdt.SSDT, version=(1, 0, 0)
|
||||
),
|
||||
requirements.PluginRequirement(
|
||||
name="kpcrs", plugin=kpcrs.KPCRs, version=(1, 0, 0)
|
||||
),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def list_timers(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
kernel_module_name: str,
|
||||
layer_name: str,
|
||||
symbol_table: str,
|
||||
) -> Iterable[Tuple[str, int, str]]:
|
||||
"""Lists all kernel timers.
|
||||
|
||||
Args:
|
||||
context: The context to retrieve required elements (layers, symbol tables) from
|
||||
kernel_module_name: The name of the kernel module on which to operate
|
||||
layer_name: The name of the layer on which to operate
|
||||
symbol_table: The name of the table containing the kernel symbols
|
||||
|
||||
Yields:
|
||||
A _KTIMER entry
|
||||
"""
|
||||
|
||||
kernel = context.modules[kernel_module_name]
|
||||
if versions.is_windows_7(
|
||||
context=context, symbol_table=symbol_table
|
||||
) or versions.is_windows_8_or_later(context=context, symbol_table=symbol_table):
|
||||
# Starting with Windows 7, there is no more KiTimerTableListHead. The list is
|
||||
# at _KPCR.PrcbData.TimerTable.TimerEntries
|
||||
# See http://pastebin.com/FiRsGW3f
|
||||
for kpcr in kpcrs.KPCRs.list_kpcrs(
|
||||
context, kernel_module_name, layer_name, symbol_table
|
||||
):
|
||||
if hasattr(kpcr.Prcb.TimerTable, "TableState"):
|
||||
for timer_entries in kpcr.Prcb.TimerTable.TimerEntries:
|
||||
for timer_entry in timer_entries:
|
||||
for timer in timer_entry.Entry.to_list(
|
||||
symbol_table + constants.BANG + "_KTIMER",
|
||||
"TimerListEntry",
|
||||
):
|
||||
yield timer
|
||||
|
||||
else:
|
||||
for timer_entries in kpcr.Prcb.TimerTable.TimerEntries:
|
||||
for timer in timer_entries.Entry.to_list(
|
||||
symbol_table + constants.BANG + "_KTIMER",
|
||||
"TimerListEntry",
|
||||
):
|
||||
yield timer
|
||||
|
||||
elif versions.is_xp_or_2003(
|
||||
context=context, symbol_table=symbol_table
|
||||
) or versions.is_vista_or_later(context=context, symbol_table=symbol_table):
|
||||
is_64bit = symbols.symbol_table_is_64bit(context, symbol_table)
|
||||
if is_64bit or versions.is_vista_or_later(
|
||||
context=context, symbol_table=symbol_table
|
||||
):
|
||||
# On XP x64, Windows 2003 SP1-SP2, and Vista SP0-SP2, KiTimerTableListHead
|
||||
# is an array of 512 _KTIMER_TABLE_ENTRY structs.
|
||||
array_size = 512
|
||||
else:
|
||||
# On XP SP0-SP3 x86 and Windows 2003 SP0, KiTimerTableListHead
|
||||
# is an array of 256 _LIST_ENTRY for _KTIMERs.
|
||||
array_size = 256
|
||||
|
||||
timer_table_list_head = kernel.object(
|
||||
object_type="array",
|
||||
offset=kernel.get_symbol("KiTimerTableListHead").address,
|
||||
subtype=kernel.get_type("_LIST_ENTRY"),
|
||||
count=array_size,
|
||||
)
|
||||
for table in timer_table_list_head:
|
||||
for timer in table.to_list(
|
||||
symbol_table + constants.BANG + "_KTIMER",
|
||||
"TimerListEntry",
|
||||
):
|
||||
yield timer
|
||||
|
||||
else:
|
||||
raise NotImplementedError("This version of Windows is not supported!")
|
||||
|
||||
def _generator(self) -> Iterator[Tuple]:
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
layer_name = kernel.layer_name
|
||||
symbol_table = kernel.symbol_table_name
|
||||
|
||||
collection = ssdt.SSDT.build_module_collection(
|
||||
self.context, kernel.layer_name, kernel.symbol_table_name
|
||||
)
|
||||
|
||||
for timer in self.list_timers(
|
||||
self.context, self.config["kernel"], layer_name, symbol_table
|
||||
):
|
||||
if not timer.valid_type():
|
||||
continue
|
||||
try:
|
||||
dpc = timer.get_dpc()
|
||||
if dpc == 0:
|
||||
continue
|
||||
if dpc.DeferredRoutine == 0:
|
||||
continue
|
||||
deferred_routine = dpc.DeferredRoutine
|
||||
except Exception as e:
|
||||
continue
|
||||
|
||||
module_symbols = list(
|
||||
collection.get_module_symbols_by_absolute_location(deferred_routine)
|
||||
)
|
||||
|
||||
if module_symbols:
|
||||
for module_name, symbol_generator in module_symbols:
|
||||
symbols_found = False
|
||||
|
||||
# we might have multiple symbols pointing to the same location
|
||||
for symbol in symbol_generator:
|
||||
symbols_found = True
|
||||
yield (
|
||||
0,
|
||||
(
|
||||
format_hints.Hex(timer.vol.offset),
|
||||
timer.get_due_time(),
|
||||
timer.Period,
|
||||
timer.get_signaled(),
|
||||
format_hints.Hex(deferred_routine),
|
||||
module_name,
|
||||
symbol.split(constants.BANG)[1],
|
||||
),
|
||||
)
|
||||
|
||||
# no symbols, but we at least can report the module name
|
||||
if not symbols_found:
|
||||
yield (
|
||||
0,
|
||||
(
|
||||
format_hints.Hex(timer.vol.offset),
|
||||
timer.get_due_time(),
|
||||
timer.Period,
|
||||
timer.get_signaled(),
|
||||
format_hints.Hex(deferred_routine),
|
||||
module_name,
|
||||
renderers.NotAvailableValue(),
|
||||
),
|
||||
)
|
||||
else:
|
||||
# no module was found at the absolute location
|
||||
yield (
|
||||
0,
|
||||
(
|
||||
format_hints.Hex(timer.vol.offset),
|
||||
timer.get_due_time(),
|
||||
timer.Period,
|
||||
timer.get_signaled(),
|
||||
format_hints.Hex(deferred_routine),
|
||||
renderers.NotAvailableValue(),
|
||||
renderers.NotAvailableValue(),
|
||||
),
|
||||
)
|
||||
|
||||
def run(self):
|
||||
return renderers.TreeGrid(
|
||||
[
|
||||
("Offset", format_hints.Hex),
|
||||
("DueTime", str),
|
||||
("Period(ms)", int),
|
||||
("Signaled", str),
|
||||
("Routine", format_hints.Hex),
|
||||
("Module", str),
|
||||
("Symbol", str),
|
||||
],
|
||||
self._generator(),
|
||||
)
|
||||
@@ -0,0 +1,160 @@
|
||||
# This file is Copyright 2024 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 datetime
|
||||
from typing import List, Iterable
|
||||
|
||||
from volatility3.framework import constants
|
||||
from volatility3.framework import interfaces, symbols
|
||||
from volatility3.framework import renderers
|
||||
from volatility3.framework.configuration import requirements
|
||||
from volatility3.framework.interfaces import configuration
|
||||
from volatility3.framework.renderers import format_hints, conversion
|
||||
from volatility3.framework.symbols import intermed
|
||||
from volatility3.plugins import timeliner
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UnloadedModules(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
|
||||
"""Lists the unloaded kernel modules."""
|
||||
|
||||
_required_framework_version = (2, 0, 0)
|
||||
_version = (1, 0, 0)
|
||||
|
||||
@classmethod
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [
|
||||
requirements.ModuleRequirement(
|
||||
name="kernel",
|
||||
description="Windows kernel",
|
||||
architectures=["Intel32", "Intel64"],
|
||||
),
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def create_unloadedmodules_table(
|
||||
context: interfaces.context.ContextInterface,
|
||||
symbol_table: str,
|
||||
config_path: str,
|
||||
) -> str:
|
||||
"""Creates a symbol table for the unloaded modules.
|
||||
|
||||
Args:
|
||||
context: The context to retrieve required elements (layers, symbol tables) from
|
||||
symbol_table: The name of an existing symbol table containing the kernel symbols
|
||||
config_path: The configuration path within the context of the symbol table to create
|
||||
|
||||
Returns:
|
||||
The name of the constructed unloaded modules table
|
||||
"""
|
||||
native_types = context.symbol_space[symbol_table].natives
|
||||
is_64bit = symbols.symbol_table_is_64bit(context, symbol_table)
|
||||
table_mapping = {"nt_symbols": symbol_table}
|
||||
|
||||
if is_64bit:
|
||||
symbol_filename = "unloadedmodules-x64"
|
||||
else:
|
||||
symbol_filename = "unloadedmodules-x86"
|
||||
|
||||
return intermed.IntermediateSymbolTable.create(
|
||||
context,
|
||||
configuration.path_join(config_path, "unloadedmodules"),
|
||||
"windows",
|
||||
symbol_filename,
|
||||
native_types=native_types,
|
||||
table_mapping=table_mapping,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def list_unloadedmodules(
|
||||
cls,
|
||||
context: interfaces.context.ContextInterface,
|
||||
layer_name: str,
|
||||
symbol_table: str,
|
||||
unloadedmodule_table_name: str,
|
||||
) -> Iterable[interfaces.objects.ObjectInterface]:
|
||||
"""Lists all the unloaded modules in the primary layer.
|
||||
|
||||
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
|
||||
|
||||
Returns:
|
||||
A list of Unloaded Modules as retrieved from MmUnloadedDrivers
|
||||
"""
|
||||
|
||||
kvo = context.layers[layer_name].config["kernel_virtual_offset"]
|
||||
ntkrnlmp = context.module(symbol_table, layer_name=layer_name, offset=kvo)
|
||||
unloadedmodules_offset = ntkrnlmp.get_symbol("MmUnloadedDrivers").address
|
||||
unloadedmodules = ntkrnlmp.object(
|
||||
object_type="pointer",
|
||||
offset=unloadedmodules_offset,
|
||||
subtype="array",
|
||||
)
|
||||
is_64bit = symbols.symbol_table_is_64bit(context, symbol_table)
|
||||
|
||||
if is_64bit:
|
||||
unloaded_count_type = "unsigned long long"
|
||||
else:
|
||||
unloaded_count_type = "unsigned long"
|
||||
|
||||
last_unloadedmodule_offset = ntkrnlmp.get_symbol("MmLastUnloadedDriver").address
|
||||
unloaded_count = ntkrnlmp.object(
|
||||
object_type=unloaded_count_type, offset=last_unloadedmodule_offset
|
||||
)
|
||||
|
||||
unloadedmodules_array = context.object(
|
||||
object_type=unloadedmodule_table_name
|
||||
+ constants.BANG
|
||||
+ "_UNLOADED_DRIVERS",
|
||||
layer_name=layer_name,
|
||||
offset=unloadedmodules,
|
||||
)
|
||||
unloadedmodules_array.UnloadedDrivers.count = unloaded_count
|
||||
|
||||
for mod in unloadedmodules_array.UnloadedDrivers:
|
||||
yield mod
|
||||
|
||||
def _generator(self):
|
||||
kernel = self.context.modules[self.config["kernel"]]
|
||||
|
||||
unloadedmodule_table_name = self.create_unloadedmodules_table(
|
||||
self.context, kernel.symbol_table_name, self.config_path
|
||||
)
|
||||
|
||||
for mod in self.list_unloadedmodules(
|
||||
self.context,
|
||||
kernel.layer_name,
|
||||
kernel.symbol_table_name,
|
||||
unloadedmodule_table_name,
|
||||
):
|
||||
yield (
|
||||
0,
|
||||
(
|
||||
mod.Name.String,
|
||||
format_hints.Hex(mod.StartAddress),
|
||||
format_hints.Hex(mod.EndAddress),
|
||||
conversion.wintime_to_datetime(mod.CurrentTime),
|
||||
),
|
||||
)
|
||||
|
||||
def generate_timeline(self):
|
||||
for row in self._generator():
|
||||
_depth, row_data = row
|
||||
description = f"Unloaded Module: {row_data[0]}"
|
||||
yield (description, timeliner.TimeLinerType.CHANGED, row_data[3])
|
||||
|
||||
def run(self):
|
||||
return renderers.TreeGrid(
|
||||
[
|
||||
("Name", str),
|
||||
("StartAddress", format_hints.Hex),
|
||||
("EndAddress", format_hints.Hex),
|
||||
("Time", datetime.datetime),
|
||||
],
|
||||
self._generator(),
|
||||
)
|
||||
@@ -56,7 +56,7 @@ class VadYaraScan(interfaces.plugins.PluginInterface):
|
||||
|
||||
filter_func = pslist.PsList.create_pid_filter(self.config.get("pid", None))
|
||||
|
||||
sanity_check = 0x1000 * 0x1000 * 0x1000
|
||||
sanity_check = 1024 * 1024 * 1024 # 1 GB
|
||||
|
||||
for task in pslist.PsList.list_processes(
|
||||
context=self.context,
|
||||
@@ -66,15 +66,14 @@ class VadYaraScan(interfaces.plugins.PluginInterface):
|
||||
):
|
||||
layer_name = task.add_process_layer()
|
||||
layer = self.context.layers[layer_name]
|
||||
for start, end in self.get_vad_maps(task):
|
||||
size = end - start
|
||||
for start, size in self.get_vad_maps(task):
|
||||
if size > sanity_check:
|
||||
vollog.warn(
|
||||
f"VAD at 0x{start:x} over sanity-check size, not scanning"
|
||||
)
|
||||
continue
|
||||
|
||||
for match in rules.match(data=layer.read(start, end - start, True)):
|
||||
for match in rules.match(data=layer.read(start, size, True)):
|
||||
if yarascan.YaraScan.yara_returns_instances():
|
||||
for match_string in match.strings:
|
||||
for instance in match_string.instances:
|
||||
@@ -106,7 +105,7 @@ class VadYaraScan(interfaces.plugins.PluginInterface):
|
||||
task: The EPROCESS object of which to traverse the vad tree
|
||||
|
||||
Returns:
|
||||
An iterable of tuples containing start and end addresses for each descriptor
|
||||
An iterable of tuples containing start and size for each descriptor
|
||||
"""
|
||||
vad_root = task.get_vad_root()
|
||||
for vad in vad_root.traverse():
|
||||
|
||||
@@ -19,9 +19,11 @@ def wintime_to_datetime(
|
||||
return renderers.NotApplicableValue()
|
||||
unix_time = unix_time - 11644473600
|
||||
try:
|
||||
return datetime.datetime.utcfromtimestamp(unix_time)
|
||||
# Windows sometimes throws OSErrors rather than ValueErrors when it can't convert a value
|
||||
except (ValueError, OSError):
|
||||
return datetime.datetime.fromtimestamp(unix_time, datetime.timezone.utc)
|
||||
# Windows sometimes throws OSErrors rather than ValueError/OverflowError when it can't convert a value
|
||||
# Since Python 3.3, this should raise OverflowError instead of ValueError. However, it was observed
|
||||
# that even in Python 3.7.17, ValueError is still being raised.
|
||||
except (ValueError, OverflowError, OSError):
|
||||
return renderers.UnparsableValue()
|
||||
|
||||
|
||||
@@ -33,8 +35,10 @@ def unixtime_to_datetime(
|
||||
)
|
||||
|
||||
if unixtime > 0:
|
||||
with contextlib.suppress(ValueError):
|
||||
ret = datetime.datetime.utcfromtimestamp(unixtime)
|
||||
# Since Python 3.3, this should raise OverflowError instead of ValueError. However, it was observed
|
||||
# that even in Python 3.7.17, ValueError is still being raised. OSError is also raised on Linux
|
||||
with contextlib.suppress(ValueError, OverflowError, OSError):
|
||||
ret = datetime.datetime.fromtimestamp(unixtime, datetime.timezone.utc)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ Text renderers should attempt to honour all hints provided in this module where
|
||||
"""
|
||||
from typing import Type, Union
|
||||
|
||||
from volatility3.framework import interfaces
|
||||
|
||||
|
||||
class Bin(int):
|
||||
"""A class to indicate that the integer value should be represented as a
|
||||
@@ -66,3 +68,17 @@ class MultiTypeData(bytes):
|
||||
and self.split_nulls == other.split_nulls
|
||||
and self.show_hex == other.show_hex
|
||||
)
|
||||
|
||||
|
||||
BinOrAbsent = lambda x: (
|
||||
Bin(x) if not isinstance(x, interfaces.renderers.BaseAbsentValue) else x
|
||||
)
|
||||
HexOrAbsent = lambda x: (
|
||||
Hex(x) if not isinstance(x, interfaces.renderers.BaseAbsentValue) else x
|
||||
)
|
||||
HexBytesOrAbsent = lambda x: (
|
||||
HexBytes(x) if not isinstance(x, interfaces.renderers.BaseAbsentValue) else x
|
||||
)
|
||||
MultiTypeDataOrAbsent = lambda x: (
|
||||
MultiTypeData(x) if not isinstance(x, interfaces.renderers.BaseAbsentValue) else x
|
||||
)
|
||||
|
||||
@@ -29,12 +29,18 @@ class LinuxKernelIntermedSymbols(intermed.IntermediateSymbolTable):
|
||||
self.set_type_class("files_struct", extensions.files_struct)
|
||||
self.set_type_class("kobject", extensions.kobject)
|
||||
self.set_type_class("cred", extensions.cred)
|
||||
self.set_type_class("inode", extensions.inode)
|
||||
# Might not exist in the current symbols
|
||||
self.optional_set_type_class("module", extensions.module)
|
||||
self.optional_set_type_class("bpf_prog", extensions.bpf_prog)
|
||||
self.optional_set_type_class("kernel_cap_struct", extensions.kernel_cap_struct)
|
||||
self.optional_set_type_class("kernel_cap_t", extensions.kernel_cap_t)
|
||||
|
||||
# kernels >= 4.18
|
||||
self.optional_set_type_class("timespec64", extensions.timespec64)
|
||||
# kernels < 4.18. Reuses timespec64 obj extension, since both has the same members
|
||||
self.optional_set_type_class("timespec", extensions.timespec64)
|
||||
|
||||
# Mount
|
||||
self.set_type_class("vfsmount", extensions.vfsmount)
|
||||
# Might not exist in older kernels or the current symbols
|
||||
|
||||
@@ -4,10 +4,13 @@
|
||||
|
||||
import collections.abc
|
||||
import logging
|
||||
import stat
|
||||
from datetime import datetime
|
||||
import socket as socket_module
|
||||
from typing import Generator, Iterable, Iterator, Optional, Tuple, List
|
||||
from typing import Generator, Iterable, Iterator, Optional, Tuple, List, Union
|
||||
|
||||
from volatility3.framework import constants, exceptions, objects, interfaces, symbols
|
||||
from volatility3.framework.renderers import conversion
|
||||
from volatility3.framework.constants.linux import SOCK_TYPES, SOCK_FAMILY
|
||||
from volatility3.framework.constants.linux import IP_PROTOCOLS, IPV6_PROTOCOLS
|
||||
from volatility3.framework.constants.linux import TCP_STATES, NETLINK_PROTOCOLS
|
||||
@@ -1761,3 +1764,136 @@ class kernel_cap_t(kernel_cap_struct):
|
||||
)
|
||||
|
||||
return cap_value & self.get_kernel_cap_full()
|
||||
|
||||
|
||||
class timespec64(objects.StructType):
|
||||
def to_datetime(self) -> datetime:
|
||||
"""Returns the respective aware datetime"""
|
||||
|
||||
dt = conversion.unixtime_to_datetime(self.tv_sec + self.tv_nsec / 1e9)
|
||||
return dt
|
||||
|
||||
|
||||
class inode(objects.StructType):
|
||||
def is_valid(self) -> bool:
|
||||
# i_count is a 'signed' counter (atomic_t). Smear, or essentially a wrong inode
|
||||
# pointer, will easily cause an integer overflow here.
|
||||
return self.i_ino > 0 and self.i_count.counter >= 0
|
||||
|
||||
@property
|
||||
def is_dir(self) -> bool:
|
||||
"""Returns True if the inode is a directory"""
|
||||
return stat.S_ISDIR(self.i_mode) != 0
|
||||
|
||||
@property
|
||||
def is_reg(self) -> bool:
|
||||
"""Returns True if the inode is a regular file"""
|
||||
return stat.S_ISREG(self.i_mode) != 0
|
||||
|
||||
@property
|
||||
def is_link(self) -> bool:
|
||||
"""Returns True if the inode is a symlink"""
|
||||
return stat.S_ISLNK(self.i_mode) != 0
|
||||
|
||||
@property
|
||||
def is_fifo(self) -> bool:
|
||||
"""Returns True if the inode is a FIFO"""
|
||||
return stat.S_ISFIFO(self.i_mode) != 0
|
||||
|
||||
@property
|
||||
def is_sock(self) -> bool:
|
||||
"""Returns True if the inode is a socket"""
|
||||
return stat.S_ISSOCK(self.i_mode) != 0
|
||||
|
||||
@property
|
||||
def is_block(self) -> bool:
|
||||
"""Returns True if the inode is a block device"""
|
||||
return stat.S_ISBLK(self.i_mode) != 0
|
||||
|
||||
@property
|
||||
def is_char(self) -> bool:
|
||||
"""Returns True if the inode is a char device"""
|
||||
return stat.S_ISCHR(self.i_mode) != 0
|
||||
|
||||
@property
|
||||
def is_sticky(self) -> bool:
|
||||
"""Returns True if the sticky bit is set"""
|
||||
return (self.i_mode & stat.S_ISVTX) != 0
|
||||
|
||||
def get_inode_type(self) -> Union[str, None]:
|
||||
"""Returns inode type name
|
||||
|
||||
Returns:
|
||||
The inode type name
|
||||
"""
|
||||
if self.is_dir:
|
||||
return "DIR"
|
||||
elif self.is_reg:
|
||||
return "REG"
|
||||
elif self.is_link:
|
||||
return "LNK"
|
||||
elif self.is_fifo:
|
||||
return "FIFO"
|
||||
elif self.is_sock:
|
||||
return "SOCK"
|
||||
elif self.is_char:
|
||||
return "CHR"
|
||||
elif self.is_block:
|
||||
return "BLK"
|
||||
else:
|
||||
return None
|
||||
|
||||
def _time_member_to_datetime(self, member) -> datetime:
|
||||
if self.has_member(f"{member}_sec") and self.has_member(f"{member}_nsec"):
|
||||
# kernels >= 6.11 it's i_*_sec -> time64_t and i_*_nsec -> u32
|
||||
# Ref Linux commit 3aa63a569c64e708df547a8913c84e64a06e7853
|
||||
return conversion.unixtime_to_datetime(
|
||||
self.member(f"{member}_sec") + self.has_member(f"{member}_nsec") / 1e9
|
||||
)
|
||||
elif self.has_member(f"__{member}"):
|
||||
# 6.6 <= kernels < 6.11 it's a timespec64
|
||||
# Ref Linux commit 13bc24457850583a2e7203ded05b7209ab4bc5ef / 12cd44023651666bd44baa36a5c999698890debb
|
||||
return self.member(f"__{member}").to_datetime()
|
||||
elif self.has_member(member):
|
||||
# In kernels < 6.6 it's a timespec64 or timespec
|
||||
return self.member(member).to_datetime()
|
||||
else:
|
||||
raise exceptions.VolatilityException(
|
||||
"Unsupported kernel inode type implementation"
|
||||
)
|
||||
|
||||
def get_access_time(self) -> datetime:
|
||||
"""Returns the inode's last access time
|
||||
This is updated when inode contents are read
|
||||
|
||||
Returns:
|
||||
A datetime with the inode's last access time
|
||||
"""
|
||||
return self._time_member_to_datetime("i_atime")
|
||||
|
||||
def get_modification_time(self) -> datetime:
|
||||
"""Returns the inode's last modification time
|
||||
This is updated when the inode contents change
|
||||
|
||||
Returns:
|
||||
A datetime with the inode's last data modification time
|
||||
"""
|
||||
|
||||
return self._time_member_to_datetime("i_mtime")
|
||||
|
||||
def get_change_time(self) -> datetime:
|
||||
"""Returns the inode's last change time
|
||||
This is updated when the inode metadata changes
|
||||
|
||||
Returns:
|
||||
A datetime with the inode's last change time
|
||||
"""
|
||||
return self._time_member_to_datetime("i_ctime")
|
||||
|
||||
def get_file_mode(self) -> str:
|
||||
"""Returns the inode's file mode as string of the form '-rwxrwxrwx'.
|
||||
|
||||
Returns:
|
||||
The inode's file mode string
|
||||
"""
|
||||
return stat.filemode(self.i_mode)
|
||||
|
||||
@@ -17,6 +17,7 @@ class WindowsKernelIntermedSymbols(intermed.IntermediateSymbolTable):
|
||||
self.set_type_class("_KTHREAD", extensions.KTHREAD)
|
||||
self.set_type_class("_LIST_ENTRY", extensions.LIST_ENTRY)
|
||||
self.set_type_class("_EPROCESS", extensions.EPROCESS)
|
||||
self.set_type_class("_ERESOURCE", extensions.ERESOURCE)
|
||||
self.set_type_class("_UNICODE_STRING", extensions.UNICODE_STRING)
|
||||
self.set_type_class("_EX_FAST_REF", extensions.EX_FAST_REF)
|
||||
self.set_type_class("_TOKEN", extensions.TOKEN)
|
||||
@@ -39,6 +40,7 @@ class WindowsKernelIntermedSymbols(intermed.IntermediateSymbolTable):
|
||||
self.set_type_class("_VACB", extensions.VACB)
|
||||
self.set_type_class("_POOL_TRACKER_BIG_PAGES", pool.POOL_TRACKER_BIG_PAGES)
|
||||
self.set_type_class("_IMAGE_DOS_HEADER", pe.IMAGE_DOS_HEADER)
|
||||
self.set_type_class("_KTIMER", extensions.KTIMER)
|
||||
|
||||
# Might not necessarily defined in every version of windows
|
||||
self.optional_set_type_class("_IMAGE_NT_HEADERS", pe.IMAGE_NT_HEADERS)
|
||||
|
||||
@@ -105,8 +105,11 @@
|
||||
},
|
||||
"NotificationRoutine": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 24
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ from volatility3.framework import (
|
||||
)
|
||||
from volatility3.framework.interfaces.objects import ObjectInterface
|
||||
from volatility3.framework.layers import intel
|
||||
from volatility3.framework.objects import utility
|
||||
from volatility3.framework.renderers import conversion
|
||||
from volatility3.framework.symbols import generic
|
||||
from volatility3.framework.symbols.windows.extensions import pool
|
||||
@@ -306,16 +307,19 @@ class MMVAD_SHORT(objects.StructType):
|
||||
|
||||
raise AttributeError("Unable to find the private memory member")
|
||||
|
||||
@property
|
||||
def Protection(self):
|
||||
if self.has_member("u"):
|
||||
return self.u.VadFlags.Protection
|
||||
elif self.has_member("Core"):
|
||||
return self.Core.u.VadFlags.Protection
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_protection(self, protect_values, winnt_protections):
|
||||
"""Get the VAD's protection constants as a string."""
|
||||
|
||||
protect = None
|
||||
|
||||
if self.has_member("u"):
|
||||
protect = self.u.VadFlags.Protection
|
||||
|
||||
elif self.has_member("Core"):
|
||||
protect = self.Core.u.VadFlags.Protection
|
||||
protect = self.Protection
|
||||
|
||||
try:
|
||||
value = protect_values[protect]
|
||||
@@ -593,6 +597,38 @@ class UNICODE_STRING(objects.StructType):
|
||||
String = property(get_string)
|
||||
|
||||
|
||||
class ERESOURCE(objects.StructType):
|
||||
def is_valid(self) -> bool:
|
||||
vollog.debug(f"Checking ERESOURCE Validity: {hex(self.vol.offset)}")
|
||||
|
||||
if not self._context.layers[self.vol.layer_name].is_valid(self.vol.offset):
|
||||
return False
|
||||
|
||||
sym_table = self.get_symbol_table_name()
|
||||
|
||||
waiters_valid = self.SharedWaiters == 0 or self._context.layers[
|
||||
self.vol.layer_name
|
||||
].is_valid(
|
||||
self.SharedWaiters.vol.offset,
|
||||
self._context.symbol_space.get_type(
|
||||
sym_table + constants.BANG + "_KSEMAPHORE"
|
||||
).size,
|
||||
)
|
||||
|
||||
try:
|
||||
return (
|
||||
waiters_valid
|
||||
and self.SystemResourcesList.Flink is not None
|
||||
and self.SystemResourcesList.Blink is not None
|
||||
and self.SystemResourcesList.Flink != self.SystemResourcesList.Blink
|
||||
and self.SystemResourcesList.Flink.Blink == self.vol.offset
|
||||
and self.SystemResourcesList.Blink.Flink == self.vol.offset
|
||||
and self.NumberOfSharedWaiters == 0
|
||||
)
|
||||
except exceptions.InvalidAddressException:
|
||||
return False
|
||||
|
||||
|
||||
class EPROCESS(generic.GenericIntelProcess, pool.ExecutiveObject):
|
||||
"""A class for executive kernel processes objects."""
|
||||
|
||||
@@ -1010,6 +1046,83 @@ class TOKEN(objects.StructType):
|
||||
vollog.log(constants.LOGLEVEL_VVVV, "Broken Token Privileges.")
|
||||
|
||||
|
||||
class KTIMER(objects.StructType):
|
||||
"""A class for Kernel Timers"""
|
||||
|
||||
VALID_TYPES = {
|
||||
8: "TimerNotificationObject",
|
||||
9: "TimerSynchronizationObject",
|
||||
}
|
||||
|
||||
def get_signaled(self):
|
||||
if self.Header.SignalState:
|
||||
return "Yes"
|
||||
return "-"
|
||||
|
||||
def get_raw_dpc(self):
|
||||
"""Returns the encoded DPC since it may not look like a pointer after encoding"""
|
||||
symbol_table_name = self.get_symbol_table_name()
|
||||
pointer_type = self._context.symbol_space.get_type(
|
||||
symbol_table_name + constants.BANG + "pointer"
|
||||
)
|
||||
|
||||
return self._context.object(
|
||||
object_type=pointer_type,
|
||||
layer_name=self.vol.layer_name,
|
||||
offset=self.Dpc.vol.offset,
|
||||
)
|
||||
|
||||
def valid_type(self):
|
||||
return self.Header.Type in self.VALID_TYPES
|
||||
|
||||
def get_due_time(self):
|
||||
return "{0:#010x}:{1:#010x}".format(self.DueTime.HighPart, self.DueTime.LowPart)
|
||||
|
||||
def get_dpc(self):
|
||||
"""Return Dpc, and if Windows 7 or later, decode it"""
|
||||
symbol_table_name = self.get_symbol_table_name()
|
||||
kvo = self._context.layers[self.vol.native_layer_name].config[
|
||||
"kernel_virtual_offset"
|
||||
]
|
||||
ntkrnlmp = self._context.module(
|
||||
symbol_table_name,
|
||||
layer_name=self.vol.native_layer_name,
|
||||
offset=kvo,
|
||||
native_layer_name=self.vol.native_layer_name,
|
||||
)
|
||||
|
||||
if ntkrnlmp.has_symbol("KiWaitNever") and ntkrnlmp.has_symbol("KiWaitAlways"):
|
||||
wait_never = ntkrnlmp.object(
|
||||
object_type="unsigned long long",
|
||||
offset=ntkrnlmp.get_symbol("KiWaitNever").address,
|
||||
)
|
||||
wait_always = ntkrnlmp.object(
|
||||
object_type="unsigned long long",
|
||||
offset=ntkrnlmp.get_symbol("KiWaitAlways").address,
|
||||
)
|
||||
|
||||
low_byte = (wait_never) & 0xFF
|
||||
entry = utility.rol(self.get_raw_dpc() ^ wait_never, low_byte)
|
||||
swap_xor = self._context.layers[self.vol.native_layer_name].canonicalize(
|
||||
self.vol.offset
|
||||
)
|
||||
entry = utility.bswap_64(entry ^ swap_xor)
|
||||
dpc = entry ^ wait_always
|
||||
|
||||
symbol_table_name = self.get_symbol_table_name()
|
||||
kdpc_type = self._context.symbol_space.get_type(
|
||||
symbol_table_name + constants.BANG + "_KDPC"
|
||||
)
|
||||
|
||||
return self._context.object(
|
||||
object_type=kdpc_type,
|
||||
layer_name=self.vol.layer_name,
|
||||
offset=dpc,
|
||||
)
|
||||
else:
|
||||
return self.Dpc
|
||||
|
||||
|
||||
class KTHREAD(objects.StructType):
|
||||
"""A class for thread control block objects."""
|
||||
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
# 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 logging
|
||||
import struct
|
||||
from datetime import datetime
|
||||
from typing import Dict, Optional, Tuple, Union
|
||||
|
||||
from volatility3.framework import constants, exceptions, interfaces, objects, renderers
|
||||
from volatility3.framework.symbols.windows.extensions import conversion
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SHIM_CACHE_ENTRY(objects.StructType):
|
||||
"""Class for abstracting variations in the shimcache LRU list entry structure"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
context: interfaces.context.ContextInterface,
|
||||
type_name: str,
|
||||
object_info: interfaces.objects.ObjectInformation,
|
||||
size: int,
|
||||
members: Dict[str, Tuple[int, interfaces.objects.Template]],
|
||||
) -> None:
|
||||
super().__init__(context, type_name, object_info, size, members)
|
||||
self._exec_flag = None
|
||||
self._file_path = None
|
||||
self._file_size = None
|
||||
self._last_modified = None
|
||||
self._last_updated = None
|
||||
|
||||
@property
|
||||
def exec_flag(self) -> Union[bool, interfaces.renderers.BaseAbsentValue]:
|
||||
"""Checks if InsertFlags fields has been bitwise OR'd with a value of 2.
|
||||
This behavior was observed when processes are created by CSRSS."""
|
||||
if self._exec_flag is not None:
|
||||
return self._exec_flag
|
||||
|
||||
if hasattr(self, "ListEntryDetail") and hasattr(
|
||||
self.ListEntryDetail, "InsertFlags"
|
||||
):
|
||||
self._exec_flag = self.ListEntryDetail.InsertFlags & 0x2 == 2
|
||||
|
||||
elif hasattr(self, "InsertFlags"):
|
||||
self._exec_flag = self.InsertFlags & 0x2 == 2
|
||||
|
||||
elif hasattr(self, "ListEntryDetail") and hasattr(
|
||||
self.ListEntryDetail, "BlobBuffer"
|
||||
):
|
||||
blob_offset = self.ListEntryDetail.BlobBuffer
|
||||
blob_size = self.ListEntryDetail.BlobSize
|
||||
|
||||
if not self._context.layers[self.vol.native_layer_name].is_valid(
|
||||
blob_offset, blob_size
|
||||
):
|
||||
self._exec_flag = renderers.UnparsableValue()
|
||||
|
||||
raw_flag = self._context.layers[self.vol.native_layer_name].read(
|
||||
blob_offset, blob_size
|
||||
)
|
||||
if not raw_flag:
|
||||
self._exec_flag = renderers.UnparsableValue()
|
||||
|
||||
try:
|
||||
self._exec_flag = bool(struct.unpack("<I", raw_flag)[0])
|
||||
except struct.error:
|
||||
self._exec_flag = renderers.UnparsableValue()
|
||||
|
||||
else:
|
||||
# Always set to true for XP/2K3
|
||||
self._exec_flag = renderers.NotApplicableValue()
|
||||
return self._exec_flag
|
||||
|
||||
@property
|
||||
def file_size(self) -> Union[int, interfaces.renderers.BaseAbsentValue]:
|
||||
if self._file_size is not None:
|
||||
return self._file_size
|
||||
try:
|
||||
self._file_size = self.FileSize
|
||||
if self._file_size < 0:
|
||||
self._file_size = 0
|
||||
|
||||
except AttributeError:
|
||||
self._file_size = renderers.NotApplicableValue()
|
||||
except exceptions.InvalidAddressException:
|
||||
self._file_size = renderers.UnreadableValue()
|
||||
|
||||
return self._file_size
|
||||
|
||||
@property
|
||||
def last_modified(self) -> Union[datetime, interfaces.renderers.BaseAbsentValue]:
|
||||
if self._last_modified is not None:
|
||||
return self._last_modified
|
||||
try:
|
||||
self._last_modified = conversion.wintime_to_datetime(
|
||||
self.ListEntryDetail.LastModified.QuadPart
|
||||
)
|
||||
except AttributeError:
|
||||
self._last_modified = conversion.wintime_to_datetime(
|
||||
self.LastModified.QuadPart
|
||||
)
|
||||
except exceptions.InvalidAddressException:
|
||||
self._last_modified = renderers.UnreadableValue()
|
||||
|
||||
return self._last_modified
|
||||
|
||||
@property
|
||||
def last_update(self) -> Union[datetime, interfaces.renderers.BaseAbsentValue]:
|
||||
if self._last_updated is not None:
|
||||
return self._last_updated
|
||||
|
||||
try:
|
||||
self._last_updated = conversion.wintime_to_datetime(
|
||||
self.LastUpdate.QuadPart
|
||||
)
|
||||
except AttributeError:
|
||||
self._last_updated = renderers.NotApplicableValue()
|
||||
|
||||
return self._last_updated
|
||||
|
||||
@property
|
||||
def file_path(self) -> Union[str, interfaces.renderers.BaseAbsentValue]:
|
||||
if self._file_path is not None:
|
||||
return self._file_path
|
||||
|
||||
if not hasattr(self.Path, "Buffer"):
|
||||
return self.Path.cast(
|
||||
"string", max_length=self.Path.vol.count, encoding="utf-16le"
|
||||
)
|
||||
|
||||
try:
|
||||
file_path_raw = (
|
||||
self._context.layers[self.vol.native_layer_name].read(
|
||||
self.Path.Buffer, self.Path.Length
|
||||
)
|
||||
or b""
|
||||
)
|
||||
self._file_path = file_path_raw.decode("utf-16", errors="replace")
|
||||
except exceptions.InvalidAddressException:
|
||||
self._file_path = renderers.UnreadableValue()
|
||||
|
||||
return self._file_path
|
||||
|
||||
def is_valid(self) -> bool:
|
||||
"""Shim cache validation is limited to ensuring that a subset of the
|
||||
pointers in the LIST_ENTRY field are valid (similar to validation of
|
||||
ERESOURCE)"""
|
||||
|
||||
# shim entries on Windows XP do not have list entry attributes; in this case,
|
||||
# perform a different set of validations
|
||||
try:
|
||||
if not hasattr(self, "ListEntry"):
|
||||
return bool(self.last_modified and self.last_update and self.file_size)
|
||||
|
||||
# on some platforms ListEntry.Blink is null, so this cannot be validated
|
||||
if (
|
||||
self.ListEntry.Flink != 0
|
||||
and (
|
||||
self.ListEntry.Blink.dereference()
|
||||
!= self.ListEntry.Flink.dereference()
|
||||
)
|
||||
and (
|
||||
self.ListEntry.Flink.Blink
|
||||
== self.ListEntry.Flink.Blink.dereference().vol.offset
|
||||
)
|
||||
):
|
||||
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except exceptions.InvalidAddressException:
|
||||
return False
|
||||
|
||||
|
||||
class SHIM_CACHE_HANDLE(objects.StructType):
|
||||
def __init__(
|
||||
self,
|
||||
context: interfaces.context.ContextInterface,
|
||||
type_name: str,
|
||||
object_info: interfaces.objects.ObjectInformation,
|
||||
size: int,
|
||||
members: Dict[str, Tuple[int, interfaces.objects.Template]],
|
||||
) -> None:
|
||||
super().__init__(context, type_name, object_info, size, members)
|
||||
|
||||
@property
|
||||
def head(self) -> Optional[SHIM_CACHE_ENTRY]:
|
||||
try:
|
||||
if not self.eresource.is_valid():
|
||||
return None
|
||||
except exceptions.InvalidAddressException:
|
||||
return None
|
||||
|
||||
rtl_avl_table = self._context.object(
|
||||
self.get_symbol_table_name() + constants.BANG + "_RTL_AVL_TABLE",
|
||||
self.vol.layer_name,
|
||||
self.rtl_avl_table,
|
||||
self.vol.native_layer_name,
|
||||
)
|
||||
|
||||
if not self._context.layers[self.vol.layer_name].is_valid(
|
||||
self.rtl_avl_table.vol.offset
|
||||
):
|
||||
return None
|
||||
|
||||
offset_head = rtl_avl_table.vol.offset + rtl_avl_table.vol.size
|
||||
|
||||
head = self._context.object(
|
||||
self.get_symbol_table_name() + constants.BANG + "SHIM_CACHE_ENTRY",
|
||||
self.vol.layer_name,
|
||||
offset_head,
|
||||
)
|
||||
|
||||
if not head.is_valid():
|
||||
return None
|
||||
|
||||
return head
|
||||
|
||||
def is_valid(self, avl_section_start: int, avl_section_end: int) -> bool:
|
||||
if self.vol.offset == 0:
|
||||
return False
|
||||
|
||||
vollog.debug(f"Checking SHIM_CACHE_HANDLE validity @ {hex(self.vol.offset)}")
|
||||
|
||||
if not (
|
||||
self._context.layers[self.vol.layer_name].is_valid(self.vol.offset)
|
||||
and self.eresource.is_valid()
|
||||
and self.rtl_avl_table.is_valid(avl_section_start, avl_section_end)
|
||||
and self.head
|
||||
):
|
||||
return False
|
||||
|
||||
return self.head.is_valid()
|
||||
|
||||
|
||||
class RTL_AVL_TABLE(objects.StructType):
|
||||
def is_valid(self, page_start: int, page_end: int) -> bool:
|
||||
try:
|
||||
if self.BalancedRoot.Parent != self.BalancedRoot.vol.offset:
|
||||
vollog.debug(
|
||||
f"RTL_AVL_TABLE @ {self.vol.offset} Invalid: Failed BalancedRoot parent equality check"
|
||||
)
|
||||
return False
|
||||
|
||||
elif self.AllocateRoutine < page_start or self.AllocateRoutine > page_end:
|
||||
vollog.debug(
|
||||
f"RTL_AVL_TABLE @ {self.vol.offset} Invalid: Failed AllocateRoutine range check"
|
||||
)
|
||||
return False
|
||||
|
||||
elif self.CompareRoutine < page_start or self.CompareRoutine > page_end:
|
||||
vollog.debug(
|
||||
f"RTL_AVL_TABLE @ {self.vol.offset} Invalid: Failed CompareRoutine range check"
|
||||
)
|
||||
return False
|
||||
|
||||
elif (
|
||||
(self.AllocateRoutine.vol.offset == self.CompareRoutine.vol.offset)
|
||||
or (self.AllocateRoutine.vol.offset == self.FreeRoutine.vol.offset)
|
||||
or (self.CompareRoutine.vol.offset == self.FreeRoutine.vol.offset)
|
||||
):
|
||||
vollog.debug(
|
||||
f"RTL_AVL_TABLE @ {self.vol.offset} Invalid: Failed (Compare|Allocate|Free)Routine uniqueness check"
|
||||
)
|
||||
return False
|
||||
|
||||
return True
|
||||
except exceptions.InvalidAddressException:
|
||||
return False
|
||||
|
||||
|
||||
class_types = {
|
||||
"SHIM_CACHE_HANDLE": SHIM_CACHE_HANDLE,
|
||||
"SHIM_CACHE_ENTRY": SHIM_CACHE_ENTRY,
|
||||
"_RTL_AVL_TABLE": RTL_AVL_TABLE,
|
||||
}
|
||||
@@ -0,0 +1,582 @@
|
||||
{
|
||||
"base_types": {
|
||||
"unsigned long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned char": {
|
||||
"kind": "char",
|
||||
"size": 1,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"pointer": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned be short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "big"
|
||||
},
|
||||
"long long": {
|
||||
"endian": "little",
|
||||
"kind": "int",
|
||||
"signed": true,
|
||||
"size": 8
|
||||
},
|
||||
"long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
}
|
||||
},
|
||||
"symbols": {},
|
||||
"user_types": {
|
||||
"_UDP_ENDPOINT": {
|
||||
"fields": {
|
||||
"Owner": {
|
||||
"offset": 40,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_EPROCESS"
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
"CreateTime": {
|
||||
"offset": 88,
|
||||
"type": {
|
||||
"kind": "union",
|
||||
"name": "_LARGE_INTEGER"
|
||||
}
|
||||
},
|
||||
"Next": {
|
||||
"offset": 112,
|
||||
"type":{
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_UDP_ENDPOINT"
|
||||
}
|
||||
}
|
||||
},
|
||||
"LocalAddr": {
|
||||
"offset": 168,
|
||||
"type":{
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_LOCAL_ADDRESS_WIN10_UDP"
|
||||
}
|
||||
}
|
||||
},
|
||||
"InetAF": {
|
||||
"offset": 32,
|
||||
"type":{
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_INETAF"
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
"Port": {
|
||||
"offset": 160,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned be short"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 168
|
||||
},
|
||||
"_TCP_LISTENER": {
|
||||
"fields": {
|
||||
"Owner": {
|
||||
"offset": 48,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_EPROCESS"
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
"CreateTime": {
|
||||
"offset": 64,
|
||||
"type": {
|
||||
"kind": "union",
|
||||
"name": "_LARGE_INTEGER"
|
||||
}
|
||||
},
|
||||
"LocalAddr": {
|
||||
"offset": 96,
|
||||
"type":{
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_LOCAL_ADDRESS"
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
"InetAF": {
|
||||
"offset": 40,
|
||||
"type":{
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_INETAF"
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
"Next": {
|
||||
"offset": 120,
|
||||
"type":{
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_TCP_LISTENER"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Port": {
|
||||
"offset": 114,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned be short"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 128
|
||||
},
|
||||
"_TCP_ENDPOINT": {
|
||||
"fields": {
|
||||
"Owner": {
|
||||
"offset": 752,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_EPROCESS"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CreateTime": {
|
||||
"offset": 776,
|
||||
"type": {
|
||||
"kind": "union",
|
||||
"name": "_LARGE_INTEGER"
|
||||
}
|
||||
},
|
||||
"AddrInfo": {
|
||||
"offset": 24,
|
||||
"type":{
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_ADDRINFO"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ListEntry": {
|
||||
"offset": 40,
|
||||
"type": {
|
||||
"kind": "union",
|
||||
"name": "nt_symbols!_LIST_ENTRY"
|
||||
}
|
||||
},
|
||||
"InetAF": {
|
||||
"offset": 16,
|
||||
"type":{
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_INETAF"
|
||||
}
|
||||
}
|
||||
},
|
||||
"LocalPort": {
|
||||
"offset": 112,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned be short"
|
||||
}
|
||||
},
|
||||
"RemotePort": {
|
||||
"offset": 114,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned be short"
|
||||
}
|
||||
},
|
||||
"State": {
|
||||
"offset": 108,
|
||||
"type": {
|
||||
"kind": "enum",
|
||||
"name": "TCPStateEnum"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 632
|
||||
},
|
||||
"_LOCAL_ADDRESS": {
|
||||
"fields": {
|
||||
"pData": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_IN_ADDR"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 20
|
||||
},
|
||||
"_LOCAL_ADDRESS_WIN10_UDP": {
|
||||
"fields": {
|
||||
"pData": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_IN_ADDR"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 4
|
||||
},
|
||||
"_ADDRINFO": {
|
||||
"fields": {
|
||||
"Local": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_LOCAL_ADDRESS"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Remote": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_IN_ADDR"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 4
|
||||
},
|
||||
"_IN_ADDR": {
|
||||
"fields": {
|
||||
"addr4": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"count": 4,
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
},
|
||||
"kind": "array"
|
||||
}
|
||||
},
|
||||
"addr6": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"count": 16,
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
},
|
||||
"kind": "array"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 6
|
||||
},
|
||||
"_INETAF": {
|
||||
"fields": {
|
||||
"AddressFamily": {
|
||||
"offset": 24,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned short"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 26
|
||||
},
|
||||
"_LARGE_INTEGER": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"QuadPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long long"
|
||||
}
|
||||
},
|
||||
"u": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "__unnamed_2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "union",
|
||||
"size": 8
|
||||
},
|
||||
"_INET_COMPARTMENT_SET": {
|
||||
"fields": {
|
||||
"InetCompartment": {
|
||||
"offset": 328,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_INET_COMPARTMENT"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 384
|
||||
},
|
||||
"_INET_COMPARTMENT": {
|
||||
"fields": {
|
||||
"ProtocolCompartment": {
|
||||
"offset": 32,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_PROTOCOL_COMPARTMENT"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 48
|
||||
},
|
||||
"_PROTOCOL_COMPARTMENT": {
|
||||
"fields": {
|
||||
"PortPool": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_INET_PORT_POOL"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 16
|
||||
},
|
||||
"_PORT_ASSIGNMENT_ENTRY": {
|
||||
"fields": {
|
||||
"Entry": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 32
|
||||
},
|
||||
"_PORT_ASSIGNMENT_LIST": {
|
||||
"fields": {
|
||||
"Assignments": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"count": 256,
|
||||
"kind": "array",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_PORT_ASSIGNMENT_ENTRY"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 6144
|
||||
},
|
||||
"_PORT_ASSIGNMENT": {
|
||||
"fields": {
|
||||
"InPaBigPoolBase": {
|
||||
"offset": 24,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_PORT_ASSIGNMENT_LIST"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 32
|
||||
},
|
||||
"_INET_PORT_POOL": {
|
||||
"fields": {
|
||||
"PortAssignments": {
|
||||
"offset": 224,
|
||||
"type": {
|
||||
"count": 256,
|
||||
"kind": "array",
|
||||
"subtype": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_PORT_ASSIGNMENT"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"PortBitMap": {
|
||||
"offset": 208,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_RTL_BITMAP"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 11200
|
||||
},
|
||||
"_PARTITION": {
|
||||
"fields": {
|
||||
"Endpoints" : {
|
||||
"offset": 8,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_RTL_DYNAMIC_HASH_TABLE"
|
||||
}
|
||||
}
|
||||
},
|
||||
"UnknownHashTable" : {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_RTL_DYNAMIC_HASH_TABLE"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 192
|
||||
},
|
||||
"_PARTITION_TABLE": {
|
||||
"fields": {
|
||||
"Partitions": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"count": 1,
|
||||
"kind": "array",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_PARTITION"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 128
|
||||
}
|
||||
},
|
||||
"enums": {
|
||||
"TCPStateEnum": {
|
||||
"base": "long",
|
||||
"constants": {
|
||||
"CLOSED": 0,
|
||||
"LISTENING": 1,
|
||||
"SYN_SENT": 2,
|
||||
"SYN_RCVD": 3,
|
||||
"ESTABLISHED": 4,
|
||||
"FIN_WAIT1": 5,
|
||||
"FIN_WAIT2": 6,
|
||||
"CLOSE_WAIT": 7,
|
||||
"CLOSING": 8,
|
||||
"LAST_ACK": 9,
|
||||
"TIME_WAIT": 12,
|
||||
"DELETE_TCB": 13
|
||||
},
|
||||
"size": 4
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"producer": {
|
||||
"version": "0.0.1",
|
||||
"name": "dgmcdona-by-hand",
|
||||
"datetime": "2024-07-30T13:00:00"
|
||||
},
|
||||
"format": "6.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
{
|
||||
"symbols": {},
|
||||
"enums": {},
|
||||
"base_types": {
|
||||
"unsigned long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned long long": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned char": {
|
||||
"kind": "char",
|
||||
"size": 1,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"pointer": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
}
|
||||
},
|
||||
"user_types": {
|
||||
"_RTL_BALANCED_LINKS": {
|
||||
"fields": {
|
||||
"Parent": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"LeftChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
},
|
||||
"RightChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 16
|
||||
},
|
||||
"Balance": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
},
|
||||
"offset": 24
|
||||
},
|
||||
"Reserved": {
|
||||
"type": {
|
||||
"kind": "array",
|
||||
"count": 3,
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
},
|
||||
"offset": 25
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 32
|
||||
},
|
||||
"_RTL_AVL_TABLE": {
|
||||
"fields": {
|
||||
"BalancedRoot": {
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"OrderedPointer": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 32
|
||||
},
|
||||
"WhichOrderedElement": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 40
|
||||
},
|
||||
"NumberGenericTableElements": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 44
|
||||
},
|
||||
"DepthOfTree": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 48
|
||||
},
|
||||
"RestartKey": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 56
|
||||
},
|
||||
"DeleteCount": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 64
|
||||
},
|
||||
"CompareRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 72
|
||||
},
|
||||
"AllocateRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 80
|
||||
},
|
||||
"FreeRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 88
|
||||
},
|
||||
"TableContext": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 96
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 104
|
||||
},
|
||||
"SHIM_CACHE_HANDLE": {
|
||||
"fields": {
|
||||
"eresource": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_ERESOURCE"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"rtl_avl_table": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_AVL_TABLE"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 16
|
||||
},
|
||||
"_LARGE_INTEGER": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"QuadPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long long"
|
||||
}
|
||||
},
|
||||
"u": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "__unnamed_2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "union",
|
||||
"size": 8
|
||||
},
|
||||
"__unnamed_2": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"SHIM_CACHE_ENTRY": {
|
||||
"fields": {
|
||||
"ListEntry": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_LIST_ENTRY"
|
||||
}
|
||||
},
|
||||
"Path": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_UNICODE_STRING"
|
||||
}
|
||||
},
|
||||
"LastModified": {
|
||||
"offset": 32,
|
||||
"type": {
|
||||
"kind": "union",
|
||||
"name": "_LARGE_INTEGER"
|
||||
}
|
||||
},
|
||||
"FileSize": {
|
||||
"offset": 40,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 48
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"producer": {
|
||||
"version": "0.0.1",
|
||||
"name": "dgmcdona by hand",
|
||||
"datetime": "2024-07-05T18:28:00.000000+00:00"
|
||||
},
|
||||
"format": "4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
{
|
||||
"symbols": {},
|
||||
"enums": {},
|
||||
"base_types": {
|
||||
"unsigned long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned long long": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned char": {
|
||||
"kind": "char",
|
||||
"size": 1,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"pointer": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
}
|
||||
},
|
||||
"user_types": {
|
||||
"_RTL_BALANCED_LINKS": {
|
||||
"fields": {
|
||||
"Parent": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"LeftChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 4
|
||||
},
|
||||
"RightChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
},
|
||||
"Balance": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
},
|
||||
"offset": 12
|
||||
},
|
||||
"Reserved": {
|
||||
"type": {
|
||||
"kind": "array",
|
||||
"count": 3,
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
},
|
||||
"offset": 12
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 16
|
||||
},
|
||||
"_RTL_AVL_TABLE": {
|
||||
"fields": {
|
||||
"BalancedRoot": {
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"OrderedPointer": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 16
|
||||
},
|
||||
"WhichOrderedElement": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 20
|
||||
},
|
||||
"NumberGenericTableElements": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 24
|
||||
},
|
||||
"DepthOfTree": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 28
|
||||
},
|
||||
"RestartKey": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 32
|
||||
},
|
||||
"DeleteCount": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 36
|
||||
},
|
||||
"CompareRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 40
|
||||
},
|
||||
"AllocateRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 44
|
||||
},
|
||||
"FreeRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 48
|
||||
},
|
||||
"TableContext": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 52
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 56
|
||||
},
|
||||
"SHIM_CACHE_HANDLE": {
|
||||
"fields": {
|
||||
"eresource": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_ERESOURCE"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"rtl_avl_table": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_AVL_TABLE"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"_LARGE_INTEGER": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"QuadPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long long"
|
||||
}
|
||||
},
|
||||
"u": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "__unnamed_2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "union",
|
||||
"size": 8
|
||||
},
|
||||
"__unnamed_2": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"SHIM_CACHE_ENTRY": {
|
||||
"fields": {
|
||||
"ListEntry": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_LIST_ENTRY"
|
||||
}
|
||||
},
|
||||
"Path": {
|
||||
"offset": 8,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_UNICODE_STRING"
|
||||
}
|
||||
},
|
||||
"LastModified": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "union",
|
||||
"name": "_LARGE_INTEGER"
|
||||
}
|
||||
},
|
||||
"FileSize": {
|
||||
"offset": 24,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"Padding": {
|
||||
"offset": 32,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 36
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"producer": {
|
||||
"version": "0.0.1",
|
||||
"name": "dgmcdona by hand",
|
||||
"datetime": "2024-07-05T18:28:00.000000+00:00"
|
||||
},
|
||||
"format": "4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
{
|
||||
"symbols": {},
|
||||
"enums": {},
|
||||
"base_types": {
|
||||
"unsigned long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned long long": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned char": {
|
||||
"kind": "char",
|
||||
"size": 1,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"pointer": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
}
|
||||
},
|
||||
"user_types": {
|
||||
"_RTL_BALANCED_LINKS": {
|
||||
"fields": {
|
||||
"Parent": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"LeftChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
},
|
||||
"RightChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 16
|
||||
},
|
||||
"Balance": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
},
|
||||
"offset": 24
|
||||
},
|
||||
"Reserved": {
|
||||
"type": {
|
||||
"kind": "array",
|
||||
"count": 3,
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
},
|
||||
"offset": 25
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 32
|
||||
},
|
||||
"_RTL_AVL_TABLE": {
|
||||
"fields": {
|
||||
"BalancedRoot": {
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"OrderedPointer": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 32
|
||||
},
|
||||
"WhichOrderedElement": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 40
|
||||
},
|
||||
"NumberGenericTableElements": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 44
|
||||
},
|
||||
"DepthOfTree": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 48
|
||||
},
|
||||
"RestartKey": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 56
|
||||
},
|
||||
"DeleteCount": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 64
|
||||
},
|
||||
"CompareRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 72
|
||||
},
|
||||
"AllocateRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 80
|
||||
},
|
||||
"FreeRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 88
|
||||
},
|
||||
"TableContext": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 96
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 104
|
||||
},
|
||||
"SHIM_CACHE_HANDLE": {
|
||||
"fields": {
|
||||
"eresource": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_ERESOURCE"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"rtl_avl_table": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_AVL_TABLE"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 16
|
||||
},
|
||||
"_LARGE_INTEGER": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"QuadPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long long"
|
||||
}
|
||||
},
|
||||
"u": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "__unnamed_2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "union",
|
||||
"size": 8
|
||||
},
|
||||
"__unnamed_2": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"SHIM_CACHE_ENTRY": {
|
||||
"fields": {
|
||||
"ListEntry": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_LIST_ENTRY"
|
||||
}
|
||||
},
|
||||
"Path": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_UNICODE_STRING"
|
||||
}
|
||||
},
|
||||
"LastModified": {
|
||||
"offset": 32,
|
||||
"type": {
|
||||
"kind": "union",
|
||||
"name": "_LARGE_INTEGER"
|
||||
}
|
||||
},
|
||||
"InsertFlags": {
|
||||
"offset": 40,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
}
|
||||
},
|
||||
"ShimFlags": {
|
||||
"offset": 44,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 48
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"producer": {
|
||||
"version": "0.0.1",
|
||||
"name": "dgmcdona by hand",
|
||||
"datetime": "2024-07-05T18:28:00.000000+00:00"
|
||||
},
|
||||
"format": "4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
{
|
||||
"symbols": {},
|
||||
"enums": {},
|
||||
"base_types": {
|
||||
"unsigned long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned long long": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned char": {
|
||||
"kind": "char",
|
||||
"size": 1,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"pointer": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
}
|
||||
},
|
||||
"user_types": {
|
||||
"_RTL_BALANCED_LINKS": {
|
||||
"fields": {
|
||||
"Parent": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"LeftChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 4
|
||||
},
|
||||
"RightChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
},
|
||||
"Balance": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
},
|
||||
"offset": 12
|
||||
},
|
||||
"Reserved": {
|
||||
"type": {
|
||||
"kind": "array",
|
||||
"count": 3,
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
},
|
||||
"offset": 12
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 16
|
||||
},
|
||||
"_RTL_AVL_TABLE": {
|
||||
"fields": {
|
||||
"BalancedRoot": {
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"OrderedPointer": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 16
|
||||
},
|
||||
"WhichOrderedElement": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 20
|
||||
},
|
||||
"NumberGenericTableElements": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 24
|
||||
},
|
||||
"DepthOfTree": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 28
|
||||
},
|
||||
"RestartKey": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 32
|
||||
},
|
||||
"DeleteCount": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 36
|
||||
},
|
||||
"CompareRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 40
|
||||
},
|
||||
"AllocateRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 44
|
||||
},
|
||||
"FreeRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 48
|
||||
},
|
||||
"TableContext": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 52
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 56
|
||||
},
|
||||
"SHIM_CACHE_HANDLE": {
|
||||
"fields": {
|
||||
"eresource": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_ERESOURCE"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"rtl_avl_table": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_AVL_TABLE"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"_LARGE_INTEGER": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"QuadPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long long"
|
||||
}
|
||||
},
|
||||
"u": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "__unnamed_2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "union",
|
||||
"size": 8
|
||||
},
|
||||
"__unnamed_2": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"SHIM_CACHE_ENTRY": {
|
||||
"fields": {
|
||||
"ListEntry": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_LIST_ENTRY"
|
||||
}
|
||||
},
|
||||
"Path": {
|
||||
"offset": 8,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_UNICODE_STRING"
|
||||
}
|
||||
},
|
||||
"LastModified": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "union",
|
||||
"name": "_LARGE_INTEGER"
|
||||
}
|
||||
},
|
||||
"InsertFlags": {
|
||||
"offset": 24,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
}
|
||||
},
|
||||
"ShimFlags": {
|
||||
"offset": 28,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 36
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"producer": {
|
||||
"version": "0.0.1",
|
||||
"name": "dgmcdona by hand",
|
||||
"datetime": "2024-07-05T18:28:00.000000+00:00"
|
||||
},
|
||||
"format": "4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
{
|
||||
"symbols": {},
|
||||
"enums": {},
|
||||
"base_types": {
|
||||
"unsigned long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned long long": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned char": {
|
||||
"kind": "char",
|
||||
"size": 1,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"pointer": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
}
|
||||
},
|
||||
"user_types": {
|
||||
"_RTL_BALANCED_LINKS": {
|
||||
"fields": {
|
||||
"Parent": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"LeftChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
},
|
||||
"RightChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 16
|
||||
},
|
||||
"Balance": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
},
|
||||
"offset": 24
|
||||
},
|
||||
"Reserved": {
|
||||
"type": {
|
||||
"kind": "array",
|
||||
"count": 3,
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
},
|
||||
"offset": 25
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 32
|
||||
},
|
||||
"_RTL_AVL_TABLE": {
|
||||
"fields": {
|
||||
"BalancedRoot": {
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"OrderedPointer": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 32
|
||||
},
|
||||
"WhichOrderedElement": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 40
|
||||
},
|
||||
"NumberGenericTableElements": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 44
|
||||
},
|
||||
"DepthOfTree": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 48
|
||||
},
|
||||
"RestartKey": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 56
|
||||
},
|
||||
"DeleteCount": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 64
|
||||
},
|
||||
"CompareRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 72
|
||||
},
|
||||
"AllocateRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 80
|
||||
},
|
||||
"FreeRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 88
|
||||
},
|
||||
"TableContext": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 96
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 104
|
||||
},
|
||||
"SHIM_CACHE_HANDLE": {
|
||||
"fields": {
|
||||
"eresource": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_ERESOURCE"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"rtl_avl_table": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_AVL_TABLE"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 16
|
||||
},
|
||||
"_LARGE_INTEGER": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"QuadPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long long"
|
||||
}
|
||||
},
|
||||
"u": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "__unnamed_2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "union",
|
||||
"size": 8
|
||||
},
|
||||
"__unnamed_2": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"SHIM_CACHE_ENTRY": {
|
||||
"fields": {
|
||||
"ListEntry": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_LIST_ENTRY"
|
||||
}
|
||||
},
|
||||
"u1": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
}
|
||||
},
|
||||
"Path": {
|
||||
"offset": 24,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_UNICODE_STRING"
|
||||
}
|
||||
},
|
||||
"ListEntryDetail": {
|
||||
"offset": 40,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "SHIM_CACHE_ENTRY_DETAIL"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 48
|
||||
},
|
||||
"SHIM_CACHE_ENTRY_DETAIL": {
|
||||
"fields": {
|
||||
"u1": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
}
|
||||
},
|
||||
"LastModified": {
|
||||
"offset": 8,
|
||||
"type": {
|
||||
"kind": "union",
|
||||
"name": "_LARGE_INTEGER"
|
||||
}
|
||||
},
|
||||
"BlobSize": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"u2": {
|
||||
"offset": 20,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"BlobBuffer": {
|
||||
"offset": 24,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 32
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"producer": {
|
||||
"version": "0.0.1",
|
||||
"name": "dgmcdona by hand",
|
||||
"datetime": "2024-07-05T18:28:00.000000+00:00"
|
||||
},
|
||||
"format": "4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
{
|
||||
"symbols": {},
|
||||
"enums": {},
|
||||
"base_types": {
|
||||
"unsigned long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned long long": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned char": {
|
||||
"kind": "char",
|
||||
"size": 1,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"pointer": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
}
|
||||
},
|
||||
"user_types": {
|
||||
"SHIM_CACHE_HANDLE": {
|
||||
"fields": {
|
||||
"eresource": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_ERESOURCE"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"rtl_avl_table": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_AVL_TABLE"
|
||||
}
|
||||
},
|
||||
"offset": 4
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"_RTL_BALANCED_LINKS": {
|
||||
"fields": {
|
||||
"Parent": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"LeftChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 4
|
||||
},
|
||||
"RightChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
},
|
||||
"Balance": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
},
|
||||
"offset": 12
|
||||
},
|
||||
"Reserved": {
|
||||
"type": {
|
||||
"kind": "array",
|
||||
"count": 3,
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
},
|
||||
"offset": 12
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 16
|
||||
},
|
||||
"_RTL_AVL_TABLE": {
|
||||
"fields": {
|
||||
"BalancedRoot": {
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"OrderedPointer": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 16
|
||||
},
|
||||
"WhichOrderedElement": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 20
|
||||
},
|
||||
"NumberGenericTableElements": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 24
|
||||
},
|
||||
"DepthOfTree": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 28
|
||||
},
|
||||
"RestartKey": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 32
|
||||
},
|
||||
"DeleteCount": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 36
|
||||
},
|
||||
"CompareRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 40
|
||||
},
|
||||
"AllocateRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 44
|
||||
},
|
||||
"FreeRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 48
|
||||
},
|
||||
"TableContext": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 52
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 56
|
||||
},
|
||||
"_LARGE_INTEGER": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"QuadPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long long"
|
||||
}
|
||||
},
|
||||
"u": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "__unnamed_2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "union",
|
||||
"size": 8
|
||||
},
|
||||
"__unnamed_2": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"SHIM_CACHE_ENTRY": {
|
||||
"fields": {
|
||||
"ListEntry": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_LIST_ENTRY"
|
||||
}
|
||||
},
|
||||
"u1": {
|
||||
"offset": 8,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"Path": {
|
||||
"offset": 12,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_UNICODE_STRING"
|
||||
}
|
||||
},
|
||||
"ListEntryDetail": {
|
||||
"offset": 20,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "SHIM_CACHE_ENTRY_DETAIL"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 24
|
||||
},
|
||||
"SHIM_CACHE_ENTRY_DETAIL": {
|
||||
"fields": {
|
||||
"u1": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"InsertFlags": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"LastModified": {
|
||||
"offset": 8,
|
||||
"type": {
|
||||
"kind": "union",
|
||||
"name": "_LARGE_INTEGER"
|
||||
}
|
||||
},
|
||||
"BlobSize": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"BlobBuffer": {
|
||||
"offset": 20,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 24
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"producer": {
|
||||
"version": "0.0.1",
|
||||
"name": "dgmcdona by hand",
|
||||
"datetime": "2024-07-05T18:28:00.000000+00:00"
|
||||
},
|
||||
"format": "4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
{
|
||||
"symbols": {},
|
||||
"enums": {},
|
||||
"base_types": {
|
||||
"unsigned long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned long long": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned char": {
|
||||
"kind": "char",
|
||||
"size": 1,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"pointer": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
}
|
||||
},
|
||||
"user_types": {
|
||||
"_RTL_BALANCED_LINKS": {
|
||||
"fields": {
|
||||
"Parent": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"LeftChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
},
|
||||
"RightChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 16
|
||||
},
|
||||
"Balance": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
},
|
||||
"offset": 24
|
||||
},
|
||||
"Reserved": {
|
||||
"type": {
|
||||
"kind": "array",
|
||||
"count": 3,
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
},
|
||||
"offset": 25
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 32
|
||||
},
|
||||
"_RTL_AVL_TABLE": {
|
||||
"fields": {
|
||||
"BalancedRoot": {
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"OrderedPointer": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 32
|
||||
},
|
||||
"WhichOrderedElement": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 40
|
||||
},
|
||||
"NumberGenericTableElements": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 44
|
||||
},
|
||||
"DepthOfTree": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 48
|
||||
},
|
||||
"RestartKey": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 56
|
||||
},
|
||||
"DeleteCount": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 64
|
||||
},
|
||||
"CompareRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 72
|
||||
},
|
||||
"AllocateRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 80
|
||||
},
|
||||
"FreeRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 88
|
||||
},
|
||||
"TableContext": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 96
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 104
|
||||
},
|
||||
"SHIM_CACHE_HANDLE": {
|
||||
"fields": {
|
||||
"eresource": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_ERESOURCE"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"rtl_avl_table": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_AVL_TABLE"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"_LARGE_INTEGER": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"QuadPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long long"
|
||||
}
|
||||
},
|
||||
"u": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "__unnamed_2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "union",
|
||||
"size": 8
|
||||
},
|
||||
"__unnamed_2": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"SHIM_CACHE_ENTRY": {
|
||||
"fields": {
|
||||
"ListEntry": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_LIST_ENTRY"
|
||||
}
|
||||
},
|
||||
"Path": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_UNICODE_STRING"
|
||||
}
|
||||
},
|
||||
"LastModified": {
|
||||
"offset": 32,
|
||||
"type": {
|
||||
"kind": "union",
|
||||
"name": "_LARGE_INTEGER"
|
||||
}
|
||||
},
|
||||
"InsertFlags": {
|
||||
"offset": 40,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
}
|
||||
},
|
||||
"ShimFlags": {
|
||||
"offset": 44,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
}
|
||||
},
|
||||
"BlobSize": {
|
||||
"offset": 48,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
}
|
||||
},
|
||||
"BlobBuffer": {
|
||||
"offset": 56,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 64
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"producer": {
|
||||
"version": "0.0.1",
|
||||
"name": "dgmcdona by hand",
|
||||
"datetime": "2024-07-05T18:28:00.000000+00:00"
|
||||
},
|
||||
"format": "4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
{
|
||||
"symbols": {},
|
||||
"enums": {},
|
||||
"base_types": {
|
||||
"unsigned long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned long long": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned char": {
|
||||
"kind": "char",
|
||||
"size": 1,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"pointer": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
}
|
||||
},
|
||||
"user_types": {
|
||||
"_RTL_BALANCED_LINKS": {
|
||||
"fields": {
|
||||
"Parent": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"LeftChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 4
|
||||
},
|
||||
"RightChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
},
|
||||
"Balance": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
},
|
||||
"offset": 12
|
||||
},
|
||||
"Reserved": {
|
||||
"type": {
|
||||
"kind": "array",
|
||||
"count": 3,
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
},
|
||||
"offset": 12
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 16
|
||||
},
|
||||
"_RTL_AVL_TABLE": {
|
||||
"fields": {
|
||||
"BalancedRoot": {
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"OrderedPointer": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 16
|
||||
},
|
||||
"WhichOrderedElement": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 20
|
||||
},
|
||||
"NumberGenericTableElements": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 24
|
||||
},
|
||||
"DepthOfTree": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 28
|
||||
},
|
||||
"RestartKey": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 32
|
||||
},
|
||||
"DeleteCount": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 36
|
||||
},
|
||||
"CompareRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 40
|
||||
},
|
||||
"AllocateRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 44
|
||||
},
|
||||
"FreeRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 48
|
||||
},
|
||||
"TableContext": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 52
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 56
|
||||
},
|
||||
"SHIM_CACHE_HANDLE": {
|
||||
"fields": {
|
||||
"eresource": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_ERESOURCE"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"rtl_avl_table": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_AVL_TABLE"
|
||||
}
|
||||
},
|
||||
"offset": 4
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"_LARGE_INTEGER": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"QuadPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long long"
|
||||
}
|
||||
},
|
||||
"u": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "__unnamed_2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "union",
|
||||
"size": 8
|
||||
},
|
||||
"__unnamed_2": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"SHIM_CACHE_ENTRY": {
|
||||
"fields": {
|
||||
"ListEntry": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_LIST_ENTRY"
|
||||
}
|
||||
},
|
||||
"Path": {
|
||||
"offset": 8,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_UNICODE_STRING"
|
||||
}
|
||||
},
|
||||
"LastModified": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "union",
|
||||
"name": "_LARGE_INTEGER"
|
||||
}
|
||||
},
|
||||
"InsertFlags": {
|
||||
"offset": 24,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
}
|
||||
},
|
||||
"ShimFlags": {
|
||||
"offset": 28,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
}
|
||||
},
|
||||
"BlobSize": {
|
||||
"offset": 32,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
}
|
||||
},
|
||||
"BlobBuffer": {
|
||||
"offset": 36,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 40
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"producer": {
|
||||
"version": "0.0.1",
|
||||
"name": "dgmcdona by hand",
|
||||
"datetime": "2024-07-05T18:28:00.000000+00:00"
|
||||
},
|
||||
"format": "4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,392 @@
|
||||
{
|
||||
"symbols": {},
|
||||
"enums": {},
|
||||
"base_types": {
|
||||
"unsigned long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned long long": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned char": {
|
||||
"kind": "char",
|
||||
"size": 1,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"pointer": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
}
|
||||
},
|
||||
"user_types": {
|
||||
"_RTL_BALANCED_LINKS": {
|
||||
"fields": {
|
||||
"Parent": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"LeftChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
},
|
||||
"RightChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 16
|
||||
},
|
||||
"Balance": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
},
|
||||
"offset": 24
|
||||
},
|
||||
"Reserved": {
|
||||
"type": {
|
||||
"kind": "array",
|
||||
"count": 3,
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
},
|
||||
"offset": 25
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 32
|
||||
},
|
||||
"_RTL_AVL_TABLE": {
|
||||
"fields": {
|
||||
"BalancedRoot": {
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"OrderedPointer": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 32
|
||||
},
|
||||
"WhichOrderedElement": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 40
|
||||
},
|
||||
"NumberGenericTableElements": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 44
|
||||
},
|
||||
"DepthOfTree": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 48
|
||||
},
|
||||
"RestartKey": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 56
|
||||
},
|
||||
"DeleteCount": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 64
|
||||
},
|
||||
"CompareRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 72
|
||||
},
|
||||
"AllocateRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 80
|
||||
},
|
||||
"FreeRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 88
|
||||
},
|
||||
"TableContext": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 96
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 104
|
||||
},
|
||||
"SHIM_CACHE_HANDLE": {
|
||||
"fields": {
|
||||
"eresource": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_ERESOURCE"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"rtl_avl_table": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_AVL_TABLE"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"_LARGE_INTEGER": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"QuadPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long long"
|
||||
}
|
||||
},
|
||||
"u": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "__unnamed_2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "union",
|
||||
"size": 8
|
||||
},
|
||||
"__unnamed_2": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"SHIM_CACHE_ENTRY": {
|
||||
"fields": {
|
||||
"ListEntry": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_LIST_ENTRY"
|
||||
}
|
||||
},
|
||||
"u1": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
}
|
||||
},
|
||||
"Path": {
|
||||
"offset": 24,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_UNICODE_STRING"
|
||||
}
|
||||
},
|
||||
"u2": {
|
||||
"offset": 40,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
}
|
||||
},
|
||||
"u3": {
|
||||
"offset": 48,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
}
|
||||
},
|
||||
"ListEntryDetail": {
|
||||
"offset": 56,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "SHIM_CACHE_ENTRY_DETAIL"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 64
|
||||
},
|
||||
"SHIM_CACHE_ENTRY_DETAIL": {
|
||||
"fields": {
|
||||
"LastModified": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "_LARGE_INTEGER"
|
||||
}
|
||||
},
|
||||
"InsertFlags": {
|
||||
"offset": 8,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
}
|
||||
},
|
||||
"ShimFlags": {
|
||||
"offset": 12,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
}
|
||||
},
|
||||
"BlobSize": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
}
|
||||
},
|
||||
"Padding": {
|
||||
"offset": 24,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
}
|
||||
},
|
||||
"BlobBuffer": {
|
||||
"offset": 32,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 40
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"producer": {
|
||||
"version": "0.0.1",
|
||||
"name": "dgmcdona by hand",
|
||||
"datetime": "2024-07-05T18:28:00.000000+00:00"
|
||||
},
|
||||
"format": "4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,386 @@
|
||||
{
|
||||
"symbols": {},
|
||||
"enums": {},
|
||||
"base_types": {
|
||||
"unsigned long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned long long": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned char": {
|
||||
"kind": "char",
|
||||
"size": 1,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"pointer": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
}
|
||||
},
|
||||
"user_types": {
|
||||
"_RTL_BALANCED_LINKS": {
|
||||
"fields": {
|
||||
"Parent": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"LeftChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 4
|
||||
},
|
||||
"RightChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
},
|
||||
"Balance": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
},
|
||||
"offset": 12
|
||||
},
|
||||
"Reserved": {
|
||||
"type": {
|
||||
"kind": "array",
|
||||
"count": 3,
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
},
|
||||
"offset": 12
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 16
|
||||
},
|
||||
"_RTL_AVL_TABLE": {
|
||||
"fields": {
|
||||
"BalancedRoot": {
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"OrderedPointer": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 16
|
||||
},
|
||||
"WhichOrderedElement": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 20
|
||||
},
|
||||
"NumberGenericTableElements": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 24
|
||||
},
|
||||
"DepthOfTree": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 28
|
||||
},
|
||||
"RestartKey": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 32
|
||||
},
|
||||
"DeleteCount": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 36
|
||||
},
|
||||
"CompareRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 40
|
||||
},
|
||||
"AllocateRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 44
|
||||
},
|
||||
"FreeRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 48
|
||||
},
|
||||
"TableContext": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 52
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 56
|
||||
},
|
||||
"SHIM_CACHE_HANDLE": {
|
||||
"fields": {
|
||||
"eresource": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_ERESOURCE"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"rtl_avl_table": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_AVL_TABLE"
|
||||
}
|
||||
},
|
||||
"offset": 4
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"_LARGE_INTEGER": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"QuadPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long long"
|
||||
}
|
||||
},
|
||||
"u": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "__unnamed_2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "union",
|
||||
"size": 8
|
||||
},
|
||||
"__unnamed_2": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"SHIM_CACHE_ENTRY": {
|
||||
"fields": {
|
||||
"ListEntry": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_LIST_ENTRY"
|
||||
}
|
||||
},
|
||||
"u1": {
|
||||
"offset": 8,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"u2": {
|
||||
"offset": 12,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"Path": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_UNICODE_STRING"
|
||||
}
|
||||
},
|
||||
"u3": {
|
||||
"offset": 24,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
}
|
||||
},
|
||||
"ListEntryDetail": {
|
||||
"offset": 32,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "SHIM_CACHE_ENTRY_DETAIL"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 36
|
||||
},
|
||||
"SHIM_CACHE_ENTRY_DETAIL": {
|
||||
"fields": {
|
||||
"LastModified": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "_LARGE_INTEGER"
|
||||
}
|
||||
},
|
||||
"InsertFlags": {
|
||||
"offset": 8,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
}
|
||||
},
|
||||
"ShimFlags": {
|
||||
"offset": 12,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"BlobSize": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"BlobBuffer": {
|
||||
"offset": 20,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 24
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"producer": {
|
||||
"version": "0.0.1",
|
||||
"name": "dgmcdona by hand",
|
||||
"datetime": "2024-07-05T18:28:00.000000+00:00"
|
||||
},
|
||||
"format": "4.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"symbols": {},
|
||||
"enums": {},
|
||||
"base_types": {
|
||||
"unsigned long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned long long": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned char": {
|
||||
"kind": "char",
|
||||
"size": 1,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"pointer": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
}
|
||||
},
|
||||
"user_types": {
|
||||
"_LARGE_INTEGER": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"QuadPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long long"
|
||||
}
|
||||
},
|
||||
"u": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "__unnamed_2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "union",
|
||||
"size": 8
|
||||
},
|
||||
"__unnamed_2": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"_RTL_BALANCED_LINKS": {
|
||||
"fields": {
|
||||
"Parent": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"LeftChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 4
|
||||
},
|
||||
"RightChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
},
|
||||
"Balance": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
},
|
||||
"offset": 12
|
||||
},
|
||||
"Reserved": {
|
||||
"type": {
|
||||
"kind": "array",
|
||||
"count": 3,
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
},
|
||||
"offset": 12
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 16
|
||||
},
|
||||
"_RTL_AVL_TABLE": {
|
||||
"fields": {
|
||||
"BalancedRoot": {
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"OrderedPointer": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 16
|
||||
},
|
||||
"WhichOrderedElement": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 20
|
||||
},
|
||||
"NumberGenericTableElements": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 24
|
||||
},
|
||||
"DepthOfTree": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 28
|
||||
},
|
||||
"RestartKey": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 32
|
||||
},
|
||||
"DeleteCount": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 36
|
||||
},
|
||||
"CompareRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 40
|
||||
},
|
||||
"AllocateRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 44
|
||||
},
|
||||
"FreeRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 48
|
||||
},
|
||||
"TableContext": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 52
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 56
|
||||
},
|
||||
"SHIM_CACHE_HANDLE": {
|
||||
"fields": {
|
||||
"eresource": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_ERESOURCE"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"rtl_avl_table": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_AVL_TABLE"
|
||||
}
|
||||
},
|
||||
"offset": 4
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"SHIM_CACHE_HEADER": {
|
||||
"fields": {
|
||||
"Magic": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"u1": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
},
|
||||
"offset": 4
|
||||
},
|
||||
"NumEntries": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
},
|
||||
"offset": 8
|
||||
},
|
||||
"u2": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
},
|
||||
"offset": 12
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 400
|
||||
},
|
||||
"SHIM_CACHE_ENTRY": {
|
||||
"fields": {
|
||||
"Path": {
|
||||
"type": {
|
||||
"count": 520,
|
||||
"kind": "array",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"LastModified": {
|
||||
"type": {
|
||||
"kind": "union",
|
||||
"name": "LARGE_INTEGER"
|
||||
},
|
||||
"offset": 4
|
||||
},
|
||||
"FileSize": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long long"
|
||||
},
|
||||
"offset": 8
|
||||
},
|
||||
"LastUpdate": {
|
||||
"type": {
|
||||
"kind": "union",
|
||||
"name": "LARGE_INTEGER"
|
||||
},
|
||||
"offset": 12
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 552
|
||||
},
|
||||
"_SEGMENT": {
|
||||
"fields": {
|
||||
"ControlArea": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_CONTROL_AREA"
|
||||
}
|
||||
}
|
||||
},
|
||||
"TotalNumberOfPtes": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"NonExtendedPtes": {
|
||||
"offset": 8,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"WritableUserReferences": {
|
||||
"offset": 12,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"SizeOfSegment": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"SegmentPteTemplate": {
|
||||
"offset": 24,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_MMPTE"
|
||||
}
|
||||
},
|
||||
"NumberOfCommittedPages": {
|
||||
"offset": 28,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"ExtendInfo": {
|
||||
"offset": 32,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_MMEXTEND_INFO"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SystemImageBase": {
|
||||
"offset": 36,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
}
|
||||
},
|
||||
"BasedAddress": {
|
||||
"offset": 40,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"u1": {
|
||||
"offset": 44,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"u2": {
|
||||
"offset": 48,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"PrototypePte": {
|
||||
"offset": 52,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_MMPTE"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ThePtes": {
|
||||
"offset": 60,
|
||||
"type": {
|
||||
"kind": "array",
|
||||
"count": 1,
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "nt_symbols!_MMPTE"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 64
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"producer": {
|
||||
"version": "0.0.1",
|
||||
"name": "dgmcdona by hand",
|
||||
"datetime": "2024-07-05T18:28:00.000000+00:00"
|
||||
},
|
||||
"format": "4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
{
|
||||
"symbols": {},
|
||||
"enums": {},
|
||||
"base_types": {
|
||||
"unsigned long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned long long": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned char": {
|
||||
"kind": "char",
|
||||
"size": 1,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"pointer": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
}
|
||||
},
|
||||
"user_types": {
|
||||
"_LARGE_INTEGER": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"QuadPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long long"
|
||||
}
|
||||
},
|
||||
"u": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "__unnamed_2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "union",
|
||||
"size": 8
|
||||
},
|
||||
"__unnamed_2": {
|
||||
"fields": {
|
||||
"HighPart": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"LowPart": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"_RTL_BALANCED_LINKS": {
|
||||
"fields": {
|
||||
"Parent": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"LeftChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 4
|
||||
},
|
||||
"RightChild": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 8
|
||||
},
|
||||
"Balance": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
},
|
||||
"offset": 12
|
||||
},
|
||||
"Reserved": {
|
||||
"type": {
|
||||
"kind": "array",
|
||||
"count": 3,
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
},
|
||||
"offset": 12
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 16
|
||||
},
|
||||
"_RTL_AVL_TABLE": {
|
||||
"fields": {
|
||||
"BalancedRoot": {
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"OrderedPointer": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 16
|
||||
},
|
||||
"WhichOrderedElement": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 20
|
||||
},
|
||||
"NumberGenericTableElements": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 24
|
||||
},
|
||||
"DepthOfTree": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 28
|
||||
},
|
||||
"RestartKey": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_BALANCED_LINKS"
|
||||
}
|
||||
},
|
||||
"offset": 32
|
||||
},
|
||||
"DeleteCount": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 36
|
||||
},
|
||||
"CompareRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 40
|
||||
},
|
||||
"AllocateRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 44
|
||||
},
|
||||
"FreeRoutine": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 48
|
||||
},
|
||||
"TableContext": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
},
|
||||
"offset": 52
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 56
|
||||
},
|
||||
"SHIM_CACHE_HEADER": {
|
||||
"fields": {
|
||||
"Magic": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"u1": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
},
|
||||
"offset": 4
|
||||
},
|
||||
"NumEntries": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
},
|
||||
"offset": 8
|
||||
},
|
||||
"u2": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned int"
|
||||
},
|
||||
"offset": 12
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 400
|
||||
},
|
||||
"SHIM_CACHE_ENTRY": {
|
||||
"fields": {
|
||||
"Path": {
|
||||
"type": {
|
||||
"count": 520,
|
||||
"kind": "array",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "unsigned char"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"LastModified": {
|
||||
"type": {
|
||||
"kind": "union",
|
||||
"name": "_LARGE_INTEGER"
|
||||
},
|
||||
"offset": 528
|
||||
},
|
||||
"FileSize": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long long"
|
||||
},
|
||||
"offset": 536
|
||||
},
|
||||
"LastUpdate": {
|
||||
"type": {
|
||||
"kind": "union",
|
||||
"name": "_LARGE_INTEGER"
|
||||
},
|
||||
"offset": 544
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 552
|
||||
},
|
||||
"SHIM_CACHE_HANDLE": {
|
||||
"fields": {
|
||||
"eresource": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!ERESOURCE"
|
||||
}
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"rtl_avl_table": {
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_RTL_AVL_TABLE"
|
||||
}
|
||||
},
|
||||
"offset": 4
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
},
|
||||
"_SEGMENT": {
|
||||
"fields": {
|
||||
"ControlArea": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_CONTROL_AREA"
|
||||
}
|
||||
}
|
||||
},
|
||||
"TotalNumberOfPtes": {
|
||||
"offset": 4,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"NonExtendedPtes": {
|
||||
"offset": 8,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"WritableUserReferences": {
|
||||
"offset": 12,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"SizeOfSegment": {
|
||||
"offset": 16,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"SegmentPteTemplate": {
|
||||
"offset": 24,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_MMPTE"
|
||||
}
|
||||
},
|
||||
"NumberOfCommittedPages": {
|
||||
"offset": 32,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"ExtendInfo": {
|
||||
"offset": 36,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_MMEXTEND_INFO"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SystemImageBase": {
|
||||
"offset": 40,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "void"
|
||||
}
|
||||
}
|
||||
},
|
||||
"BasedAddress": {
|
||||
"offset": 44,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"u1": {
|
||||
"offset": 48,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"u2": {
|
||||
"offset": 52,
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "long"
|
||||
}
|
||||
},
|
||||
"PrototypePte": {
|
||||
"offset": 56,
|
||||
"type": {
|
||||
"kind": "pointer",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_MMPTE"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ThePtes": {
|
||||
"offset": 64,
|
||||
"type": {
|
||||
"kind": "array",
|
||||
"count": 1,
|
||||
"subtype": {
|
||||
"kind": "base",
|
||||
"name": "nt_symbols!_MMPTE"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 72
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"producer": {
|
||||
"version": "0.0.1",
|
||||
"name": "dgmcdona by hand",
|
||||
"datetime": "2024-07-05T18:28:00.000000+00:00"
|
||||
},
|
||||
"format": "4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
{
|
||||
"symbols": {},
|
||||
"enums": {},
|
||||
"base_types": {
|
||||
"unsigned long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned long long": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned char": {
|
||||
"kind": "char",
|
||||
"size": 1,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"pointer": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
}
|
||||
},
|
||||
"user_types": {
|
||||
"_UNLOADED_DRIVER": {
|
||||
"fields": {
|
||||
"Name": {
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_UNICODE_STRING"
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"StartAddress": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
},
|
||||
"offset": 16
|
||||
},
|
||||
"EndAddress": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
},
|
||||
"offset": 24
|
||||
},
|
||||
"CurrentTime": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
},
|
||||
"offset": 32
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 40
|
||||
},
|
||||
"_UNLOADED_DRIVERS": {
|
||||
"fields": {
|
||||
"UnloadedDrivers": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"count": 1,
|
||||
"kind": "array",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_UNLOADED_DRIVER"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 8
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"producer": {
|
||||
"version": "0.0.1",
|
||||
"name": "Dave Lassalle by hand",
|
||||
"datetime": "2024-06-19T17:57:16.394003"
|
||||
},
|
||||
"format": "4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
{
|
||||
"symbols": {},
|
||||
"enums": {},
|
||||
"base_types": {
|
||||
"unsigned long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned long long": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned char": {
|
||||
"kind": "char",
|
||||
"size": 1,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"pointer": {
|
||||
"kind": "int",
|
||||
"size": 8,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned int": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"unsigned short": {
|
||||
"kind": "int",
|
||||
"size": 2,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
},
|
||||
"long": {
|
||||
"kind": "int",
|
||||
"size": 4,
|
||||
"signed": false,
|
||||
"endian": "little"
|
||||
}
|
||||
},
|
||||
"user_types": {
|
||||
"_UNLOADED_DRIVER": {
|
||||
"fields": {
|
||||
"Name": {
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"name": "nt_symbols!_UNICODE_STRING"
|
||||
},
|
||||
"offset": 0
|
||||
},
|
||||
"StartAddress": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 8
|
||||
},
|
||||
"EndAddress": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long"
|
||||
},
|
||||
"offset": 12
|
||||
},
|
||||
"CurrentTime": {
|
||||
"type": {
|
||||
"kind": "base",
|
||||
"name": "unsigned long long"
|
||||
},
|
||||
"offset": 16
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 24
|
||||
},
|
||||
"_UNLOADED_DRIVERS": {
|
||||
"fields": {
|
||||
"UnloadedDrivers": {
|
||||
"offset": 0,
|
||||
"type": {
|
||||
"count": 1,
|
||||
"kind": "array",
|
||||
"subtype": {
|
||||
"kind": "struct",
|
||||
"name": "_UNLOADED_DRIVER"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 4
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"producer": {
|
||||
"version": "0.0.1",
|
||||
"name": "Dave Lassalle by hand",
|
||||
"datetime": "2024-06-19T17:57:16.394003"
|
||||
},
|
||||
"format": "4.0.0"
|
||||
}
|
||||
}
|
||||
@@ -114,6 +114,24 @@ is_windows_xp = OsDistinguisher(
|
||||
],
|
||||
)
|
||||
|
||||
is_windows_xp_sp2 = OsDistinguisher(
|
||||
version_check=lambda x: (5, 1) <= x < (5, 2),
|
||||
fallback_checks=[
|
||||
("KdCopyDataBlock", None, False),
|
||||
("_MMFREE_POOL_ENTRY", None, False),
|
||||
("_HANDLE_TABLE", "HandleCount", True),
|
||||
],
|
||||
)
|
||||
|
||||
is_windows_xp_sp3 = OsDistinguisher(
|
||||
version_check=lambda x: (5, 1) <= x < (5, 2),
|
||||
fallback_checks=[
|
||||
("KdCopyDataBlock", None, False),
|
||||
("_MMFREE_POOL_ENTRY", None, True),
|
||||
("_HANDLE_TABLE", "HandleCount", True),
|
||||
],
|
||||
)
|
||||
|
||||
is_xp_or_2003 = OsDistinguisher(
|
||||
version_check=lambda x: (5, 1) <= x < (6, 0),
|
||||
fallback_checks=[
|
||||
@@ -122,6 +140,15 @@ is_xp_or_2003 = OsDistinguisher(
|
||||
],
|
||||
)
|
||||
|
||||
is_2003 = OsDistinguisher(
|
||||
version_check=lambda x: (5, 2) <= x < (5, 3),
|
||||
fallback_checks=[
|
||||
("KdCopyDataBlock", None, False),
|
||||
("_HANDLE_TABLE", "HandleCount", True),
|
||||
("_MM_AVL_TABLE", None, True),
|
||||
],
|
||||
)
|
||||
|
||||
is_win10_up_to_15063 = OsDistinguisher(
|
||||
version_check=lambda x: (10, 0) <= x < (10, 0, 15063),
|
||||
fallback_checks=[
|
||||
@@ -141,6 +168,15 @@ is_win10_15063 = OsDistinguisher(
|
||||
],
|
||||
)
|
||||
|
||||
is_win10_15063_or_later = OsDistinguisher(
|
||||
version_check=lambda x: x >= (10, 0, 15063),
|
||||
fallback_checks=[
|
||||
("ObHeaderCookie", None, True),
|
||||
("_HANDLE_TABLE", "HandleCount", False),
|
||||
("_EPROCESS", "KeepAliveCounter", False),
|
||||
],
|
||||
)
|
||||
|
||||
is_win10_16299_or_later = OsDistinguisher(
|
||||
version_check=lambda x: x >= (10, 0, 16299),
|
||||
fallback_checks=[
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# PYTHON_ARGCOMPLETE_OK
|
||||
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user