ogclone-engine/client/lib/engine/bin/RegistryLib.py

319 lines
12 KiB
Python

#/**
#@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)