1 | import subprocess |
---|
2 | import os |
---|
3 | import re |
---|
4 | |
---|
5 | from engine.FileLib import * |
---|
6 | from engine.SystemLib import * |
---|
7 | |
---|
8 | def chntpw(*args): |
---|
9 | chntpw_path = subprocess.check_output(['which', 'drbl-chntpw']).decode().strip() |
---|
10 | if not chntpw_path: |
---|
11 | chntpw_path = subprocess.check_output(['which', 'chntpw']).decode().strip() |
---|
12 | subprocess.run([chntpw_path, '-e'] + list(args), timeout=5) |
---|
13 | |
---|
14 | def ogAddRegistryKey(path_mountpoint, str_hive, str_key): |
---|
15 | # Variables locales. |
---|
16 | FILE = ogGetHivePath(path_mountpoint, str_hive) |
---|
17 | if not FILE: |
---|
18 | return |
---|
19 | |
---|
20 | # Añadir nueva clave. |
---|
21 | chntpw(FILE, 'cd', str_key.rsplit('\\', 1)[0]) |
---|
22 | chntpw(FILE, 'nk', str_key.rsplit('\\', 1)[-1]) |
---|
23 | chntpw(FILE, 'q') |
---|
24 | chntpw(FILE, 'y') |
---|
25 | |
---|
26 | def ogAddRegistryValue(path_mountpoint, str_hive, str_key, str_valuename, str_valuetype=''): |
---|
27 | # Variables locales. |
---|
28 | FILE = ogGetHivePath(path_mountpoint, str_hive) |
---|
29 | if not FILE: |
---|
30 | return |
---|
31 | |
---|
32 | # Determine the value type. |
---|
33 | if str_valuetype.upper() == 'STRING' or str_valuetype == '': |
---|
34 | TYPE = 1 |
---|
35 | elif str_valuetype.upper() == 'BINARY': |
---|
36 | TYPE = 3 |
---|
37 | elif str_valuetype.upper() == 'DWORD': |
---|
38 | TYPE = 4 |
---|
39 | else: |
---|
40 | ogRaiseError(OG_ERR_OUTOFLIMIT, str_valuetype) |
---|
41 | return |
---|
42 | |
---|
43 | # Add the registry value. |
---|
44 | chntpw(FILE, 'cd', str_key.rsplit('\\', 1)[0]) |
---|
45 | chntpw(FILE, 'nv', str_valuename.rsplit('\\', 1)[-1], TYPE) |
---|
46 | chntpw(FILE, 'q') |
---|
47 | chntpw(FILE, 'y') |
---|
48 | |
---|
49 | def ogDeleteRegistryKey(path_mountpoint, str_hive, str_key): |
---|
50 | # Variables locales. |
---|
51 | FILE = ogGetHivePath(path_mountpoint, str_hive) |
---|
52 | if not FILE: |
---|
53 | return |
---|
54 | |
---|
55 | # Delete the registry key. |
---|
56 | subprocess.run(['chntpw', FILE], input=f"cd {str_key.rsplit('\\', 1)[0]}\ndk {str_key.rsplit('\\', 1)[-1]}\nq\ny\n".encode(), timeout=5) |
---|
57 | |
---|
58 | def ogDeleteRegistryValue(path_mountpoint, str_hive, str_valuename): |
---|
59 | # Variables locales. |
---|
60 | FILE = ogGetHivePath(path_mountpoint, str_hive) |
---|
61 | if not FILE: |
---|
62 | return |
---|
63 | |
---|
64 | # Delete the registry value. |
---|
65 | chntpw(FILE, 'cd', str_valuename.rsplit('\\', 1)[0]) |
---|
66 | chntpw(FILE, 'dv', str_valuename.rsplit('\\', 1)[-1]) |
---|
67 | chntpw(FILE, 'q') |
---|
68 | chntpw(FILE, 'y') |
---|
69 | |
---|
70 | def ogGetHivePath(path_mountpoint, str_hive): |
---|
71 | # Variables locales. |
---|
72 | FILE = None |
---|
73 | |
---|
74 | # Camino del fichero de registro de usuario o de sistema (de menor a mayor prioridad). |
---|
75 | FILE = ogGetPath(f"/{path_mountpoint}/Windows/System32/config/{str_hive}") |
---|
76 | if not FILE: |
---|
77 | FILE = ogGetPath(f"/{path_mountpoint}/Users/{str_hive}/NTUSER.DAT") |
---|
78 | if not FILE: |
---|
79 | FILE = ogGetPath(f"/{path_mountpoint}/winnt/system32/config/{str_hive}") |
---|
80 | if not FILE: |
---|
81 | FILE = ogGetPath(f"/{path_mountpoint}/Documents and Settings/{str_hive}/NTUSER.DAT") |
---|
82 | if FILE and os.path.isfile(FILE): |
---|
83 | return FILE |
---|
84 | else: |
---|
85 | ogRaiseError(OG_ERR_NOTFOUND, f"{path_mountpoint} {str_hive}") |
---|
86 | return None |
---|
87 | |
---|
88 | def ogGetRegistryValue(path_mountpoint, str_hive, str_valuename): |
---|
89 | # Variables locales. |
---|
90 | FILE = ogGetHivePath(path_mountpoint, str_hive) |
---|
91 | if not FILE: |
---|
92 | return |
---|
93 | |
---|
94 | # Devolver el dato del valor de registro. |
---|
95 | chntpw_cmd = f''' |
---|
96 | chntpw "{FILE}" << EOT 2> /dev/null | awk '/> Value/ {{ |
---|
97 | if (index($0, "REG_BINARY") > 0) {{ |
---|
98 | data="" |
---|
99 | }} else {{ |
---|
100 | getline |
---|
101 | data=$0 |
---|
102 | }} |
---|
103 | }} |
---|
104 | /^:[0-9A-F]+ / {{ |
---|
105 | data=data""substr($0, 9, 48) |
---|
106 | }} |
---|
107 | END {{ |
---|
108 | print data |
---|
109 | }}' |
---|
110 | cd {str_valuename.rsplit('\\', 1)[0]} |
---|
111 | cat {str_valuename.rsplit('\\', 1)[-1]} |
---|
112 | q |
---|
113 | EOT |
---|
114 | ''' |
---|
115 | subprocess.run(chntpw_cmd, shell=True, timeout=5) |
---|
116 | |
---|
117 | def ogListRegistryKeys(path_mountpoint, str_hive, str_key): |
---|
118 | # Variables locales. |
---|
119 | FILE = ogGetHivePath(path_mountpoint, str_hive) |
---|
120 | if not FILE: |
---|
121 | return |
---|
122 | |
---|
123 | # Devolver la lista de claves de registro. |
---|
124 | chntpw_cmd = f''' |
---|
125 | chntpw "{FILE}" << EOT 2> /dev/null | awk 'BEGIN {{FS="[<>]"}} $1~/^ $/ {{print $2}}' |
---|
126 | ls {str_key} |
---|
127 | q |
---|
128 | EOT |
---|
129 | ''' |
---|
130 | subprocess.run(chntpw_cmd, shell=True, timeout=5) |
---|
131 | |
---|
132 | def ogListRegistryValues(path_mountpoint, str_hive, str_key): |
---|
133 | # Variables locales. |
---|
134 | FILE = ogGetHivePath(path_mountpoint, str_hive) |
---|
135 | if not FILE: |
---|
136 | return |
---|
137 | |
---|
138 | # Devolver la lista de valores de registro. |
---|
139 | chntpw_cmd = f''' |
---|
140 | chntpw "{FILE}" << EOT 2> /dev/null | awk 'BEGIN {{FS="[<>]"}} $1~/REG_/ {{print $2}}' |
---|
141 | ls {str_key} |
---|
142 | q |
---|
143 | EOT |
---|
144 | ''' |
---|
145 | subprocess.run(chntpw_cmd, shell=True, timeout=5) |
---|
146 | |
---|
147 | def ogSetRegistryValue(path_mountpoint, str_hive, str_valuename, str_data): |
---|
148 | # Variables locales. |
---|
149 | FILE = ogGetHivePath(path_mountpoint, str_hive) |
---|
150 | if not FILE: |
---|
151 | return |
---|
152 | |
---|
153 | # Fichero temporal para componer la entrada al comando "chntpw". |
---|
154 | tmpfile = "/tmp/chntpw$$" |
---|
155 | try: |
---|
156 | # Comprobar tipo de datos del valor del registro. |
---|
157 | with open(tmpfile, 'w') as f: |
---|
158 | f.write(f"ls {str_valuename.rsplit('\\', 1)[0]}\nq\n") |
---|
159 | output = subprocess.check_output(['chntpw', FILE], input=open(tmpfile, 'rb'), stderr=subprocess.DEVNULL).decode() |
---|
160 | if f"BINARY.*<{str_valuename.rsplit('\\', 1)[-1]}>" in output: |
---|
161 | # Procesar tipo binario (incluir nº de bytes y líneas de 16 parejas hexadecimales). |
---|
162 | if not re.match(r'^([0-9A-F]{2} )*$', str_data): |
---|
163 | ogRaiseError(OG_ERR_FORMAT, f'"{str_data}"') |
---|
164 | return |
---|
165 | n = len(str_data) + 1 |
---|
166 | with open(tmpfile, 'w') as f: |
---|
167 | f.write(f"cd {str_valuename.rsplit('\\', 1)[0]}\ned {str_valuename.rsplit('\\', 1)[-1]}\n{int(n/3)}\n") |
---|
168 | for i in range(0, n, 48): |
---|
169 | f.write(f":{i//3:05x} {str_data[i:i+48]}\n") |
---|
170 | f.write("s\nq\ny\n") |
---|
171 | else: |
---|
172 | # Cambiar el dato del valor de registro para cadenas y bytes. |
---|
173 | with open(tmpfile, 'w') as f: |
---|
174 | f.write(f"cd {str_valuename.rsplit('\\', 1)[0]}\ned {str_valuename.rsplit('\\', 1)[-1]}\n{str_data}\nq\ny\n") |
---|
175 | |
---|
176 | # Aplicar cambios. |
---|
177 | subprocess.run(['chntpw', FILE], input=open(tmpfile, 'rb'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) |
---|
178 | finally: |
---|
179 | os.remove(tmpfile) |
---|