summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlejandro Sirgo Rica <asirgo@soleta.eu>2024-04-17 11:26:21 +0200
committerAlejandro Sirgo Rica <asirgo@soleta.eu>2024-07-29 15:07:22 +0200
commitbb03e92840b61385949507bab372ca28c5b06379 (patch)
tree832707d7c7b6be36a924ba7be4f9e08e89dc5351 /src
parent7ab965c0b57bf829c42ed54b84213d2c01f135b3 (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/utils/winreg.py114
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