
regipy v6.3.0
Regipy es una biblioteca de Python independiente del sistema operativo para analizar registry hives sin conexión.
regipy
⚠️ Cambios importantes en v6.0.0
La versión 6.0.0 incluye cambios de modernización significativos:
- Se requiere Python 3.9+ - Se eliminó el soporte para Python 3.6, 3.7 y 3.8
- Se eliminó la biblioteca
attrs- Las clases de datos ahora usan el módulodataclassesintegrado de Python- Si tu código importa clases internas (
Cell,VKRecord,Value,Subkey) y usa funciones deattrscomoattr.asdict(), cambia adataclasses.asdict()Consulta el CHANGELOG para más detalles.
Regipy es una biblioteca de Python para analizar archivos de registro sin conexión (archivos Hive con cabecera REGF). regipy tiene muchas capacidades:
- Uso como biblioteca:
- Recorrer recursivamente el archivo de registro, desde la raíz o una ruta dada y obtener todas las subclaves y valores
- Leer subclaves y valores específicos
- Aplicar registros de transacciones en un archivo de registro
- Herramientas de línea de comandos
- Volcar un archivo de registro completo a json
- Aplicar registros de transacciones en un archivo de registro
- Comparar archivos de registro
- Ejecutar plugins desde un sistema robusto de plugins (por ejemplo: amcache, shimcache, extraer nombre del equipo...)
Requiere Python 3.9 o superior.
Installation
La última versión de Regipy se puede instalar desde pypi:
pip install regipy[full]
NOTA: regipy[full] instala dependencias que requieren herramientas de compilación y pueden llevar algo de tiempo.
Es posible instalar una versión con dependencias relajadas, omitiendo el [full].
Además, es posible instalar desde el código fuente clonando el repositorio y ejecutando:
pip install --editable .[full]
Rust-accelerated backend (alpha)
Una implementación opcional en Rust del analizador REGF central está disponible como un backend opcional, publicado por separado en PyPI como regipy-rs:
pip install regipy[rust]
from regipy.registry_rs import RegistryHive # instead of regipy.registry
reg = RegistryHive('/tmp/NTUSER.dat')
# Same API: get_key, iter_values, recurse_subkeys, plugins — everything
# works unchanged, including all regipy plugins.
Es un reemplazo directo validado 1:1 contra el analizador puro de Python en todo el corpus de prueba de archivos de registro — cada ruta de clave, marca de tiempo, valor y salida del plugin, notarizado mediante coincidencia de resúmenes SHA-256 de recorrido (consulta regipy_tests/comparison_test.py y la sección Forensic parity evidence de regipy-rs/BENCHMARKS.md).
Recorrido completo con valores (recurse_subkeys), mejor de 3 ejecuciones:
| Archivo de registro | Claves | Python | Rust | Aceleración |
|---|---|---|---|---|
| NTUSER.DAT | 1,812 | 173 ms | 5 ms | 38x |
| UsrClass.dat | 6,205 | 948 ms | 17 ms | 55x |
| amcache.hve | 2,105 | 837 ms | 12 ms | 67x |
| SYSTEM | 30,756 | 23.1 s | 91 ms | 253x |
| SYSTEM (Win10 1709) | 43,211 | 118.7 s | 111 ms | 1,068x |
| SOFTWARE | 117,488 | 745.6 s | 292 ms | 2,550x |
cProfile muestra por qué: en el backend de Python, el tiempo de recorrido está dominado por el análisis de las estructuras construct por registro y la decodificación de valores; con el backend de Rust, el analizador desaparece por completo del perfil y el único costo restante de Python es la construcción de las clases de datos Subkey devueltas.
Los perfiles completos, los resúmenes por archivo de registro y un aviso que documenta las pocas divergencias intencionales (tipos de excepción en archivos de registro corruptos, comportamiento del guardián de ciclos) están en regipy-rs/BENCHMARKS.md; python regipy-rs/benchmark.py regenera todo el informe.
El analizador puro de Python sigue siendo el predeterminado y no se ve afectado cuando el backend de Rust no está instalado.
CLI
Analizar la cabecera:
regipy-parse-header ~/Documents/TestEvidence/Registry/SYSTEM
Ejemplo de salida:
╒════════════════════════╤══════════╕
│ signature │ b'regf' │
├────────────────────────┼──────────┤
│ primary_sequence_num │ 11639 │
├────────────────────────┼──────────┤
│ secondary_sequence_num │ 11638 │
├────────────────────────┼──────────┤
│ last_modification_time │ 0 │
├────────────────────────┼──────────┤
│ major_version │ 1 │
├────────────────────────┼──────────┤
│ minor_version │ 5 │
├────────────────────────┼──────────┤
│ file_type │ 0 │
├────────────────────────┼──────────┤
│ file_format │ 1 │
├────────────────────────┼──────────┤
│ root_key_offset │ 32 │
├────────────────────────┼──────────┤
│ hive_bins_data_size │ 10534912 │
├────────────────────────┼──────────┤
│ clustering_factor │ 1 │
├────────────────────────┼──────────┤
│ file_name │ SYSTEM │
├────────────────────────┼──────────┤
│ checksum │ 0 │
╘════════════════════════╧══════════╛
[2019-02-09 13:46:12.111654] WARNING: regipy.cli: Hive is not clean! You should apply transaction logs
- Al analizar la cabecera de un archivo de registro, también se realizan la validación de suma de verificación y las validaciones de transacciones
Volcar archivo de registro completo al disco (esto puede llevar algo de tiempo)
regipy-dump ~/Documents/TestEvidence/Registry/NTUSER-CCLEANER.DAT -o /tmp/output.json
La utilidad regipy-dump también puede generar una línea de tiempo en lugar de un JSON, añadiendo la opción -t
Ejecutar plugins relevantes en un archivo de registro
regipy-plugins-run ~/Documents/TestEvidence/Registry/SYSTEM -o /tmp/plugins_output.json
El tipo de archivo de registro se detectará automáticamente y se ejecutarán los plugins relevantes. Consulta la sección de plugins para más información
Comparar archivos de registro
Compara archivos de registro del mismo tipo y genera salida a CSV (si no se especifica -o, la salida se imprimirá en pantalla)
regipy-diff NTUSER.dat NTUSER_modified.dat -o /tmp/diff.csv
Ejemplo de salida:
[2019-02-11 19:49:18.824245] INFO: regipy.cli: Comparing NTUSER.DAT vs NTUSER_modified.DAT
╒══════════════╤══════════════╤════════════════════════════════════════════════════════════════════════════════╤════════════════════════════════════════════════╕
│ difference │ first_hive │ second_hive │ description │
╞══════════════╪══════════════╪════════════════════════════════════════════════════════════════════════════════╪════════════════════════════════════════════════╡
│ new_subkey │ │ 2019-02-11T19:46:31.832134+00:00 │ \Software\Microsoft\legitimate_subkey │
├──────────────┼──────────────┼────────────────────────────────────────────────────────────────────────────────┼────────────────────────────────────────────────┤
│ new_value │ │ not_a_malware: c:\temp\legitimate_binary.exe @ 2019-02-11 19:45:25.516346+00:00 │ \Software\Microsoft\Windows\CurrentVersion\Run │
╘══════════════╧══════════════╧════════════════════════════════════════════════════════════════════════════════╧════════════════════════════════════════════════╛
[2019-02-11 19:49:18.825328] INFO: regipy.cli: Detected 2 differences
Recuperar un archivo de registro usando registros de transacciones:
regipy-process-transaction-logs NTUSER.DAT -p ntuser.dat.log1 -s ntuser.dat.log2 -o recovered_NTUSER.dat
Después de recuperar, compara los archivos de registro con registry-diff para ver qué cambió
Using as a library
Inicializar el objeto del archivo de registro
from regipy.registry import RegistryHive
reg = RegistryHive('/Users/martinkorman/Documents/TestEvidence/Registry/Vibranium-NTUSER.DAT')
Iterar recursivamente sobre todo el archivo de registro, desde la clave raíz
for entry in reg.recurse_subkeys(as_json=True):
print(entry)
Iterar sobre una clave y obtener todas las subclaves y su hora de modificación:
for sk in reg.get_key('Software').iter_subkeys():
print(sk.name, convert_wintime(sk.header.last_modified).isoformat())
Adobe 2019-02-03T22:05:32.525965
AppDataLow 2019-02-03T22:05:32.526047
McAfee 2019-02-03T22:05:32.526140
Microsoft 2019-02-03T22:05:32.526282
Netscape 2019-02-03T22:05:32.526352
ODBC 2019-02-03T22:05:32.526521
Policies 2019-02-03T22:05:32.526592
Obtener los valores de una clave:
reg.get_key('Software\Microsoft\Internet Explorer\BrowserEmulation').get_values(as_json=True)
[{'name': 'CVListTTL',
'value': 0,
'value_type': 'REG_DWORD',
'is_corrupted': False},
{'name': 'UnattendLoaded',
'value': 0,
'value_type': 'REG_DWORD',
'is_corrupted': False},
{'name': 'TLDUpdates',
'value': 0,
'value_type': 'REG_DWORD',
'is_corrupted': False},
{'name': 'CVListXMLVersionLow',
'value': 2097211,
'value_type': 'REG_DWORD',
'is_corrupted': False},
{'name': 'CVListXMLVersionHigh',
'value': None,
'value_type': 'REG_DWORD',
'is_corrupted': False},
{'name': 'CVListLastUpdateTime',
'value': None,
'value_type': 'REG_DWORD',
'is_corrupted': False},
{'name': 'IECompatVersionHigh',
'value': None,
'value_type': 'REG_DWORD',
'is_corrupted': False},
{'name': 'IECompatVersionLow',
'value': 2097211,
'value_type': 'REG_DWORD',
'is_corrupted': False},
{'name': 'StaleCompatCache',
'value': 0,
'value_type': 'REG_DWORD',
'is_corrupted': False}]
Usar como plugin:
from regipy.plugins.ntuser.ntuser_persistence import NTUserPersistencePlugin
NTUserPersistencePlugin(reg, as_json=True).run()
{
'Software\\Microsoft\\Windows\\CurrentVersion\\Run': {
'timestamp': '2019-02-03T22:10:52.655462',
'values': [{
'name': 'Sidebar',
'value': '%ProgramFiles%\\Windows Sidebar\\Sidebar.exe /autoRun',
'value_type': 'REG_EXPAND_SZ',
'is_corrupted': False
}]
}
}
Ejecutar todos los plugins relevantes para un archivo de registro específico
from regipy.plugins.utils import run_relevant_plugins
reg = RegistryHive('/Users/martinkorman/Documents/TestEvidence/Registry/SYSTEM')
run_relevant_plugins(reg, as_json=True)
{
'routes': {},
'computer_name': [{
'control_set': 'ControlSet001\\Control\\ComputerName\\ComputerName',
'computer_name': 'DESKTOP-5EG84UG',
'timestamp': '2019-02-03T22:19:28.853219'
}]
}
Casos de validación
Informe de casos de validación
Todos los nuevos plugins deben tener uno o más casos de validación básicos (que se pueden ampliar en el futuro), por ejemplo:
from regipy.plugins.system.bam import BAMPlugin
from regipy_tests.validation.validation import ValidationCase
class NTUserUserAssistValidationCase(ValidationCase):
# define your plugin class
plugin = BAMPlugin
# define the test file name, which should be present in `regipy_tests/data`
test_hive_file_name = "SYSTEM_WIN_10_1709.xz"
# Use `expected_entries` to test for presence of a few samples from the plugin results
expected_entries = [
{
"sequence_number": 9,
"version": 1,
"sid": "S-1-5-90-0-1",
"executable": "\\Device\\HarddiskVolume2\\Windows\\System32\\dwm.exe",
"timestamp": "2020-04-19T09:09:35.731816+00:00",
"key_path": "\\ControlSet001\\Services\\bam\\state\\UserSettings\\S-1-5-90-0-1",
}
]
# OR use `exact_expected_result` to test for an exact result:
exact_expected_result = [
{
"sequence_number": 9,
"version": 1,
"sid": "S-1-5-90-0-1",
"executable": "\\Device\\HarddiskVolume2\\Windows\\System32\\dwm.exe",
"timestamp": "2020-04-19T09:09:35.731816+00:00",
"key_path": "\\ControlSet001\\Services\\bam\\state\\UserSettings\\S-1-5-90-0-1",
},
{
"sequence_number": 8,
"version": 1,
"sid": "S-1-5-90-0-1",
"executable": "\\Device\\HarddiskVolume2\\Windows\\System32\\cmd.exe",
"timestamp": "2020-04-19T09:09:34.544224+00:00",
"key_path": "\\ControlSet001\\Services\\bam\\state\\UserSettings\\S-1-5-90-0-1",
}
]
expected_entries_count = 2
Development
Configuración para el desarrollo
# Clone the repository
git clone https://github.com/mkorman90/regipy.git
cd regipy
# Install in development mode with all dependencies
pip install -e ".[full,dev]"
# Install pre-commit hooks
pre-commit install
Ejecutar pruebas
# Run all tests
pytest
# Run specific test files
pytest regipy_tests/tests.py
pytest regipy_tests/cli_tests.py
# Run plugin validation
PYTHONPATH=. python regipy_tests/validation/plugin_validation.py
Calidad del código
# Run linter
ruff check .
# Run formatter
ruff format .
# Run type checker
mypy regipy/
Probar GitHub Actions localmente
Para probar los cambios en el flujo de trabajo de CI localmente antes de subirlos, usa act:
# Install act (Fedora)
sudo dnf install act-cli
# Install act (macOS)
brew install act
# Install act (other)
# See https://nektosact.com/installation/index.html
Asegúrate de que Docker esté en funcionamiento, luego:
# List available jobs
act -l
# Run the lint job
act -j lint
# Run all jobs for a push event
act push
# Run the test job with a specific Python version
act -j test
# Test the build job from publish workflow (simulates a release)
act release -j build --eventpath /dev/stdin <<< '{"action": "published"}'
Nota: Algunos trabajos pueden requerir secretos. Puedes proporcionarlos con:
act -j publish --secret PYPI_API_TOKEN=your_token
License
MIT