Skip to content

Commit

Permalink
Merge pull request volatilityfoundation#1500 from volatilityfoundatio…
Browse files Browse the repository at this point in the history
…n/issue_1469_cachedump_exception

Exception handling in registry-related code
  • Loading branch information
ikelos authored Jan 3, 2025
2 parents 66eb161 + c8e67e5 commit cedc0b0
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 22 deletions.
2 changes: 1 addition & 1 deletion volatility3/framework/constants/_version.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# We use the SemVer 2.0.0 versioning scheme
VERSION_MAJOR = 2 # Number of releases of the library with a breaking change
VERSION_MINOR = 14 # Number of changes that only add to the interface
VERSION_MINOR = 15 # Number of changes that only add to the interface
VERSION_PATCH = 0 # Number of changes that do not change the interface
VERSION_SUFFIX = ""

Expand Down
10 changes: 5 additions & 5 deletions volatility3/framework/plugins/windows/amcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ def indented(
amcache.get_key("Root\\InventoryDriverBinary") # type: ignore
)
)
except KeyError:
except (KeyError, registry.RegistryFormatException):
# Registry key not found
pass

Expand All @@ -554,7 +554,7 @@ def indented(
amcache.get_key("Root\\Programs")
) # type: ignore
}
except KeyError:
except (KeyError, registry.RegistryFormatException):
programs = {}

try:
Expand All @@ -564,7 +564,7 @@ def indented(
),
key=_entry_sort_key,
)
except KeyError:
except (KeyError, registry.RegistryFormatException):
files = []

for program_id, file_entries in itertools.groupby(
Expand Down Expand Up @@ -593,7 +593,7 @@ def indented(
amcache.get_key("Root\\InventoryApplication") # type: ignore
)
)
except KeyError:
except (KeyError, registry.RegistryFormatException):
programs = {}

try:
Expand All @@ -603,7 +603,7 @@ def indented(
),
key=_entry_sort_key,
)
except KeyError:
except (KeyError, registry.RegistryFormatException):
files = []

