summaryrefslogtreecommitdiffstats
path: root/src/utils/winreg.py
blob: ed2d5c624feece4e4682128597c0c9d5d7fed523 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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