Sistemas de archivos · Lección 4 de 8
Archivos de metadatos de NTFS: $LogFile, $UsnJrnl y flujos de datos alternativos
12 min de lectura
La lección 1.3 mostró cómo la $MFT describe cada archivo en su estado actual. Esta lección aborda tres funciones de NTFS que registran lo que ocurrió antes o contienen datos que pasan inadvertidos en una revisión superficial: el registro de transacciones $LogFile, el diario de cambios USN y los flujos de datos alternativos. Con ellas, un examinador puede demostrar que un archivo se creó, cambió de nombre o se eliminó después de que haya desaparecido, y encontrar datos ocultos junto a un archivo común.
$LogFile: el registro de transacciones
$LogFile es el registro 2 de la MFT. NTFS es un sistema de archivos con registro por diario: antes de modificar sus propios metadatos (registros de la MFT, índices de directorios, mapa de bits de asignación), escribe un registro que describe el cambio. Si el sistema falla a mitad del proceso, Windows vuelve a aplicar o revierte estos registros en el siguiente montaje para mantener la coherencia de los metadatos. $LogFile protege únicamente los metadatos; no conserva copias del contenido de los archivos escrito en atributos $DATA no residentes.
Estructura
- Área de reinicio. Las dos primeras páginas de 4.096 bytes contienen la firma
RSTR. Son dos copias del área de reinicio, que registra la posición actual en el registro de transacciones y dónde debe comenzar la recuperación. - Páginas de registros de transacciones. El resto del archivo se compone de páginas con la firma
RCRD. Cada registro de transacción tiene un número de secuencia de registro (LSN), un ID de transacción, una operación de rehacer (cómo aplicar el cambio) y una operación de deshacer (cómo revertirlo), además de los bytes implicados. Los nombres de las operaciones incluyenInitializeFileRecordSegment,DeallocateFileRecordSegment,AddIndexEntryAllocation,DeleteIndexEntryAllocationyUpdateResidentValue. - Vínculo con la MFT. El encabezado de cada registro de la MFT contiene, en el desplazamiento 0x08, el LSN del último cambio registrado en ese registro, lo que permite a las herramientas relacionar los registros de transacciones con los registros de la MFT.
El registro de transacciones es circular y se reutiliza constantemente. Su tamaño predeterminado es de unas pocas decenas de MB; lea el tamaño real en el atributo $DATA del registro 2 de la MFT en lugar de darlo por supuesto. En un disco del sistema con mucha actividad, ese espacio abarca solo de unos minutos a unas pocas horas de actividad; en un volumen con poco uso puede abarcar más tiempo.
Qué puede revelar
Como los datos de rehacer y deshacer contienen los bytes reales de los metadatos, $LogFile puede mostrar la creación, los cambios de nombre y la eliminación recientes de archivos, incluidos los nombres antiguos y nuevos, las entradas de índice eliminadas de un directorio y los datos residentes o valores de $STANDARD_INFORMATION antes y después de un cambio (útil cuando se han alterado las marcas de tiempo). Los registros de transacciones no tienen un campo de tiempo propio: las horas se obtienen de las marcas de tiempo dentro de los datos de atributos registrados o de la correlación con el diario USN. Algunos ejemplos de analizadores son LogFileParser y NTFS Log Tracker; el segundo correlaciona $LogFile con $UsnJrnl.
El diario de cambios USN
El diario de números de secuencia de actualización (USN) registra los cambios en archivos y directorios para que el software de copias de seguridad e indexación pueda identificar qué cambió. Windows lo habilita de forma predeterminada en el volumen del sistema. Se encuentra en $Extend\$UsnJrnl (el número de registro de la MFT de $UsnJrnl no es fijo, a diferencia del de $LogFile) y tiene dos flujos $DATA con nombre:
| Flujo | Contenido |
|---|---|
$J | Los registros de cambios, agregados uno tras otro |
$Max | Configuración del diario: tamaño máximo, incremento de asignación e ID del diario |
El USN de un registro es su desplazamiento en bytes dentro de $J. Cuando el diario supera su tamaño máximo, NTFS libera la asignación de la parte más antigua de $J y la convierte en dispersa (un intervalo sin clústeres asignados que se lee como ceros). Por tanto, el tamaño lógico de $J puede mostrar varios GB, aunque solo las decenas de MB más recientes contengan registros. fsutil usn queryjournal C: en un sistema en ejecución muestra los valores configurados; en los volúmenes del sistema de Windows 10 y 11, el máximo suele ser de 32 MB.
Hasta dónde se remonta el diario depende de la actividad y del tamaño máximo: a menudo de días a semanas en una estación de trabajo, y a veces solo unas horas en un servidor con mucha actividad. Los registros más antiguos pueden persistir en el espacio no asignado y en las instantáneas de volumen. En las unidades NTFS extraíbles, el diario suele estar ausente salvo que algún software o fsutil usn createjournal lo haya habilitado; FAT32 y exFAT (lección 1.5) no tienen diario.
USN_RECORD_V2
La mayoría de los registros en NTFS son de la versión 2 (la versión 3 utiliza ID de archivo de 128 bits y aparece principalmente en ReFS). Todos los enteros están en formato little-endian.
| Desplazamiento | Tamaño | Campo |
|---|---|---|
| 0x00 | 4 | Longitud del registro (múltiplo de 8) |
| 0x04 | 2 + 2 | Versión principal (2), versión secundaria (0) |
| 0x08 | 8 | Número de referencia del archivo (entrada de la MFT de 6 bytes + secuencia de 2 bytes) |
| 0x10 | 8 | Número de referencia del archivo padre |
| 0x18 | 8 | USN |
| 0x20 | 8 | Marca de tiempo (FILETIME, UTC, momento en que se escribió el registro) |
| 0x28 | 4 | Indicadores de motivo |
| 0x2C | 4 | Información de origen (distinta de cero para cambios realizados por servicios del sistema, como la replicación) |
| 0x30 | 4 | ID de seguridad |
| 0x34 | 4 | Atributos del archivo (p. ej., 0x20 archivo, 0x10 directorio) |
| 0x38 | 2 + 2 | Longitud del nombre del archivo en bytes, desplazamiento del nombre del archivo (normalmente 0x3C) |
| 0x3C | var. | Nombre del archivo, UTF-16LE, sin ruta |
Indicadores de motivo habituales:
| Indicador | Valor | Significado |
|---|---|---|
| DATA_OVERWRITE | 0x00000001 | Se sobrescribieron datos en el flujo sin nombre |
| DATA_EXTEND | 0x00000002 | El flujo sin nombre aumentó de tamaño |
| DATA_TRUNCATION | 0x00000004 | El flujo sin nombre se redujo de tamaño |
| FILE_CREATE | 0x00000100 | Se creó un archivo o directorio |
| FILE_DELETE | 0x00000200 | Se eliminó un archivo o directorio |
| RENAME_OLD_NAME | 0x00001000 | El registro contiene el nombre anterior a un cambio de nombre o traslado |
| RENAME_NEW_NAME | 0x00002000 | El registro contiene el nombre posterior a un cambio de nombre o traslado |
| BASIC_INFO_CHANGE | 0x00008000 | Se modificaron atributos o marcas de tiempo |
| STREAM_CHANGE | 0x00200000 | Se agregó, eliminó o cambió de nombre un flujo con nombre |
| CLOSE | 0x80000000 | Se cerró el último identificador de acceso; finaliza este conjunto de cambios |
Cómo una operación genera varios registros
Los indicadores de motivo se acumulan. Mientras un archivo está abierto, cada nuevo tipo de cambio escribe un registro cuyo motivo es el resultado de aplicar OR a todo lo observado hasta ese momento, y cuando se cierra el último identificador de acceso, NTFS escribe un registro final con CLOSE agregado. Así, crear un archivo y escribir en él genera FILE_CREATE, después FILE_CREATE | DATA_EXTEND y, por último, FILE_CREATE | DATA_EXTEND | CLOSE. Interprete el registro CLOSE como el resumen de toda la operación.
Dos advertencias. «Eliminar» en el Explorador normalmente mueve el archivo a $Recycle.Bin, lo que aparece como registros RENAME_OLD_NAME / RENAME_NEW_NAME (el nombre nuevo comienza por $R), no como FILE_DELETE; FILE_DELETE aparece en caso de eliminación permanente, vaciado de la Papelera de reciclaje o eliminación mediante un programa. Además, un registro demuestra que se produjo un cambio, no quién lo realizó ni por qué.
Reconstrucción de rutas completas
Un registro contiene únicamente el nombre del archivo y el número de referencia del archivo padre. Para reconstruir la ruta, divida la referencia del padre en entrada de la MFT (los 6 bytes menos significativos) y número de secuencia (los 2 bytes más significativos), busque esa entrada en la $MFT, tome su nombre y repita el proceso con su propio padre hasta llegar a la entrada 5, el directorio raíz. Si el número de secuencia de la $MFT difiere del que figura en el registro, la entrada se ha liberado o reutilizado y la ruta no es fiable. La $MFT muestra los nombres actuales de las carpetas; los registros de cambio de nombre de una carpeta muestran los anteriores. MFTECmd, por ejemplo, analiza $J, lo exporta a CSV y resuelve una columna ParentPath cuando se proporciona la $MFT mediante -m.
Flujos de datos alternativos
Cada archivo NTFS tiene un atributo $DATA sin nombre (tipo 0x80, longitud del nombre 0): el contenido que se ve al abrir el archivo. Un archivo o directorio también puede tener cualquier cantidad de atributos $DATA con nombre, denominados flujos de datos alternativos (ADS). Cada uno es un atributo $DATA independiente en el mismo registro de la MFT, con el nombre del flujo almacenado en el encabezado del atributo; un flujo pequeño es residente dentro del registro, mientras que uno más grande tiene sus propias secuencias de clústeres. La sintaxis es file.txt:stream o, en su forma completa, file.txt:stream:$DATA. El tamaño que muestra el Explorador corresponde únicamente al flujo sin nombre.
Zone.Identifier
Cuando un navegador o cliente de correo guarda en Windows un archivo procedente de Internet, agrega un flujo llamado Zone.Identifier con texto como [ZoneTransfer], ZoneId=3, ReferrerUrl=… y HostUrl=…. ZoneId 3 es la zona de Internet (0 equipo local, 1 intranet local, 2 sitios de confianza, 4 sitios restringidos). Los navegadores recientes basados en Chromium, como Chrome y Edge en Windows 10 y 11, agregan los campos ReferrerUrl y HostUrl; HostUrl es la URL de descarga. Otros programas pueden escribir solo la línea ZoneId. Esto constituye evidencia directa del origen, pero algunas herramientas de descarga y de extracción de archivos comprimidos no lo crean ni lo propagan.
Ocultar datos y perderlos
Se puede escribir cualquier contenido en un flujo, por ejemplo type secret.zip > notes.txt:x.zip, sin que cambie el tamaño del archivo visible; el malware ha almacenado cargas útiles de esta manera. Los ADS existen únicamente en NTFS (y ReFS): copiar un archivo a FAT32 o exFAT, adjuntarlo a un correo electrónico o subirlo descarta todos los flujos con nombre, por lo que su ausencia en medios extraíbles no demuestra nada sobre el original.
Detección de flujos
dir /renumera los flujos comonotes.txt:x.zip:$DATA.- En PowerShell,
Get-Item .\notes.txt -Stream *enumera cada flujo y su longitud. - En una imagen, la salida de MFTECmd marca los archivos que tienen flujos (
HasAds) y asigna a cada flujo su propia fila (IsAds), con el texto residente de Zone.Identifier enZoneIdContents. Agregar un flujo también escribe registros USN con STREAM_CHANGE.
Ejemplo resuelto: un archivo en el diario USN
El $J de un disco del sistema con Windows 11 contiene estos registros (se omiten los registros de otros archivos intercalados entre ellos, por lo que los USN presentan saltos). Todos tienen la referencia de archivo 0x0005000000012A3F y la referencia del padre 0x0003000000009C40.
| USN | Marca de tiempo (UTC) | Motivo | Nombre |
|---|---|---|---|
| 1476395008 | 2026-03-14T09:21:07.250Z | FILE_CREATE (0x00000100) | draft.txt |
| 1476395088 | 2026-03-14T09:21:07.251Z | FILE_CREATE, DATA_EXTEND (0x00000102) | draft.txt |
| 1476395168 | 2026-03-14T09:21:07.253Z | FILE_CREATE, DATA_EXTEND, CLOSE (0x80000102) | draft.txt |
| 1476421632 | 2026-03-14T09:24:51.008Z | RENAME_OLD_NAME (0x00001000) | draft.txt |
| 1476421712 | 2026-03-14T09:24:51.008Z | RENAME_NEW_NAME (0x00002000) | keys.txt |
| 1476421792 | 2026-03-14T09:24:51.009Z | RENAME_NEW_NAME, CLOSE (0x80002000) | keys.txt |
| 1476444584 | 2026-03-14T09:30:12.115Z | FILE_DELETE, CLOSE (0x80000200) | keys.txt |
Longitud del registro. draft.txt tiene 9 caracteres, 18 bytes en UTF-16: 60 + 18 = 78, redondeado hacia arriba a un múltiplo de 8 = 80 bytes. Por eso el siguiente registro de la misma ráfaga está en 1476395008 + 80 = 1476395088. keys.txt da 60 + 16 = 76, con relleno hasta 80.
Marca de tiempo. El primer registro contiene el valor FILETIME 134179536672500000 (intervalos de 100-ns desde 1601-01-01). 134179536672500000 / 10.000.000 = 13.417.953.667,25 s; menos 11.644.473.600 s (de 1601 a 1970) = tiempo Unix 1.773.480.067,25 = 2026-03-14T09:21:07.250Z.
Referencias. 0x0005000000012A3F: los 6 bytes menos significativos, 0x12A3F = entrada 76.351 de la MFT; los 2 bytes más significativos = secuencia 5. El padre 0x0003000000009C40 es la entrada 40.000, secuencia 3. En la $MFT, la entrada 40.000 (secuencia 3) es Desktop, cuya cadena de padres es ana, Users y la raíz, por lo que la ruta completa era C:\Users\ana\Desktop\draft.txt, cuyo nombre se cambió a keys.txt sin moverlo de ubicación.
Interpretación. El archivo se creó y se escribió a las 09:21:07Z, cambió de nombre a las 09:24:51Z y se eliminó permanentemente a las 09:30:12Z; no se envió a la Papelera de reciclaje, ya que no aparece ningún cambio de nombre hacia $Recycle.Bin. La entrada 76.351 puede contener ya otro archivo con la secuencia 6; el diario sigue demostrando el nombre y las horas anteriores. $LogFile puede confirmar la eliminación si todavía abarca las 09:30.
Enfoque del examen: Prepárese para indicar una hora, un nombre original o una ruta completa a partir de $J, lo que requiere leer el registro CLOSE de una ráfaga, distinguir RENAME_OLD_NAME de RENAME_NEW_NAME y resolver la referencia del padre mediante la $MFT. Es posible que se le pregunte de dónde procede un archivo descargado (HostUrl en Zone.Identifier) o qué archivo contiene un flujo oculto. Sepa qué intervalo temporal abarca cada artefacto: $LogFile, de minutos a horas; $J, normalmente de días a semanas.
Puntos clave
- $LogFile (registro 2 de la MFT) registra las transacciones de metadatos como registros de rehacer/deshacer después de un área de reinicio
RSTR; es pequeño, circular y solo abarca actividad reciente. $Extend\$UsnJrnl:$Jcontiene entradas USN_RECORD_V2; el USN es el desplazamiento del registro en el archivo disperso$J, y$Maxcontiene la configuración de tamaño.- Los indicadores de motivo se acumulan hasta un registro con CLOSE; los cambios de nombre generan un registro OLD_NAME y uno NEW_NAME; la eliminación desde el Explorador suele ser un cambio de nombre hacia
$Recycle.Bin. - Las rutas se reconstruyen a partir de la referencia del archivo padre mediante la $MFT; compruebe el número de secuencia antes de confiar en el resultado.
- Los atributos $DATA con nombre son flujos de datos alternativos; Zone.Identifier registra ZoneId, ReferrerUrl y HostUrl, y todos los flujos se pierden en FAT32/exFAT.