#/** #@file Registry.lib #@brief Librería o clase Registry #@class Boot #@brief Funciones para gestión del registro de Windows. #@version 1.1.0 #@warning License: GNU GPLv3+ #*/ import subprocess import os import re import shutil import ogGlobals import SystemLib import FileLib # Función ficticia para lanzar chntpw con timeout de 5 s., evitando cuelgues del programa. def chntpw (file, input): exe = shutil.which ('drbl-chntpw') or shutil.which ('chntpw') return subprocess.run ([exe, '-e', file], timeout=5, input=input, capture_output=True, text=True).stdout #/** # 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(path_mountpoint, str_hive, str_key): # Variables locales. FILE = ogGetHivePath(path_mountpoint, str_hive) if not FILE: return # Añadir nueva clave. chntpw(FILE, 'cd', str_key.rsplit('\\', 1)[0]) chntpw(FILE, 'nk', str_key.rsplit('\\', 1)[-1]) chntpw(FILE, 'q') chntpw(FILE, 'y') #/** # 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. #*/ ## def ogAddRegistryValue(path_mountpoint, str_hive, str_key, str_valuename, str_valuetype=''): # Variables locales. FILE = ogGetHivePath(path_mountpoint, str_hive) if not FILE: return # Determine the value type. if str_valuetype.upper() == 'STRING' or str_valuetype == '': TYPE = 1 elif str_valuetype.upper() == 'BINARY': TYPE = 3 elif str_valuetype.upper() == 'DWORD': TYPE = 4 else: SystemLib.ogRaiseError( "session", ogGlobals.OG_ERR_OUTOFLIMIT, f"Error: {str_valuetype}", ) return # Add the registry value. chntpw(FILE, 'cd', str_key.rsplit('\\', 1)[0]) chntpw(FILE, 'nv', str_valuename.rsplit('\\', 1)[-1], TYPE) chntpw(FILE, 'q') chntpw(FILE, 'y') #/** # 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(path_mountpoint, str_hive, str_key): # Variables locales. FILE = ogGetHivePath(path_mountpoint, str_hive) if not FILE: return # Delete the registry key. subprocess.run(['chntpw', FILE], input=f"cd {str_key.rsplit('\\', 1)[0]}\ndk {str_key.rsplit('\\', 1)[-1]}\nq\ny\n".encode(), timeout=5) #/** # 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. #*/ ## def ogDeleteRegistryValue(path_mountpoint, str_hive, str_valuename): # Variables locales. FILE = ogGetHivePath(path_mountpoint, str_hive) if not FILE: return # Delete the registry value. chntpw(FILE, 'cd', str_valuename.rsplit('\\', 1)[0]) chntpw(FILE, 'dv', str_valuename.rsplit('\\', 1)[-1]) chntpw(FILE, 'q') chntpw(FILE, 'y') #/** # 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', 'SOFTWARE') => /mnt/sda1/WINDOWS/System32/config/SOFTWARE #ogGetHivePath ('/mnt/sda1', 'user1') => /mnt/sda1/Users/user1/NTUSER.DAT def ogGetHivePath(path_mountpoint, str_hive): # Camino del fichero de registro de usuario o de sistema (de menor a mayor prioridad). FILE = FileLib.ogGetPath(file=f"/{path_mountpoint}/Windows/System32/config/{str_hive}") if not FILE: FILE = FileLib.ogGetPath(file=f"/{path_mountpoint}/Users/{str_hive}/NTUSER.DAT") if not FILE: FILE = FileLib.ogGetPath(file=f"/{path_mountpoint}/winnt/system32/config/{str_hive}") if not FILE: FILE = FileLib.ogGetPath(file=f"/{path_mountpoint}/Documents and Settings/{str_hive}/NTUSER.DAT") if FILE and os.path.isfile(FILE): return FILE else: SystemLib.ogRaiseError( [], ogGlobals.OG_ERR_NOTFOUND, f"{path_mountpoint} {str_hive}" ) return None #/** # 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(path_mountpoint, str_hive, str_valuename): FILE = ogGetHivePath(path_mountpoint, str_hive) if not FILE: return elems = str_valuename.split ('\\') dirname = '\\'.join (elems[0:-1]) basename = elems[-1] input = '\n'.join ([ f'cd {dirname}', f'cat {basename}', 'q', ]) chntpw_out = chntpw (file, input) lines = chntpw_out.splitlines() if 2 != len (lines): return None if 'REG_BINARY' in lines[0]: offset, content = lines[1].split (maxsplit=1) return content #/** # 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. #*/ ## def ogListRegistryKeys(path_mountpoint, str_hive, str_key): # Variables locales. FILE = ogGetHivePath(path_mountpoint, str_hive) if not FILE: return # Devolver la lista de claves de registro. chntpw_cmd = f''' chntpw "{FILE}" << EOT 2> /dev/null | awk 'BEGIN {{FS="[<>]"}} $1~/^ $/ {{print $2}}' ls {str_key} q EOT ''' subprocess.run(chntpw_cmd, shell=True, timeout=5) #/** # 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. #*/ ## def ogListRegistryValues(path_mountpoint, str_hive, str_key): # Variables locales. FILE = ogGetHivePath(path_mountpoint, str_hive) if not FILE: return # Devolver la lista de valores de registro. chntpw_cmd = f''' chntpw "{FILE}" << EOT 2> /dev/null | awk 'BEGIN {{FS="[<>]"}} $1~/REG_/ {{print $2}}' ls {str_key} q EOT ''' subprocess.run(chntpw_cmd, shell=True, timeout=5) #/** # 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. #*/ ## def ogSetRegistryValue(path_mountpoint, str_hive, str_valuename, str_data): # Variables locales. FILE = ogGetHivePath(path_mountpoint, str_hive) if not FILE: return # Fichero temporal para componer la entrada al comando "chntpw". tmpfile = "/tmp/chntpw$$" try: # Comprobar tipo de datos del valor del registro. with open(tmpfile, 'w') as f: f.write(f"ls {str_valuename.rsplit('\\', 1)[0]}\nq\n") output = subprocess.check_output(['chntpw', FILE], input=open(tmpfile, 'rb'), stderr=subprocess.DEVNULL).decode() if f"BINARY.*<{str_valuename.rsplit('\\', 1)[-1]}>" in output: # Procesar tipo binario (incluir nº de bytes y líneas de 16 parejas hexadecimales). if not re.match(r'^([0-9A-F]{2} )*$', str_data): SystemLib.ogRaiseError( "session", ogGlobals.OG_ERR_FORMAT, f'"{str_data}"' ) return n = len(str_data) + 1 with open(tmpfile, 'w') as f: f.write(f"cd {str_valuename.rsplit('\\', 1)[0]}\ned {str_valuename.rsplit('\\', 1)[-1]}\n{int(n/3)}\n") for i in range(0, n, 48): f.write(f":{i//3:05x} {str_data[i:i+48]}\n") f.write("s\nq\ny\n") else: # Cambiar el dato del valor de registro para cadenas y bytes. with open(tmpfile, 'w') as f: f.write(f"cd {str_valuename.rsplit('\\', 1)[0]}\ned {str_valuename.rsplit('\\', 1)[-1]}\n{str_data}\nq\ny\n") # Aplicar cambios. subprocess.run(['chntpw', FILE], input=open(tmpfile, 'rb'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) finally: os.remove(tmpfile)