Amcache FileId explicado: el formato de hash SHA-1 que almacena Windows

El valor FileId en Root\InventoryApplicationFile es uno de los campos más útiles de todo el hive Amcache — y uno de los más malentendidos. Es el hash de contenido del archivo, pero no es del todo un SHA-1 estándar, y no hashea del todo el archivo completo. Este post es la referencia completa: qué es el valor, cómo usarlo y las trampas que cazan a los analistas nuevos.

Para la referencia más amplia de Amcache, ver la referencia completa de Amcache; para la estructura del registro circundante, ver Estructura del registro Amcache.


Cómo se ve el valor#

Un FileId típico de un hive real:

0000da39a3ee5e6b4b0d3255bfef95601890afd80709

41 caracteres en total:

  • Los primeros 4 caracteres son siempre "0000" — una etiqueta de tipo fija.
  • Los 40 caracteres restantes son el digest hex SHA-1 del archivo.

El prefijo "0000" es un artefacto histórico: las primeras versiones del appraiser anticipaban múltiples algoritmos de hash (con cada prefijo indicando cuál) pero en la práctica solo se llegó a usar SHA-1. Hoy el prefijo es constante.

Cuando AmcacheParser expone este campo en su CSV, lo divide en dos columnas:

Columna Valor
FileId La cadena completa de 41 caracteres, prefijo incluido.
Hash Solo los 40 caracteres hexadecimales — el SHA-1 solo.

Usa siempre Hash (o quita el prefijo tú mismo) cuando hagas joins contra feeds externos de hash. VirusTotal, tus feeds de TI y las bases de datos de allowlist de hash esperan un SHA-1 de 40 caracteres — no coincidirá con nada si incluyes el prefijo "0000".


Qué hashea realmente#

Esta es la trampa que caza a casi todo analista nuevo de Amcache:

El SHA-1 de Amcache hashea los primeros 31 MiB del archivo, no el archivo completo.

Para archivos menores de 31 MiB (que es casi todo — la mayoría de EXEs y DLLs están muy por debajo), el hash de prefijo equivale al SHA-1 del archivo completo. Son indistinguibles entre sí.

Para archivos mayores de 31 MiB, el hash de Amcache es un hash de prefijo, no un hash de contenido completo. Sigue siendo lo bastante distintivo para identificar un build específico de un binario específico, pero no es el mismo valor que obtendrías con sha1sum sobre el archivo completo.

Por qué esto importa#

  • Coincidencias en VirusTotal. Para archivos por debajo de 31 MiB, el SHA-1 de Amcache coincide con el SHA-1 que VirusTotal indexa. Para archivos más grandes (instaladores, algunos binarios de juegos, software empresarial grande) no coincidirá, y una respuesta de "sin registro" de VirusTotal no significa nada.
  • Bases de datos personalizadas de hash. Si mantienes una allowlist interna de hashes conocidos como buenos, asegúrate de estar almacenando el mismo tipo de hash con el que vas a comparar. O almacena SHA-1 de contenido completo (y acepta que las comparaciones con Amcache para binarios grandes fallarán) o mantén una columna paralela de hash de prefijo.
  • Recompilar para verificación. Si tienes el binario original a mano y quieres verificar que un hash de Amcache coincide, hashea solo los primeros 31 MiB:
import hashlib
PREFIX_BYTES = 31 * 1024 * 1024  # 31 MiB
 
def amcache_sha1(path: str) -> str:
    h = hashlib.sha1()
    with open(path, 'rb') as f:
        h.update(f.read(PREFIX_BYTES))
    return h.hexdigest()

Trampas del mundo real#

Un puñado de obstáculos que aparecen en casos reales:

No incluyas el prefijo "0000" en las búsquedas#

# Mal
search_virustotal('0000da39a3ee5e6b4b0d3255bfef95601890afd80709')
 
# Bien
search_virustotal('da39a3ee5e6b4b0d3255bfef95601890afd80709')

La API de VirusTotal espera específicamente el hash desnudo. Incluir el prefijo devuelve un resultado vacío silenciosamente — lo que se ve idéntico a "este archivo es desconocido" y es mucho más engañoso.

Las colisiones de hash son teóricas pero no imposibles#

