summaryrefslogtreecommitdiffstats
path: root/src/utils/winreg.py
blob: 0b220974a4fb15c99e91d3a88b009f6d448e663c (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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#
# 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
from src.utils.disk import *
from src.utils.uefi import is_uefi_supported


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


def get_disk_id_bytes(disk):
    disk_id = get_disk_id(disk)

    if is_uefi_supported():
        return uuid_to_bytes(disk_id)

    return bytes.fromhex(disk_id)[::-1]


def get_part_id_bytes(disk, partition):
    if is_uefi_supported():
        part_id = get_partition_id(disk, partition)
        return uuid_to_bytes(part_id)

    partition_start_offset = get_partition_start_offset(disk, partition)
    sector_size = get_sector_size(disk)
    byte_offset = partition_start_offset * sector_size
    byte_offset = "{0:016x}".format(byte_offset)
    return bytes.fromhex(byte_offset)[::-1]