381 lines
14 KiB
Python
381 lines
14 KiB
Python
#/**
|
|
#@file RegistryLib.py
|
|
#@brief Librería o clase Registry
|
|
#@class Boot
|
|
#@brief Funciones para gestión del registro de Windows.
|
|
#@warning License: GNU GPLv3+
|
|
#*/
|
|
|
|
import subprocess
|
|
import os
|
|
import re
|
|
import shutil
|
|
import tempfile
|
|
|
|
import ogGlobals
|
|
import SystemLib
|
|
import FileLib
|
|
|
|
# Función ficticia para lanzar chntpw con timeout de 5 s., evitando cuelgues del programa.
|
|
chntpw_exe = shutil.which ('drbl-chntpw') or shutil.which ('chntpw')
|
|
def chntpw (hivefile, input_file):
|
|
with open (input_file, 'r') as fd:
|
|
input_contents = fd.read()
|
|
return subprocess.run ([chntpw_exe, '-e', hivefile], timeout=5, input=input_contents, capture_output=True, text=True).stdout
|
|
|
|
## en el codigo bash aparecen "${3%\\*}" y "${3##*\\}" varias veces
|
|
## ${3%\\*} es el "dirname" de una key del registro
|
|
## ${3##*\\} es el "basename"
|
|
def _split_k (k):
|
|
k_elems = k.split ('\\')
|
|
k_dirname = '\\'.join (k_elems[0:-1])
|
|
k_basename = k_elems[-1]
|
|
return k_dirname, k_basename
|
|
|
|
#/**
|
|
# ogAddRegistryKey path_mountpoint str_hive str_keyname
|
|
#@brief Añade una nueva clave al registro de Windows.
|
|
#@param path_mountpoint directorio donde está montado el sistema Windows
|
|
#@param str_hive sección del registro
|
|
#@param str_keyname nombre de la clave
|
|
#@return (nada)
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Fichero de registro no encontrado.
|
|
#@note hive = { default, sam, security, software, system, components }
|
|
#@warning Requisitos: chntpw
|
|
#@warning El sistema de archivos de Windows debe estar montada previamente.
|
|
#*/ ##
|
|
def ogAddRegistryKey (mntpt, hive, k):
|
|
hivefile = ogGetHivePath (mntpt, hive)
|
|
if not hivefile: return
|
|
|
|
k_dirname, k_basename = _split_k (k)
|
|
|
|
with tempfile.NamedTemporaryFile (delete_on_close=False, prefix='chntpw-', mode='w') as f:
|
|
f.write (f'cd {k_dirname}\n')
|
|
f.write (f'nk {k_basename}\n')
|
|
f.write ('q\ny\n')
|
|
f.close()
|
|
chntpw (hivefile, f.name)
|
|
os.remove (f.name)
|
|
|
|
#/**
|
|
# ogAddRegistryValue path_mountpoint str_hive str_valuename [str_valuetype]
|
|
#@brief Añade un nuevo valor al registro de Windows, indicando su tipo de datos.
|
|
#@param path_mountpoint directorio donde está montado el sistema Windows
|
|
#@param str_hive sección del registro
|
|
#@param str_valuename nombre del valor
|
|
#@param str_valuetype tipo de datos del valor (opcional)
|
|
#@return (nada)
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Fichero de registro no encontrado.
|
|
#@note hive = { DEFAULT, SAM, SECURITY, SOFTWARE, SYSTEM, COMPONENTS }
|
|
#@note valuetype = { STRING, BINARY, DWORD }, por defecto: STRING
|
|
#@warning Requisitos: chntpw
|
|
#@warning El sistema de archivos de Windows debe estar montada previamente.
|
|
#*/ ##
|
|
#ogAddRegistryValue ('/mnt/sda1', 'SOFTWARE', '\Microsoft\NewKey\Value1') ## type STRING by default
|
|
#ogAddRegistryValue ('/mnt/sda1', 'SOFTWARE', '\Microsoft\NewKey\Value1', 'STRING')
|
|
#ogAddRegistryValue ('/mnt/sda1', 'SOFTWARE', '\Microsoft\NewKey\Value1', 'BINARY')
|
|
#ogAddRegistryValue ('/mnt/sda1', 'SOFTWARE', '\Microsoft\NewKey\Value1', 'DWORD')
|
|
def ogAddRegistryValue (mntpt, hive, k, vtype='STRING'):
|
|
hivefile = ogGetHivePath (mntpt, hive)
|
|
if not hivefile: return
|
|
|
|
k_dirname, k_basename = _split_k (k)
|
|
|
|
# Determine the value type.
|
|
if 'STRING' == vtype.upper(): TYPE = 1
|
|
elif 'BINARY' == vtype.upper(): TYPE = 3
|
|
elif 'DWORD' == vtype.upper(): TYPE = 4
|
|
else:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_OUTOFLIMIT, vtype)
|
|
return
|
|
|
|
with tempfile.NamedTemporaryFile (delete_on_close=False, prefix='chntpw-', mode='w') as f:
|
|
f.write (f'cd {k_dirname}\n')
|
|
f.write (f'nv {TYPE} {k_basename}\n')
|
|
f.write ('q\ny\n')
|
|
f.close()
|
|
chntpw (hivefile, f.name)
|
|
os.remove (f.name)
|
|
|
|
|
|
#/**
|
|
# ogDeleteRegistryKey path_mountpoint str_hive str_keyname
|
|
#@brief Elimina una clave del registro de Windows con todo su contenido.
|
|
#@param path_mountpoint directorio donde está montado el sistema Windows
|
|
#@param str_hive sección del registro
|
|
#@param str_keyname nombre de la clave
|
|
#@return (nada)
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Fichero de registro no encontrado.
|
|
#@note hive = { default, sam, security, software, system, components }
|
|
#@warning Requisitos: chntpw
|
|
#@warning El sistema de archivos de Windows debe estar montada previamente.
|
|
#@warning La clave debe estar vacía para poder ser borrada.
|
|
#*/ ##
|
|
def ogDeleteRegistryKey (mntpt, hive, k):
|
|
hivefile = ogGetHivePath (mntpt, hive)
|
|
if not hivefile: return
|
|
|
|
k_dirname, k_basename = _split_k (k)
|
|
|
|
with tempfile.NamedTemporaryFile (delete_on_close=False, prefix='chntpw-', mode='w') as f:
|
|
f.write (f'cd {k_dirname}\n')
|
|
f.write (f'dk {k_basename}\n')
|
|
f.write ('q\ny\n')
|
|
f.close()
|
|
chntpw (hivefile, f.name)
|
|
os.remove (f.name)
|
|
|
|
|
|
#/**
|
|
# ogDeleteRegistryValue path_mountpoint str_hive str_valuename
|
|
#@brief Elimina un valor del registro de Windows.
|
|
#@param path_mountpoint directorio donde está montado el sistema Windows
|
|
#@param str_hive sección del registro
|
|
#@param str_valuename nombre del valor
|
|
#@return (nada)
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Fichero de registro no encontrado.
|
|
#@note hive = { default, sam, security, software, system, components }
|
|
#@warning Requisitos: chntpw
|
|
#@warning El sistema de archivos de Windows debe estar montada previamente.
|
|
#*/ ##
|
|
#ogDeleteRegistryValue ('/mnt/sda1', 'SOFTWARE', '\Microsoft\NewKey\Value1')
|
|
def ogDeleteRegistryValue (mntpt, hive, k):
|
|
hivefile = ogGetHivePath (mntpt, hive)
|
|
if not hivefile: return
|
|
|
|
k_dirname, k_basename = _split_k (k)
|
|
|
|
with tempfile.NamedTemporaryFile (delete_on_close=False, prefix='chntpw-', mode='w') as f:
|
|
f.write (f'cd {k_dirname}\n')
|
|
f.write (f'dv {k_basename}\n')
|
|
f.write ('q\ny\n')
|
|
f.close()
|
|
chntpw (hivefile, f.name)
|
|
os.remove(f.name)
|
|
|
|
|
|
#/**
|
|
# ogGetHivePath path_mountpoint [str_hive|str_user]
|
|
#@brief Función básica que devuelve el camino del fichero con una sección del registro.
|
|
#@param path_mountpoint directorio donde está montado el sistema Windows
|
|
#@param str_hive sección del registro
|
|
#@return str_path - camino del fichero de registro
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Fichero de registro no encontrado.
|
|
#@note hive = { DEFAULT, SAM, SECURITY, SOFTWARE, SYSTEM, COMPONENTS, NombreDeUsuario }
|
|
#@warning El sistema de archivos de Windows debe estar montada previamente.
|
|
#*/ ##
|
|
#ogGetHivePath ('/mnt/sda1', 'user1') => /mnt/sda1/Users/user1/NTUSER.DAT
|
|
#ogGetHivePath ('/mnt/sda1', 'SYSTEM') => //mnt/sda1/Windows/System32/config/SYSTEM
|
|
#ogGetHivePath ('/mnt/sda1', 'IEUser') => //mnt/sda1/Users/IEUser/NTUSER.DAT
|
|
def ogGetHivePath(mntpt, hive):
|
|
# Camino del fichero de registro de usuario o de sistema (de menor a mayor prioridad).
|
|
FILE = FileLib.ogGetPath(file=f"/{mntpt}/Windows/System32/config/{hive}")
|
|
if not FILE: FILE = FileLib.ogGetPath(file=f"/{mntpt}/Users/{hive}/NTUSER.DAT")
|
|
if not FILE: FILE = FileLib.ogGetPath(file=f"/{mntpt}/winnt/system32/config/{hive}")
|
|
if not FILE: FILE = FileLib.ogGetPath(file=f"/{mntpt}/Documents and Settings/{hive}/NTUSER.DAT")
|
|
if FILE and os.path.isfile(FILE):
|
|
return FILE
|
|
else:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'{mntpt} {hive}')
|
|
return None
|
|
|
|
|
|
## simulate 'grep --after-context 1'
|
|
def _grep_A1 (strings, search_term):
|
|
results = []
|
|
for i in range (len (strings)):
|
|
if search_term in strings[i]:
|
|
results.append (strings[i])
|
|
if i + 1 < len(strings):
|
|
results.append (strings[i + 1])
|
|
|
|
return results
|
|
|
|
#/**
|
|
# ogGetRegistryValue path_mountpoint str_hive str_valuename
|
|
#@brief Devuelve el dato de un valor del registro de Windows.
|
|
#@param path_mountpoint directorio donde está montado el sistema Windows
|
|
#@param str_hive sección del registro
|
|
#@param str_valuename nombre del valor
|
|
#@return str_valuedata - datos del valor.
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Fichero de registro no encontrado.
|
|
#@note hive = { default, sam, security, software, system, components }
|
|
#@warning Requisitos: chntpw, awk
|
|
#@warning El sistema de archivos de Windows debe estar montado previamente.
|
|
#*/ ##
|
|
def ogGetRegistryValue (mntpt, hive, k):
|
|
hivefile = ogGetHivePath(mntpt, hive)
|
|
if not hivefile: return
|
|
|
|
k_dirname, k_basename = _split_k (k)
|
|
|
|
with tempfile.NamedTemporaryFile (delete_on_close=False, prefix='chntpw-', mode='w') as f:
|
|
f.write (f'cd {k_dirname}\n')
|
|
f.write (f'cat {k_basename}\n')
|
|
f.write ('q\n')
|
|
f.close()
|
|
chntpw_out = chntpw (hivefile, f.name)
|
|
os.remove (f.name)
|
|
|
|
lines = chntpw_out.splitlines()
|
|
lines = _grep_A1 (lines, '> Value')
|
|
if 2 != len (lines):
|
|
return None
|
|
|
|
ret = None
|
|
if 'REG_BINARY' in lines[0]:
|
|
if re.search ('^:[0-9A-F]+ ', lines[1]):
|
|
ret = lines[1][8:56]
|
|
else:
|
|
ret = lines[1]
|
|
return ret
|
|
|
|
|
|
#/**
|
|
# ogListRegistryKeys path_mountpoint str_hive str_key
|
|
#@brief Lista los nombres de subclaves de una determinada clave del registro de Windows.
|
|
#@param path_mountpoint directorio donde está montado el sistema Windows
|
|
#@param str_hive sección del registro
|
|
#@param str_key clave de registro
|
|
#@return str_subkey ... - lista de subclaves
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Fichero de registro no encontrado.
|
|
#@note hive = { default, sam, security, software, system, components }
|
|
#@warning Requisitos: chntpw, awk
|
|
#@warning El sistema de archivos de Windows debe estar montado previamente.
|
|
#*/ ##
|
|
#ogListRegistryKeys ('/mnt/sda1', 'SOFTWARE', '\Microsoft\Windows\CurrentVersion')
|
|
def ogListRegistryKeys (mntpt, hive, k):
|
|
hivefile = ogGetHivePath(mntpt, hive)
|
|
if not hivefile: return
|
|
|
|
with tempfile.NamedTemporaryFile (delete_on_close=False, prefix='chntpw-', mode='w') as f:
|
|
f.write (f'ls {k}\n')
|
|
f.write ('q\n')
|
|
f.close()
|
|
chntpw_out = chntpw (hivefile, f.name)
|
|
os.remove (f.name)
|
|
|
|
lines = chntpw_out.splitlines()
|
|
ret = []
|
|
for l in lines:
|
|
elems = re.split ('[<>]', l)
|
|
if len(elems) < 2: continue
|
|
if ' ' == elems[0]:
|
|
ret.append (elems[1])
|
|
return ret
|
|
|
|
|
|
#/**
|
|
# ogListRegistryValues path_mountpoint str_hive str_key
|
|
#@brief Lista los nombres de valores de una determinada clave del registro de Windows.
|
|
#@param path_mountpoint directorio donde está montado el sistema Windows
|
|
#@param str_hive sección del registro
|
|
#@param str_key clave de registro
|
|
#@return str_value ... - lista de valores
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Fichero de registro no encontrado.
|
|
#@note hive = { default, sam, security, software, system, components }
|
|
#@warning Requisitos: chntpw, awk
|
|
#@warning El sistema de archivos de Windows debe estar montado previamente.
|
|
#*/ ##
|
|
#ogListRegistryValues ('/mnt/sda1', 'SOFTWARE', '\Microsoft\Windows\CurrentVersion')
|
|
def ogListRegistryValues (mntpt, hive, k):
|
|
hivefile = ogGetHivePath(mntpt, hive)
|
|
if not hivefile: return
|
|
|
|
with tempfile.NamedTemporaryFile (delete_on_close=False, prefix='chntpw-', mode='w') as f:
|
|
f.write (f'ls {k}\n')
|
|
f.write ('q\n')
|
|
f.close()
|
|
chntpw_out = chntpw (hivefile, f.name)
|
|
os.remove (f.name)
|
|
|
|
lines = chntpw_out.splitlines()
|
|
ret = []
|
|
for l in lines:
|
|
elems = re.split ('[<>]', l)
|
|
if len(elems) < 2: continue
|
|
if 'REG_' in elems[0]:
|
|
ret.append (elems[1])
|
|
return ret
|
|
|
|
|
|
def _format_hex (hex_string):
|
|
result = []
|
|
offset = 0
|
|
|
|
hex_values = hex_string.strip().split()
|
|
result.append (str (len (hex_values)))
|
|
|
|
while hex_values:
|
|
chunk = hex_values[:16]
|
|
hex_values = hex_values[16:]
|
|
|
|
offset_str = f':{offset:05x} '
|
|
hex_line = ' '.join (chunk)
|
|
result.append (offset_str + hex_line)
|
|
|
|
offset += 16
|
|
|
|
return '\n'.join (result)
|
|
|
|
#/**
|
|
# ogSetRegistryValue path_mountpoint str_hive str_valuename str_valuedata
|
|
#@brief Establece el dato asociado a un valor del registro de Windows.
|
|
#@param path_mountpoint directorio donde está montado el sistema Windows
|
|
#@param str_hive sección del registro
|
|
#@param str_valuename nombre del valor de registro
|
|
#@param str_valuedata dato del valor de registro
|
|
#@return (nada)
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Fichero de registro no encontrado.
|
|
#@note hive = { default, sam, security, software, system, components }
|
|
#@warning Requisitos: chntpw
|
|
#@warning El sistema de archivos de Windows debe estar montado previamente.
|
|
#*/ ##
|
|
#ogSetRegistryValue ('/mnt/sda1', 'SOFTWARE', '\Key\SubKey\StringValue', 'Abcde Fghij')
|
|
#ogSetRegistryValue ('/mnt/sda1', 'SOFTWARE', '\Key\SubKey\DwordValue', 1)
|
|
#ogSetRegistryValue ('/mnt/sda1', 'SOFTWARE', '\Key\SubKey\BinaryValue', '04 08 0C 10')
|
|
def ogSetRegistryValue (mntpt, hive, k, v):
|
|
hivefile = ogGetHivePath (mntpt, hive)
|
|
if not hivefile: return
|
|
|
|
k_dirname, k_basename = _split_k (k)
|
|
|
|
with tempfile.NamedTemporaryFile (delete_on_close=False, prefix='chntpw-', mode='w') as f:
|
|
f.write (f"ls {k_dirname}\n")
|
|
f.write ('q\n')
|
|
f.close()
|
|
chntpw_out = chntpw (hivefile, f.name)
|
|
os.remove(f.name)
|
|
|
|
if re.search (f"BINARY.*<{k_basename}>", chntpw_out):
|
|
## the entry in the registry is binary. Our input should be a sequence of bytes
|
|
|
|
if ' ' != v[-1]: v += ' ' ## the regex below requires a trailing space
|
|
if not re.match (r'^([0-9A-F]{2} )*$', v.upper()):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'"{v}"')
|
|
return
|
|
|
|
formatted = _format_hex (v.upper())
|
|
formatted += '\ns'
|
|
else:
|
|
formatted = v
|
|
|
|
with tempfile.NamedTemporaryFile (delete_on_close=False, prefix='chntpw-', mode='w') as f:
|
|
f.write (f'cd {k_dirname}\n')
|
|
f.write (f'ed {k_basename}\n')
|
|
f.write (f'{formatted}\n')
|
|
f.write ('q\ny\n')
|
|
f.close()
|
|
chntpw (hivefile, f.name)
|
|
os.remove(f.name)
|