SHA-1 tiene ataques de colisión conocidos. En un contexto no adversarial esto es irrelevante — encontrar una colisión SHA-1 contra una entrada específica de Amcache requiere un esfuerzo desproporcionadamente mayor al que gana un atacante. Pero para coincidencias de alta confianza en una investigación de altas apuestas, no trates una coincidencia SHA-1 como identidad criptográfica. Empareja con tamaño del archivo, fecha de link y al menos otro campo.

No confíes en el FileId de una fila con IsPeFile = False#

Amcache ocasionalmente registra valores FileId para archivos no-PE inventariados por el appraiser. El hash sigue siendo real, pero el contexto es diferente — está hasheando lo que sea el archivo (un script, un archivo de configuración), y las herramientas downstream que asumen contexto de archivo PE (búsquedas PE-aware de VirusTotal, reglas Yara contra bytes PE) devolverán resultados menos útiles.

Múltiples filas, mismo hash#

Si encuentras el mismo valor Hash en múltiples filas *_UnassociatedFileEntries.csv en el mismo host, eso es significativo. Significa que el mismo contenido binario fue inventariado en múltiples rutas. Razones comunes:

  • El atacante copió una herramienta a varias ubicaciones para probar cuál ejecutaría.
  • Un instalador legítimo dejó la misma DLL en múltiples directorios de productos.
  • Un usuario copió un archivo manualmente.

Agrupa por Hash, luego mira el conjunto de FullPath y KeyLastWriteTimestamp para cada instancia. Las marcas de tiempo te dicen la secuencia de copias; las rutas te dicen la intención.

Múltiples hashes, mismo FullPath#

El patrón opuesto — la misma ruta con diferentes valores Hash en múltiples filas — significa que el binario en esa ruta cambió entre inventarios. Esta es una señal fuerte de reemplazo binario:

  • Legítimo: una actualización de software sobrescribió el archivo.
  • Sospechoso: un atacante reemplazó un binario del sistema o una herramienta de usuario que se ejecuta regularmente con una copia troyanizada.

Ordena las filas por KeyLastWriteTimestamp para ver cuándo apareció cada nuevo hash, luego correlaciona con eventos de parche o eventos de Sysmon File Create alrededor de esos momentos.


Pivotes que usan FileId / Hash#

Los pivotes que se ganan su trabajo en casos reales:

Caza de hash entre hosts#

# Pivotar un SHA-1 conocido como malicioso a través del CSV Amcache de cada host
$badHash = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
Get-ChildItem -Recurse -Filter *_UnassociatedFileEntries.csv |
  ForEach-Object {
    Import-Csv $_.FullName |
      Where-Object { $_.Hash -eq $badHash } |
      Select-Object @{n='Host';e={$_.PSChildName.Split('_')[0]}},
                    FullPath, KeyLastWriteTimestamp, Size
  } |
  Sort-Object Host

Así pasas de "encontramos este hash en un host" a "dime cada host del entorno que ha tenido alguna vez este binario presente, y cuándo apareció."

Enriquecimiento con VirusTotal de un CSV#

import csv, requests, time
 
API = 'https://www.virustotal.com/api/v3/files/'
HEADERS = {'x-apikey': '<your-key>'}
 
seen = set()
with open('HOST_amcache_UnassociatedFileEntries.csv', newline='') as f:
    for row in csv.DictReader(f):
        h = row['Hash']
        if not h or h in seen:
            continue
        seen.add(h)
        r = requests.get(API + h, headers=HEADERS)
        if r.status_code == 200:
            stats = r.json()['data']['attributes']['last_analysis_stats']
            if stats.get('malicious', 0) > 0:
                print(h, stats, row['FullPath'])
        time.sleep(15)  # VT public API rate limit

Incluso una búsqueda de bajo volumen contra la API pública produce una lista ajustada de hashes confirmados como malos en un host típico infectado.

Correlación con eventos Image Loaded de Sysmon#

El ID de evento 7 de Sysmon (Image Loaded) registra el SHA-1 de cada DLL cargada por cada proceso. Unir Hash de Amcache al campo Hashes del Sysmon 7 te dice exactamente qué procesos cargaron una DLL dada del atacante, y cuándo.


Ver también#

¿Quieres ver los valores FileId en tu propio hive sin instalar nada? Suelta un hive en la página de inicio del parser — se parsea enteramente en tu navegador.

Artículos relacionados

Volver a todos los artículos