Los timestamps de Amcache, decodificados
Hay al menos nueve campos en Amcache.hve que parecen un timestamp. Dos no son timestamps. Cuatro significan cosas distintas en Windows 7 que en Windows 10. Uno es controlable por el atacante. Los otros dos son útiles, a veces, con caveats.
Si alguna vez te preguntaron "¿cuándo apareció este archivo en el host?" y respondiste usando un solo campo de Amcache, este post es la conversación que deberías haber tenido contigo mismo primero.
Los dos formatos que Windows usa, lado a lado#
Amcache mezcla dos convenciones de timestamp en la misma hive, lo cual es un cierto tipo de decisión de diseño.
El primero es el FILETIME de 64 bits: intervalos de 100 nanosegundos desde 1601-01-01 UTC, almacenados little-endian. Es lo que usa el LastWrite de cada clave del Registro, y algunos campos a nivel de valor lo guardan. Los parsers lo manejan transparentemente. La semántica suele ser "el Registro escribió esta entrada en este momento".
El segundo es DateTime-como-string, donde Microsoft eligió guardar un timestamp legible para humanos dentro de un valor REG_SZ. Los formatos varían entre builds: MM/DD/AAAA HH:MM:SS en Win10, ISO-8601-ish AAAA-MM-DD HH:MM:SS en algunas entradas de Win11. La zona horaria suele ser UTC pero ocasionalmente es hora local en hives Win7. Comprueba siempre antes de construir una timeline; un desfase de una zona horaria en un informe es embarazoso.
Lee el tipo de celda vk cruda si no estás seguro. REG_QWORD y REG_BINARY de longitud 8 significan FILETIME; REG_SZ significa parsea el string y reza.
Los campos, uno a uno#
Key LastWrite en InventoryApplicationFile\#
El timestamp más útil de la hive. Es el FILETIME que el Registro escribió en el cabecero de la clave la última vez que el Compatibility Appraiser actualizó la entrada de este archivo. En la práctica esto es "Appraiser advirtió este archivo" o "Appraiser re-hasheó este archivo porque algo cambió".
No es creación del archivo, no es ejecución, no es actividad de usuario. La primera vez que Appraiser ve un binario recién soltado, el LastWrite es aproximadamente la siguiente corrida programada después de que el archivo apareció. La cadencia de corrida programada depende del host, pero unas horas es típico en un sistema configurado normal.
Sanity check: este timestamp debería ser siempre posterior al tiempo de creación NTFS del propio archivo desde la MFT. Si es anterior, algo va mal (timestomping, deriva de reloj o un atacante que editó la hive).
LinkDate (InventoryApplicationFile, InventoryDriverBinary)#
IMAGE_FILE_HEADER.TimeDateStamp del cabecero PE, guardado como string DateTime. Es el timestamp de compilación que estampó el linker, que es lo que sea que dijera el entorno de build.
Controlado por el atacante. Trivialmente. link.exe /timestamp o un patch post-link pueden ponerlo a cualquier cosa. La mitad del malware commodity llega con LinkDate = 1970-01-01 porque nadie se molesta. Mejores samples lo ponen a un 2018-2020 plausible. Los pulidos lo emparejan con el LinkDate de un binario Microsoft real para mezclarse.
Útil para:
- Detectar valores descaradamente equivocados (1970, 2099, o valores que contradicen el resto de la timeline del host).
- Distinguir dos builds del mismo proyecto, cuando ambos samples tienen tiempos de compilación honestos.
No útil para: timeline. No lo pongas en una timeline.
InstallDate (InventoryApplication)#
Un string DateTime bajo cada clave InventoryApplication\<ProgramId>. El valor es lo que el instalador escribió, normalmente sacado de metadatos MSI o del valor DisplayInstallDate en la clave Uninstall. Para software empaquetado legítimamente (Office, Chrome, MSIs de vendor) esto es honesto al día, ocasionalmente al segundo.
Para droppers de malware, tooling sideloaded o cualquier cosa que no haya pasado por un instalador real, este campo está ausente, puesto a cero o puesto a lo que fuera conveniente. Trátalo como orientativo.
Uso InstallDate para corroborar aplicaciones de cara al usuario cuando la pregunta es "cuándo instaló este usuario Chrome", no para actividad de adversario.
InstallDateMsi, InstallDateArpLastModified, InstallDateFromLinkFile (InventoryApplication)#
Mismo significado general, fuentes distintas. Windows 10 build 1709 y posteriores exponen varias variantes de install-date por aplicación:
InstallDateMsi: de la base de datos MSI, si la instalación usó MSI.InstallDateArpLastModified: del tiempo de última modificación de la entrada de Registro de Add/Remove Programs (ARP).InstallDateFromLinkFile: de los metadatos del archivo .lnk del menú Inicio, cuando la aplicación creó uno.
Cuando estos tres difieren en más de unos minutos, ha pasado algo interesante: una reinstalación de reparación, una actualización o un re-registro. Cuando coinciden, la fecha de instalación es sólida.
Key LastWrite en InventoryApplication\#
Distinto de InstallDate. Es la última escritura de la clave del Registro, que se actualiza cada vez que Appraiser refresca la entrada de la aplicación. Para la mayoría de aplicaciones, la primera escritura está cerca del momento de instalación y las posteriores son infrecuentes. Útil como comprobación de corroboración contra InstallDate*.
Key LastWrite en InventoryDeviceContainer\#
Lo más cercano a "cuándo vio Windows este dispositivo por última vez" que vas a encontrar en la hive. Actualizado cuando Appraiser refresca el registro del dispositivo. Combina con la historia USB propia (SYSTEM\ControlSet001\Enum\USBSTOR, Microsoft-Windows-Partition%4Diagnostic.evtx, setupapi.dev.log) para cualquier pregunta USB; el valor de Amcache solo es demasiado grueso.
Key LastWrite en InventoryDriverBinary\ e InventoryDriverPackage\#
Misma forma que las claves de aplicación. El LastWrite es "Appraiser refrescó esta entrada de driver", lo que en un host funcionando con normalidad pasa poco después de que el driver aterriza. Para investigaciones BYOVD donde el atacante soltó un driver firmado vulnerable, el LastWrite de InventoryDriverBinary suele ser la cota más estrecha que tienes sobre "cuándo se preparó este driver".
Key LastWrite en InventoryApplicationShortcut\#
Cuándo Appraiser indexó este .lnk. El shortcut en sí tiene sus propios MAC times en el cuerpo del archivo LNK, que el parser de LNK te dará. El LastWrite de Amcache es un timestamp distinto, posterior, menos interesante. Lo uso como sanity check, no como hallazgo.
Lo que Win7, Win10 y Win11 hacen distinto#
La hive no es la misma entre builds mayores, aunque los nombres de claves parezcan idénticos.
Windows 7 SP1 con el Compatibility Appraiser original tenía una hive mucho más simple. Las claves de primer nivel eran Root\File, Root\Programs, Root\Generic y Root\Orphan. El valor LastModified bajo Root\File\<volume>\<fileid> era el explícito "archivo modificado por última vez según NTFS en tiempo de escaneo de Appraiser", una semántica distinta a cualquier cosa en la hive moderna. Si estás leyendo una hive Win7, no puedes usar nombres de campo Win10. El plugin amcache antiguo de RegRipper lo gestiona; AmcacheParser maneja mejor las hives modernas que las legacy.
Windows 8 / 8.1 introdujo las claves InventoryApplication* pero el esquema era inestable. Varios campos aparecen en 8.1 que desaparecen en 10 y viceversa. No recomendaría construir automatización contra una hive 8.1 sin inspeccionar la lista de valores primero.
Windows 10 builds hasta ~1709 tenía un esquema InventoryApplication más delgado. Las tres variantes InstallDate* no existían todas. LinkDate a veces estaba vacío para archivos PE que Appraiser no podía parsear del todo.
Windows 10 1809 y posteriores es el esquema estable que apunta la mayoría del tooling actual. El conjunto de columnas de AmcacheParser coincide con este.
Windows 11 añade unos cuantos valores bajo InventoryApplicationFile (notablemente algunos campos relacionados con firma) y cambia el formato de string de ciertos valores DateTime de US-locale a algo ISO-ish. La semántica de los timestamps centrales no cambia.
Las actualizaciones in-place hacen un lío#
Cuando un host se actualiza de Windows 10 a Windows 11, o de un build mayor de 10 a otro, la Amcache se migra, no se regenera. En la práctica:
- Las entradas viejas de
InventoryApplicationFilesuelen preservarse con su LastWrite original de la corrida pre-actualización. - El Appraiser re-escanea todo tras la actualización, así que en horas o días la mayoría de LastWrites se refrescan.
- Los cambios de esquema significan que algunos campos están poblados en entradas creadas tras la actualización y vacíos en entradas que sobrevivieron de antes.
- Un subconjunto de entradas a veces queda huérfano: el binario ya no existe pero la clave nunca se limpió durante la migración.
Si la distribución de LastWrite de tu hive muestra dos clusters separados por un hueco limpio, probablemente estás mirando una población pre y post-actualización. Confirma contra setupact.log o el canal Setup en el log de eventos antes de leer demasiado.
Sanity checks prácticos#
Antes de que ningún timestamp entre en un informe, repásate estos mentalmente:
- ¿El LastWrite de la clave
InventoryApplicationFilees posterior al tiempo de creación NTFS del archivo? Si no, algo va mal. - ¿El LastWrite es consistente con el last-run de la tarea Compatibility Appraiser en
Microsoft-Windows-TaskScheduler%4Operational.evtx? Las escrituras del Appraiser son por lotes; deberías ver clusters de LastWrites que coinciden con corridas de la tarea. - ¿Las tres
InstallDate*bajoInventoryApplicationson consistentes entre sí? El desacuerdo es interesante. - ¿
LinkDatees plausible? 1970, 2099, o cualquier valor fuera de aproximadamente 1995-ahora significa que el cabecero PE fue estampado, no que el archivo sea tan viejo. - Cruza al menos un timestamp de Amcache contra tiempos de ejecución de Prefetch, eventos Sysmon process create o creaciones del journal USN. Si el cruce está en desacuerdo, la Amcache no está necesariamente equivocada, pero tienes que explicar la diferencia antes de comprometerte.
La Amcache no te miente a propósito. Pero te dará un timestamp perfectamente razonable que significa algo completamente distinto de lo que asumiste. Es lo que tienen en común todos los campos de este post.
Lecturas adicionales#
- Amcache.hve in Windows 8 de Yogesh Khatri, que aún documenta la semántica de los campos mejor que cualquier fuente del vendor.
- El código fuente del AmcacheParser de Eric Zimmerman para el mapeo canónico de nombres de valor a columnas.
- La documentación del Compatibility Appraiser de Microsoft, escasa en forense pero útil para entender la cadencia de la tarea.
- Los videos deep-dive de 13Cubed sobre Amcache y Shimcache, particularmente los segmentos de timestamps.
Artículos relacionados
- Qué te dice realmente la Amcache en una investigación DFIR
Una mirada de profesional a la hive Amcache.hve: qué prueba realmente cada entrada, dónde te mienten los timestamps, y los errores que se repiten en los informes de incidente.
- El formato binario de Amcache.hve, en la práctica
Un recorrido por la estructura en disco de Amcache.hve: el layout de la hive regf, las subclaves que importan en DFIR y las herramientas que las leen sin mentirte.
- Marcas de tiempo de Amcache explicadas: KeyLastWriteTimestamp vs LinkDate vs el resto
Una referencia para cada marca de tiempo que Amcache expone — KeyLastWriteTimestamp, LinkDate, InstallDate, MsiInstallDate, LastModified — qué significa cada una y sobre cuál pivotar.
- SHA-1 en la Amcache: pivotando del disco al threat intel
Cómo el campo FileId de Amcache se convierte en el pivote más útil en una investigación DFIR, por qué los hashes ganan a las rutas y el flujo para pivotar por hash a escala.