refs #1226 finish and refactor RegistryLib

pull/1/head
Natalia Serrano 2024-12-05 14:55:28 +01:00
parent 1332b0b8bc
commit 7dccc621cb
1 changed files with 125 additions and 104 deletions

View File

@ -17,11 +17,18 @@ import SystemLib
import FileLib import FileLib
# Función ficticia para lanzar chntpw con timeout de 5 s., evitando cuelgues del programa. # Función ficticia para lanzar chntpw con timeout de 5 s., evitando cuelgues del programa.
def chntpw (file, input): chntpw_exe = shutil.which ('drbl-chntpw') or shutil.which ('chntpw')
exe = shutil.which ('drbl-chntpw') or shutil.which ('chntpw') def chntpw (hivefile, input_file):
return subprocess.run ([chntpw_exe, '-e', hivefile], timeout=5, input=open(input_file, 'r'), capture_output=True, text=True).stdout
return subprocess.run ([exe, '-e', file], timeout=5, input=input, 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 # ogAddRegistryKey path_mountpoint str_hive str_keyname
@ -36,18 +43,19 @@ def chntpw (file, input):
#@warning Requisitos: chntpw #@warning Requisitos: chntpw
#@warning El sistema de archivos de Windows debe estar montada previamente. #@warning El sistema de archivos de Windows debe estar montada previamente.
#*/ ## #*/ ##
def ogAddRegistryKey(path_mountpoint, str_hive, str_key): def ogAddRegistryKey (mntpt, hive, k):
# Variables locales. hivefile = ogGetHivePath (mntpt, hive)
FILE = ogGetHivePath(path_mountpoint, str_hive) if not hivefile: return
if not FILE:
return
# Añadir nueva clave. k_dirname, k_basename = _split_k (k)
chntpw(FILE, 'cd', str_key.rsplit('\\', 1)[0])
chntpw(FILE, 'nk', str_key.rsplit('\\', 1)[-1])
chntpw(FILE, 'q')
chntpw(FILE, 'y')
tmpfile = tempfile.TemporaryFile (prefix='chntpw-', mode='w')
with open (tmpfile, 'w') as f:
f.write (f'cd {k_dirname}\n')
f.write (f'nk {k_basename}\n')
f.write ('q\ny\n')
chntpw (hivefile, tmpfile)
os.remove (tmpfile)
#/** #/**
# ogAddRegistryValue path_mountpoint str_hive str_valuename [str_valuetype] # ogAddRegistryValue path_mountpoint str_hive str_valuename [str_valuetype]
@ -64,32 +72,29 @@ def ogAddRegistryKey(path_mountpoint, str_hive, str_key):
#@warning Requisitos: chntpw #@warning Requisitos: chntpw
#@warning El sistema de archivos de Windows debe estar montada previamente. #@warning El sistema de archivos de Windows debe estar montada previamente.
#*/ ## #*/ ##
def ogAddRegistryValue(path_mountpoint, str_hive, str_key, str_valuename, str_valuetype=''): #ogAddRegistryValue ('/mnt/sda1', 'SOFTWARE', '\Microsoft\NewKey\Value1')
# Variables locales. #ogAddRegistryValue ('/mnt/sda1', 'SOFTWARE', '\Microsoft\NewKey\Value1', 'DWORD')
FILE = ogGetHivePath(path_mountpoint, str_hive) def ogAddRegistryValue (mntpt, hive, k, vtype='STRING'):
if not FILE: hivefile = ogGetHivePath (mntpt, hive)
return if not hivefile: return
k_dirname, k_basename = _split_k (k)
# Determine the value type. # Determine the value type.
if str_valuetype.upper() == 'STRING' or str_valuetype == '': if 'STRING' == vtype.upper(): TYPE = 1
TYPE = 1 elif 'BINARY' == vtype.upper(): TYPE = 3
elif str_valuetype.upper() == 'BINARY': elif 'DWORD' == vtype.upper(): TYPE = 4
TYPE = 3
elif str_valuetype.upper() == 'DWORD':
TYPE = 4
else: else:
SystemLib.ogRaiseError( SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_OUTOFLIMIT, vtype)
"session",
ogGlobals.OG_ERR_OUTOFLIMIT,
f"Error: {str_valuetype}",
)
return return
# Add the registry value. tmpfile = tempfile.TemporaryFile (prefix='chntpw-', mode='w')
chntpw(FILE, 'cd', str_key.rsplit('\\', 1)[0]) with open (tmpfile, 'w') as f:
chntpw(FILE, 'nv', str_valuename.rsplit('\\', 1)[-1], TYPE) f.write (f'cd {k_dirname}\n')
chntpw(FILE, 'q') f.write (f'nv {TYPE} {k_basename}\n')
chntpw(FILE, 'y') f.write ('q\ny\n')
chntpw (hivefile, tmpfile)
os.remove (tmpfile)
#/** #/**
@ -106,14 +111,19 @@ def ogAddRegistryValue(path_mountpoint, str_hive, str_key, str_valuename, str_va
#@warning El sistema de archivos de Windows debe estar montada previamente. #@warning El sistema de archivos de Windows debe estar montada previamente.
#@warning La clave debe estar vacía para poder ser borrada. #@warning La clave debe estar vacía para poder ser borrada.
#*/ ## #*/ ##
def ogDeleteRegistryKey(path_mountpoint, str_hive, str_key): def ogDeleteRegistryKey (mntpt, hive, k):
# Variables locales. hivefile = ogGetHivePath (mntpt, hive)
FILE = ogGetHivePath(path_mountpoint, str_hive) if not hivefile: return
if not FILE:
return
# Delete the registry key. k_dirname, k_basename = _split_k (k)
subprocess.run(['chntpw', FILE], input=f"cd {str_key.rsplit('\\', 1)[0]}\ndk {str_key.rsplit('\\', 1)[-1]}\nq\ny\n".encode(), timeout=5)
tmpfile = tempfile.TemporaryFile (prefix='chntpw-', mode='w')
with open (tmpfile, 'w') as f:
f.write (f'cd {k_dirname}\n')
f.write (f'dk {k_basename}\n')
f.write ('q\ny\n')
chntpw (hivefile, tmpfile)
os.remove (tmpfile)
#/** #/**
@ -129,17 +139,20 @@ def ogDeleteRegistryKey(path_mountpoint, str_hive, str_key):
#@warning Requisitos: chntpw #@warning Requisitos: chntpw
#@warning El sistema de archivos de Windows debe estar montada previamente. #@warning El sistema de archivos de Windows debe estar montada previamente.
#*/ ## #*/ ##
def ogDeleteRegistryValue(path_mountpoint, str_hive, str_valuename): #ogDeleteRegistryValue ('/mnt/sda1', 'SOFTWARE', '\Microsoft\NewKey\Value1')
# Variables locales. def ogDeleteRegistryValue (mntpt, hive, k):
FILE = ogGetHivePath(path_mountpoint, str_hive) hivefile = ogGetHivePath (mntpt, hive)
if not FILE: if not hivefile: return
return
# Delete the registry value. k_dirname, k_basename = _split_k (k)
chntpw(FILE, 'cd', str_valuename.rsplit('\\', 1)[0])
chntpw(FILE, 'dv', str_valuename.rsplit('\\', 1)[-1]) tmpfile = tempfile.TemporaryFile (prefix='chntpw-', mode='w')
chntpw(FILE, 'q') with open(tmpfile, 'w') as f:
chntpw(FILE, 'y') f.write (f'cd {k_dirname}\n')
f.write (f'dv {k_basename}\n')
f.write ('q\ny\n')
chntpw (hivefile, tmpfile)
os.remove(tmpfile)
#/** #/**
@ -153,21 +166,20 @@ def ogDeleteRegistryValue(path_mountpoint, str_hive, str_valuename):
#@note hive = { DEFAULT, SAM, SECURITY, SOFTWARE, SYSTEM, COMPONENTS, NombreDeUsuario } #@note hive = { DEFAULT, SAM, SECURITY, SOFTWARE, SYSTEM, COMPONENTS, NombreDeUsuario }
#@warning El sistema de archivos de Windows debe estar montada previamente. #@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 #ogGetHivePath ('/mnt/sda1', 'user1') => /mnt/sda1/Users/user1/NTUSER.DAT
def ogGetHivePath(path_mountpoint, str_hive): def ogGetHivePath(mntpt, hive):
# Camino del fichero de registro de usuario o de sistema (de menor a mayor prioridad). # 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}") FILE = FileLib.ogGetPath(file=f"/{mntpt}/Windows/System32/config/{hive}")
if not FILE: FILE = FileLib.ogGetPath(file=f"/{path_mountpoint}/Users/{str_hive}/NTUSER.DAT") if not FILE: FILE = FileLib.ogGetPath(file=f"/{mntpt}/Users/{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"/{mntpt}/winnt/system32/config/{hive}")
if not FILE: FILE = FileLib.ogGetPath(file=f"/{path_mountpoint}/Documents and Settings/{str_hive}/NTUSER.DAT") if not FILE: FILE = FileLib.ogGetPath(file=f"/{mntpt}/Documents and Settings/{hive}/NTUSER.DAT")
if FILE and os.path.isfile(FILE): if FILE and os.path.isfile(FILE):
return FILE return FILE
else: else:
SystemLib.ogRaiseError( SystemLib.ogRaiseError(
[], [],
ogGlobals.OG_ERR_NOTFOUND, ogGlobals.OG_ERR_NOTFOUND,
f"{path_mountpoint} {str_hive}" f"{mntpt} {hive}"
) )
return None return None
@ -185,20 +197,20 @@ def ogGetHivePath(path_mountpoint, str_hive):
#@warning Requisitos: chntpw, awk #@warning Requisitos: chntpw, awk
#@warning El sistema de archivos de Windows debe estar montado previamente. #@warning El sistema de archivos de Windows debe estar montado previamente.
#*/ ## #*/ ##
def ogGetRegistryValue(path_mountpoint, hive, k): def ogGetRegistryValue (mntpt, hive, k):
FILE = ogGetHivePath(path_mountpoint, hive) FILE = ogGetHivePath(mntpt, hive)
if not FILE: return if not FILE: return
k_elems = k.split ('\\') k_dirname, k_basename = _split_k (k)
k_dirname = '\\'.join (k_elems[0:-1])
k_basename = k_elems[-1]
input = '\n'.join ([ tmpfile = tempfile.TemporaryFile (prefix='chntpw-', mode='w')
f'cd {k_dirname}', with open(tmpfile, 'w') as f:
f'cat {k_basename}', f.write (f'cd {k_dirname}\n')
'q', f.write (f'cat {k_basename}\n')
]) f.write ('q\n')
chntpw_out = chntpw (file, input)
chntpw_out = chntpw (hivefile, tmpfile)
os.remove (tmpfile)
lines = chntpw_out.splitlines() lines = chntpw_out.splitlines()
if 2 != len (lines): if 2 != len (lines):
return None return None
@ -220,20 +232,26 @@ def ogGetRegistryValue(path_mountpoint, hive, k):
#@warning Requisitos: chntpw, awk #@warning Requisitos: chntpw, awk
#@warning El sistema de archivos de Windows debe estar montado previamente. #@warning El sistema de archivos de Windows debe estar montado previamente.
#*/ ## #*/ ##
def ogListRegistryKeys(path_mountpoint, str_hive, str_key): #ogListRegistryKeys ('/mnt/sda1', 'SOFTWARE', '\Microsoft\Windows\CurrentVersion')
# Variables locales. def ogListRegistryKeys (mntpt, hive, k):
FILE = ogGetHivePath(path_mountpoint, str_hive) FILE = ogGetHivePath(mntpt, hive)
if not FILE: if not FILE: return
return
# Devolver la lista de claves de registro. tmpfile = tempfile.TemporaryFile (prefix='chntpw-', mode='w')
chntpw_cmd = f''' with open(tmpfile, 'w') as f:
chntpw "{FILE}" << EOT 2> /dev/null | awk 'BEGIN {{FS="[<>]"}} $1~/^ $/ {{print $2}}' f.write (f'ls {k}\n')
ls {str_key} f.write ('q\n')
q chntpw_out = chntpw (hivefile, tmpfile)
EOT os.remove (tmpfile)
''' lines = chntpw_out.splitlines()
subprocess.run(chntpw_cmd, shell=True, timeout=5)
ret = []
for l in lines:
elems = re.split ('[<>]', l)
if len(elems) < 2: continue
if ' ' == elems[0]:
ret.append (elems[1])
return ret
#/** #/**
@ -249,20 +267,27 @@ def ogListRegistryKeys(path_mountpoint, str_hive, str_key):
#@warning Requisitos: chntpw, awk #@warning Requisitos: chntpw, awk
#@warning El sistema de archivos de Windows debe estar montado previamente. #@warning El sistema de archivos de Windows debe estar montado previamente.
#*/ ## #*/ ##
def ogListRegistryValues(path_mountpoint, str_hive, str_key): #ogListRegistryValues ('/mnt/sda1', 'SOFTWARE', '\Microsoft\Windows\CurrentVersion')
# Variables locales. def ogListRegistryValues (mntpt, hive, k):
FILE = ogGetHivePath(path_mountpoint, str_hive) FILE = ogGetHivePath(mntpt, hive)
if not FILE: if not FILE: return
return
tmpfile = tempfile.TemporaryFile (prefix='chntpw-', mode='w')
with open(tmpfile, 'w') as f:
f.write (f'ls {k}\n')
f.write ('q\n')
chntpw_out = chntpw (hivefile, tmpfile)
os.remove (tmpfile)
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
# 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): def _format_hex (hex_string):
result = [] result = []
@ -304,11 +329,7 @@ def ogSetRegistryValue (mntpt, hive, k, v):
hivefile = ogGetHivePath (mntpt, hive) hivefile = ogGetHivePath (mntpt, hive)
if not hivefile: return if not hivefile: return
# ${3%\\*} es dirname k_dirname, k_basename = _split_k (k)
# ${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') tmpfile = tempfile.TemporaryFile (prefix='chntpw-', mode='w')
try: try:
@ -316,8 +337,8 @@ def ogSetRegistryValue (mntpt, hive, k, v):
f.write (f"ls {k_dirname}\n") f.write (f"ls {k_dirname}\n")
f.write ('q\n') f.write ('q\n')
output = subprocess.run (['chntpw', hivefile], input=open(tmpfile, 'r'), capture_output=True, text=True).stdout chntpw_out = chntpw (hivefile, tmpfile)
if re.search (f"BINARY.*<{k_basename}>", output): if re.search (f"BINARY.*<{k_basename}>", chntpw_out):
## the entry in the registry is binary. Our input should be a sequence of bytes ## 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 ' ' != v[-1]: v += ' ' ## the regex below requires a trailing space
@ -337,6 +358,6 @@ def ogSetRegistryValue (mntpt, hive, k, v):
f.write ('q\ny\n') f.write ('q\ny\n')
# Aplicar cambios. # Aplicar cambios.
subprocess.run (['chntpw', hivefile], input=open(tmpfile, 'r')) chntpw (hivefile, tmpfile)
finally: finally:
os.remove(tmpfile) os.remove(tmpfile)