diff options
-rw-r--r-- | src/utils/winreg.py | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/src/utils/winreg.py b/src/utils/winreg.py new file mode 100644 index 0000000..ed2d5c6 --- /dev/null +++ b/src/utils/winreg.py @@ -0,0 +1,114 @@ +# +# Copyright (C) 2022 Soleta Networks <info@soleta.eu> +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the +# Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +import libhivexmod +import hivex +from enum import Enum +from src.log import OgError +from uuid import UUID + + +WINDOWS_HIVES_PATH = '/Windows/System32/config' +WINDOWS_HIVE_SOFTWARE = f'{WINDOWS_HIVES_PATH}/SOFTWARE' +WINDOWS_HIVE_SYSTEM = f'{WINDOWS_HIVES_PATH}/SYSTEM' + +WINDOWS_HIVE_ENCODING = 'utf-16-le' + + +class RegistryType(Enum): + NONE = 0 + SZ = 1 + EXPAND_SZ = 2 + BINARY = 3 + DWORD = 4 + DWORD_BIG_ENDIAN = 5 + LINK = 6 + MULTI_SZ = 7 + RESOURCE_LIST = 8 + FULL_RESOURCE_DESCRIPTIOR = 9 + RESOURCE_REQUIREMENTS_LISTS = 10 + QWORD = 11 + + +def get_value_from_node(hive, node, value): + type_node_value = hive.node_get_value(node, value) + + val = None + + val_type = hive.value_type(type_node_value)[0] + rtype = RegistryType(val_type) + + if rtype == RegistryType.SZ: + val = hive.value_string(type_node_value) + elif rtype == RegistryType.MULTI_SZ: + val = hive.value_multiple_strings(type_node_value) + elif rtype == RegistryType.DWORD: + val = hive.value_dword(type_node_value) + elif rtype == RegistryType.QWORD: + val = hive.value_qword(type_node_value) + elif rtype == RegistryType.BINARY: + _, val = hive.value_value(type_node_value) + + if not val: + raise OgError(f'No valid value found for the node {hive.node_name(node)}') + + return val + + +def check_hive_consistency(hive_path): + """ + The Hivex class tries to call libhivexmod.close in the __del__ method. + That is not reliable as trying to free resources from a corrupted hivex + file will not work, we first check if the hivex can be loaded. + """ + try: + h = libhivexmod.open(hive_path, 0) + libhivexmod.close(h) + except RuntimeError as e: + raise OgError(f'Unable to load the registry hive at {hive_path}: {e}') from e + + +def hive_handler_open(hive_path, write): + check_hive_consistency(hive_path) + + h = hivex.Hivex(hive_path, write = write) + + if not h.root(): + raise OgError(f'Unable to find the root node for hive at {hive_path}') from e + return h + + +def get_node_child(hive, node, name): + child_node = hive.node_get_child(node, name) + + if not child_node: + raise OgError(f'Could not find child node {name} in {hive.node_name(node)}') + + return child_node + + +def get_node_child_from_path(hive, node, path): + path_components = path.split('/') + + child_node = node + for node_name in path_components: + child_node = get_node_child(hive, child_node, node_name) + + return child_node + + +def uuid_to_bytes(uuid): + uuid = uuid.replace('-', '') + + group0 = f'{uuid[6:8]}{uuid[4:6]}{uuid[2:4]}{uuid[0:2]}' + group1 = f'{uuid[10:12]}{uuid[8:10]}' + group2 = f'{uuid[14:16]}{uuid[12:14]}' + group3 = uuid[16:20] + group4 = uuid[20:32] + res = f'{group0}-{group1}-{group2}-{group3}-{group4}' + return UUID(res).bytes |