Amcache ProgramId explicado: la identidad de aplicación de 44 caracteres
El campo ProgramId en Root\InventoryApplicationFile y
Root\InventoryApplication es la identidad lógica de aplicación
de Amcache. Es una cadena hex de 44 caracteres que identifica de
forma única una aplicación — y, lo más importante, es determinista:
la misma aplicación en un host diferente típicamente obtiene el
mismo ProgramId. Eso lo convierte en uno de los pivotes
cross-host más útiles de todo el toolkit DFIR de Windows.
Esta página es la referencia completa: qué es el valor, cómo lo construye Windows, cómo usarlo en una investigación de un solo host y cómo pivotarlo a través de un entorno en un hunt.
Para el contexto más amplio 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 ProgramId típico de un hive real:
0006fa0b2a9f8a4eb9d7c81e8b1f3c5d3e2a0000ffff
44 caracteres hexadecimales, sin prefijo, sin delimitadores. Cada
entrada en InventoryApplicationFile lleva uno; cada entrada en
InventoryApplication está indexada por uno. Los dos enlazan
mediante el valor compartido: el ProgramId de un archivo te dice
a qué aplicación instalada pertenece.
Estructura de los 44 caracteres#
El valor no es un único hash uniforme. Codifica varios componentes, de forma aproximada:
- Una etiqueta de tipo / versión (los primeros caracteres).
- Un hash de los atributos identificadores de la aplicación — principalmente nombre, publisher, versión e idioma.
- Un discriminador final (a menudo
0000ffffo similar) usado por Windows para clasificación interna.
La construcción exacta ha cambiado a lo largo de los builds de Windows y no está completamente documentada por Microsoft. Para fines DFIR las reglas prácticas son:
- Dos registros con el mismo
ProgramIdson sobre la misma aplicación. - El
ProgramIdes estable entre hosts para la misma instalación de aplicación — Office 365 en el host A y el mismo build de Office 365 en el host B comparten unProgramId. - El
ProgramIdno es estable a través de upgrades de versión mayor — actualizar la aplicación típicamente cambia suProgramId.
Usar ProgramId en un solo host#
El uso estrella es unir un archivo a su registro de aplicación.
Archivo → aplicación#
Encontraste una fila sospechosa en
*_UnassociatedFileEntries.csv. Su ProgramId es
0006fa0b2a9f8a4eb9d7c81e8b1f3c5d3e2a0000ffff.
Busca el mismo ProgramId en *_AssociatedFileEntries.csv y en el
catálogo padre de aplicaciones (la clave del registro
Root\InventoryApplication\<ProgramId>, o el CSV equivalente si tu
parser emite uno). Típicamente obtienes:
- El nombre de visualización y el publisher de la aplicación.
- La fecha de instalación.
- El origen de instalación (a veces una URL de descarga).
- La lista completa de archivos asociados con esa aplicación.
Esto es invaluable cuando un atacante deja una herramienta que se
hace pasar por una aplicación legítima. El nombre del archivo y
los metadatos podrían decir "AdobeReaderUpdater.exe / Adobe Inc.",
pero su ProgramId o bien no coincide con ningún producto Adobe
instalado (sospechoso) o coincide con una aplicación diferente
de la que sugiere su nombre (muy sospechoso).
Aplicación → archivos#
El pivote inverso es igualmente útil. Encontraste un registro de
aplicación sospechoso en InventoryApplication — quizá un build
portable de algo con un publisher de "" y un origen de instalación
inusual. Toma su ProgramId y lista cada archivo que lo
comparta:
$pid = '0006fa0b2a9f8a4eb9d7c81e8b1f3c5d3e2a0000ffff'
Import-Csv .\HOST_amcache_UnassociatedFileEntries.csv |
Where-Object { $_.ProgramId -eq $pid } |
Select-Object FullPath, Hash, KeyLastWriteTimestamp
Import-Csv .\HOST_amcache_AssociatedFileEntries.csv |
Where-Object { $_.ProgramId -eq $pid } |
Select-Object FullPath, Hash, KeyLastWriteTimestampObtienes la huella completa de archivos de esa aplicación tal como la vio el appraiser — cada EXE, DLL y PE que el appraiser vinculó de vuelta a esa aplicación. Para herramientas del atacante, esta suele ser la forma más rápida de enumerar el conjunto completo de binarios desplegados a partir de un único archivo observado.
Pivote cross-host con ProgramId#
Aquí es donde ProgramId brilla como primitiva de hunt. Como la
identidad es estable entre hosts para la misma aplicación, un único
ProgramId sospechoso en un host se convierte en una consulta que
puedes ejecutar contra el Amcache de cualquier otro host:
$pid = '0006fa0b2a9f8a4eb9d7c81e8b1f3c5d3e2a0000ffff'
Get-ChildItem -Recurse -Filter *_UnassociatedFileEntries.csv |
ForEach-Object {
$rows = Import-Csv $_.FullName |
Where-Object { $_.ProgramId -eq $pid }
if ($rows) {
$host = $_.PSChildName.Split('_')[0]
foreach ($r in $rows) {
[pscustomobject]@{
Host = $host
Path = $r.FullPath
Hash = $r.Hash
When = $r.KeyLastWriteTimestamp
}
}
}
} |
Sort-Object WhenEste es el pivote de movimiento lateral. Si un único host tiene
un ProgramId sospechoso, ejecutar esta consulta a través de tus
CSVs Amcache recogidos te dice cada otro host en el que alguna vez
apareció la misma aplicación, con rutas y horas — típicamente una
señal más ajustada que los pivotes solo de hash porque el
ProgramId sobrevive a pequeñas variaciones en el binario
(re-firma, recompilación con el mismo nombre/publisher/versión).
Para el playbook completo de movimiento lateral, ver
Movimiento lateral y pivote ProgramId de Amcache.
Cuándo ProgramId es más útil#
Algunos patrones de investigación en los que ProgramId es el
pivote correcto:
Misma familia, múltiples builds#
Un atacante puede compilar su herramienta múltiples veces con los
mismos metadatos de nombre, publisher y versión — solo cambia el
binario. Los hashes difieren. El ProgramId es el mismo. El
hashing por sí solo pierde la familia; ProgramId la captura.
Binarios renombrados#
mimikatz.exe → svchost64.exe → update.exe. El nombre del
archivo cambia; los metadatos PE incrustados son los mismos. Si el
atacante no se molestó en limpiar el recurso de version-info, el
ProgramId se mantiene igual.
Herramientas redesplegadas en un entorno#
El atacante deja la misma herramienta en 20 hosts mientras se mueve
lateralmente. Los hashes pueden coincidir, las rutas normalmente
no. El ProgramId es el identificador más consistente a través de
los 20 hosts.
Cuándo ProgramId es el pivote equivocado#
Algunos casos en los que ProgramId rinde mal:
Herramientas con metadatos rotativos#
Si el atacante recompila con nombre/publisher/versión diferentes
cada vez, cada build obtiene un ProgramId diferente. Para estos,
el hash de contenido del archivo (el SHA-1 en Hash) es el
mejor pivote cross-host, porque al menos un componente del build es
idéntico.
Binarios living-off-the-land#
net.exe, psexec.exe, certutil.exe — herramientas legítimas
abusadas. Cada host que haya ejecutado cualquiera de estos tiene el
mismo ProgramId para ellos. Las coincidencias de ProgramId son
esencialmente sin significado aquí. Pivota sobre la línea de
comandos (4688 / Sysmon 1) o sobre la ruta desde la que se
ejecutó el LOLBIN.
Binarios verdaderamente novedosos#
Un archivo que aparece por primera vez en cualquier sitio tiene un
ProgramId que ningún otro host comparte. Sin un corpus con el que
comparar, ProgramId no hace trabajo; hash más
Publisher = '' and IsPeFile = True and FullPath bajo \Users\
es el filtro de triage que funciona.
Confusiones comunes#
Dos cosas que ProgramId no es:
No es un hash del binario#
Hash (o FileId) es el hash de contenido. ProgramId es un
hash de identidad de aplicación, calculado a partir de metadatos,
no de los bytes del binario. Dos binarios completamente diferentes
con metadatos idénticos obtienen el mismo ProgramId; el mismo
binario recompilado con metadatos diferentes obtiene un ProgramId
diferente.
No es un identificador único por host#
Un error común es asumir que ProgramId identifica una
instalación específica. No lo hace. Si un usuario instala
Notepad++ en cinco hosts, esos cinco hosts comparten un ProgramId
para Notepad++. Para distinguir instalaciones, necesitas fechas
de instalación, orígenes o rutas además de ProgramId.
Dónde vive ProgramId en la salida de AmcacheParser#
AmcacheParser expone ProgramId en cada CSV de categoría que lo
tenga:
| CSV | Uso de ProgramId |
|---|---|
*_UnassociatedFileEntries.csv |
La aplicación a la que un archivo dice pertenecer (incluso si falta el registro de aplicación padre). |
*_AssociatedFileEntries.csv |
La aplicación a la que el archivo está genuinamente asociado. |
*_ProgramEntries.csv |
La propia identidad de la aplicación (schema legacy). |
*_ShortcutEntries.csv |
La aplicación a la que apunta el acceso directo. |
Para pivotes, el patrón estándar es: identificar una fila
sospechosa en UnassociatedFileEntries, tomar su ProgramId y
ejecutar los patrones de consulta arriba.
Ver también#
- Referencia completa de Amcache — la visión general de alto nivel.
- Estructura del registro Amcache
— dónde se sitúa
ProgramIden el hive. - Amcache FileId explicado — el
identificador de hash de contenido que complementa a
ProgramId. - Marcas de tiempo de Amcache explicadas
— cómo acotar en el tiempo tus pivotes de
ProgramId. - Movimiento lateral y pivote
ProgramIdde Amcache — el playbook completo de hunt cross-host.
Para explorar valores ProgramId en tu propio hive sin instalar
nada, suelta un archivo en la página de inicio del parser —
nunca sale de tu navegador.
Artículos relacionados
- Volatility y Amcache: extraer el hive de imágenes de memoria
Una guía práctica para recuperar Amcache de una imagen de memoria de Windows usando Volatility — cuándo la recuperación del lado de memoria es la única opción, qué plugins usar y cómo entregar a AmcacheParser.
- Plugin amcache de RegRipper: qué hace y cuándo usarlo
Una guía práctica del plugin amcache de RegRipper — qué parsea, en qué se diferencia su salida de texto del CSV de AmcacheParser y cuándo recurrir a él en lugar de (o junto con) la herramienta de Zimmerman.
- ¿Qué es Amcache ProgramId? (glosario)
ProgramId es el hash de identidad de aplicación de 44 caracteres que Amcache asigna a cada aplicación lógica. El mismo ProgramId en hosts diferentes significa la misma instalación de aplicación.
- Las columnas de salida de AmcacheParser explicadas: cada campo CSV decodificado
Referencia campo por campo para la salida CSV de AmcacheParser — FileId, PathHash, ProgramId, LinkDate, BinFileVersion, IsPeFile y cualquier otra columna, con los pivotes que importan en DFIR.