#/** #@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. 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, hive, k): FILE = ogGetHivePath(path_mountpoint, hive) if not FILE: return k_elems = k.split ('\\') k_dirname = '\\'.join (k_elems[0:-1]) k_basename = k_elems[-1] input = '\n'.join ([ f'cd {k_dirname}', f'cat {k_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) 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 # ${3%\\*} es dirname # ${3##*\\} es basename k_elems = k.split ('\\') k_dirname = '\\'.join (k_elems[0:-1]) k_basename = k_elems[-1] tmpfile = tempfile.TemporaryFile (prefix='chntpw-', mode='w') try: with open(tmpfile, 'w') as f: f.write (f"ls {k_dirname}\n") f.write ('q\n') output = subprocess.run (['chntpw', hivefile], input=open(tmpfile, 'r'), capture_output=True, text=True).stdout if re.search (f"BINARY.*<{k_basename}>", output): ## 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 open(tmpfile, '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') # Aplicar cambios. subprocess.run (['chntpw', hivefile], input=open(tmpfile, 'r')) finally: os.remove(tmpfile)