From bb03e92840b61385949507bab372ca28c5b06379 Mon Sep 17 00:00:00 2001 From: Alejandro Sirgo Rica Date: Wed, 17 Apr 2024 11:26:21 +0200 Subject: utils: add win edit registry utilities Add winreg.py to the utils folder. Implement hive enum types, hive handler validation and validated get_* functions for nodes and registry values. Implement the utility hive operations through the Hivex library. This serves as preparatory work for BCD manipulation but it also has potential to improve registry usage in previous code. UCS-2 Little Endian is the prefered windows registry text encoding for binary content. Define a WINDOWS_HIVE_ENCODING global variable to use when encoding string to write in the win registry. This commit is preparatory work for the new native postinstall code. --- src/utils/winreg.py | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 src/utils/winreg.py (limited to 'src/utils') 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 +# +# 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 -- cgit v1.2.3-18-g5258