for program_id, file_entries in itertools.groupby(
Expand Down
11 changes: 8 additions & 3 deletions volatility3/framework/plugins/windows/cachedump.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from Crypto.Cipher import ARC4, AES
from Crypto.Hash import HMAC

from volatility3.framework import interfaces, renderers
from volatility3.framework import interfaces, renderers, exceptions
from volatility3.framework.configuration import requirements
from volatility3.framework.layers import registry
from volatility3.framework.symbols.windows import versions
Expand Down Expand Up @@ -140,9 +140,14 @@ def _generator(self, syshive, sechive):
if cache_item.Name == "NL$Control":
continue

data = sechive.read(cache_item.Data + 4, cache_item.DataLength)
if data is None:
try:
data = sechive.read(cache_item.Data + 4, cache_item.DataLength)
except exceptions.InvalidAddressException:
continue

if not data:
continue

(
uname_len,
domain_len,
Expand Down
2 changes: 1 addition & 1 deletion volatility3/framework/plugins/windows/hashdump.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ def get_hive_key(cls, hive: registry.RegistryHive, key: str):
try:
if hive:
result = hive.get_key(key)
except KeyError:
except (KeyError, registry.RegistryFormatException):
vollog.info(
f"Unable to load the required registry key {hive.get_name()}\\{key} from this memory image"
)
Expand Down
7 changes: 5 additions & 2 deletions volatility3/framework/plugins/windows/lsadump.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from Crypto.Cipher import ARC4, DES, AES
from Crypto.Hash import MD5, SHA256

from volatility3.framework import interfaces, renderers
from volatility3.framework import interfaces, renderers, exceptions
from volatility3.framework.configuration import requirements
from volatility3.framework.layers import registry
from volatility3.framework.symbols.windows import versions
Expand Down Expand Up @@ -81,7 +81,10 @@ def get_lsa_key(
if not enc_reg_value:
return None

obf_lsa_key = sechive.read(enc_reg_value.Data + 4, enc_reg_value.DataLength)
try:
obf_lsa_key = sechive.read(enc_reg_value.Data + 4, enc_reg_value.DataLength)
except exceptions.InvalidAddressException:
return None

if not obf_lsa_key:
return None
Expand Down
55 changes: 45 additions & 10 deletions volatility3/framework/symbols/windows/extensions/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,20 @@ class CM_KEY_NODE(objects.StructType):
"""Extension to allow traversal of registry keys."""

def get_volatile(self) -> bool:
"""
Returns a bool indicating whether or not the key is volatile.
Raises TypeError if the key was not instantiated on a RegistryHive layer
"""
if not isinstance(self._context.layers[self.vol.layer_name], RegistryHive):
raise ValueError(
"Cannot determine volatility of registry key without an offset in a RegistryHive layer"
)
raise TypeError("CM_KEY_NODE was not instantiated on a RegistryHive layer")
return bool(self.vol.offset & 0x80000000)

def get_subkeys(self) -> Iterator["CM_KEY_NODE"]:
"""Returns a list of the key nodes."""
"""Returns a list of the key nodes.
Raises TypeError if the key was not instantiated on a RegistryHive layer
"""
hive = self._context.layers[self.vol.layer_name]
if not isinstance(hive, RegistryHive):
raise TypeError("CM_KEY_NODE was not instantiated on a RegistryHive layer")
Expand Down Expand Up @@ -222,7 +228,10 @@ def _get_subkeys_recursive(
yield from self._get_subkeys_recursive(hive, subnode)

def get_values(self) -> Iterator["CM_KEY_VALUE"]:
"""Returns a list of the Value nodes for a key."""
"""Returns a list of the Value nodes for a key.
Raises TypeError if the key was not instantiated on a RegistryHive layer
"""
hive = self._context.layers[self.vol.layer_name]
if not isinstance(hive, RegistryHive):
raise TypeError("CM_KEY_NODE was not instantiated on a RegistryHive layer")
Expand Down Expand Up @@ -251,6 +260,11 @@ def get_name(self) -> interfaces.objects.ObjectInterface:
return self.Name.cast("string", max_length=namelength, encoding="latin-1")

def get_key_path(self) -> str:
"""
Returns the full path to this registry key.
Raises TypeError if the key was not instantiated on a RegistryHive layer
"""
reg = self._context.layers[self.vol.layer_name]
if not isinstance(reg, RegistryHive):
raise TypeError("Key was not instantiated on a RegistryHive layer")
Expand All @@ -276,7 +290,16 @@ def get_type(self) -> RegValueTypes:
return RegValueTypes(self.Type)

def decode_data(self) -> Union[int, bytes]:
"""Properly decodes the data associated with the value node"""
"""
Properly decodes the data associated with the value node.
If an InvalidAddressException occurs when reading data from the
underlying RegistryHive layer, the data will be padded with null bytes
of the same length.
Raises ValueError if the data cannot be read
Raises TypeError if the class was not instantiated on a RegistryHive layer
"""
# Determine if the data is stored inline
datalen = self.DataLength
data = b""
Expand Down Expand Up @@ -310,14 +333,26 @@ def decode_data(self) -> Union[int, bytes]:
and block_offset < layer.maximum_address
):
amount = min(BIG_DATA_MAXLEN, datalen)
data += layer.read(
offset=layer.get_cell(block_offset).vol.offset, length=amount
)
try:
data += layer.read(
offset=layer.get_cell(block_offset).vol.offset,
length=amount,
)
except exceptions.InvalidAddressException:
vollog.debug(
f"Failed to read {amount:x} bytes of data, padding with {amount:x}"
)
datalen -= amount
else:
# Suspect Data actually points to a Cell,
# but the length at the start could be negative so just adding 4 to jump past it
data = layer.read(self.Data + 4, datalen)
try:
data = layer.read(self.Data + 4, datalen)
except exceptions.InvalidAddressException:
vollog.debug(
f"Failed to read {datalen:x} bytes of data, returning {datalen:x} null bytes"
)
data = b"\x00" * datalen

if self.get_type() == RegValueTypes.REG_DWORD:
if len(data) != struct.calcsize("<L"):
Expand Down

0 comments on commit cedc0b0

Please sign in to comment.