ProgramId Amcache expliqué : l'identité applicative de 44 caractères
Le champ ProgramId dans Root\InventoryApplicationFile et
Root\InventoryApplication est l'identité applicative logique
d'Amcache. C'est une chaîne hexadécimale de 44 caractères qui
identifie de manière unique une application — et, surtout, elle est
déterministe : la même application sur un hôte différent obtient
généralement le même ProgramId. Cela en fait l'un des pivots
cross-hôtes les plus utiles de toute la trousse à outils DFIR
Windows.
Cette page est la référence complète : ce qu'est la valeur, comment Windows la construit, comment l'utiliser dans une enquête mono-hôte, et comment la pivoter dans un environnement lors d'un hunt.
Pour le contexte Amcache plus large, voir la référence complète Amcache ; pour la structure de registre environnante, voir Structure du registre Amcache.
À quoi ressemble la valeur#
Un ProgramId typique issu d'une ruche réelle :
0006fa0b2a9f8a4eb9d7c81e8b1f3c5d3e2a0000ffff
44 caractères hexadécimaux, sans préfixe, sans délimiteurs. Chaque
entrée dans InventoryApplicationFile en porte un ; chaque entrée
dans InventoryApplication est indexée par un. Les deux se lient
via la valeur partagée : le ProgramId d'un fichier vous dit à quelle
application installée il appartient.
Structure des 44 caractères#
La valeur n'est pas un hash uniforme unique. Elle encode plusieurs composants, en gros :
- Une étiquette de type / version (les premiers caractères).
- Un hash des attributs identifiants de l'application — principalement nom, éditeur, version et langue.
- Un discriminateur final (souvent
0000ffffou similaire) utilisé par Windows pour une classification interne.
La construction exacte a évolué selon les builds Windows et n'est pas entièrement documentée par Microsoft. Pour les besoins DFIR, les règles pratiques sont :
- Deux enregistrements avec le même
ProgramIdconcernent la même application. - Le
ProgramIdest stable entre hôtes pour le même install d'application — Office 365 sur l'hôte A et le même build Office 365 sur l'hôte B partagent unProgramId. - Le
ProgramIdn'est pas stable entre mises à niveau majeures — la mise à niveau de l'application change généralement sonProgramId.
Utiliser ProgramId sur un hôte unique#
L'usage phare est joindre un fichier à son enregistrement applicatif.
Fichier → application#
Vous avez trouvé une ligne suspecte dans
*_UnassociatedFileEntries.csv. Son ProgramId est
0006fa0b2a9f8a4eb9d7c81e8b1f3c5d3e2a0000ffff.
Cherchez le même ProgramId dans *_AssociatedFileEntries.csv et
dans le catalogue d'application parent (la clé du registre
Root\InventoryApplication\<ProgramId>, ou le CSV équivalent si votre
analyseur en émet un). Vous obtenez typiquement :
- Le nom d'affichage et l'éditeur de l'application.
- La date d'installation.
- La source d'installation (parfois une URL de téléchargement).
- La liste complète des fichiers associés à cette application.
C'est inestimable quand un attaquant dépose un outil qui se fait
passer pour une application légitime. Le nom de fichier et les
métadonnées peuvent dire « AdobeReaderUpdater.exe / Adobe Inc. »,
mais son ProgramId ne correspond à aucun produit Adobe installé
(suspect) ou correspond à une application différente de ce que
son nom suggère (très suspect).
Application → fichiers#
Le pivot inverse est tout aussi utile. Vous avez trouvé un
enregistrement applicatif suspect dans InventoryApplication —
peut-être un build portable de quelque chose avec un éditeur "" et
une source d'installation inhabituelle. Prenez son ProgramId et
listez chaque fichier qui le partage :
$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, KeyLastWriteTimestampVous obtenez l'empreinte fichier complète de cette application telle que l'appraiser l'a vue — chaque EXE, DLL et PE que l'appraiser a rattaché à cette application. Pour l'outillage attaquant, c'est souvent le moyen le plus rapide d'énumérer l'ensemble complet des binaires déposés à partir d'un seul fichier observé.
Pivot cross-hôtes avec ProgramId#
C'est là que ProgramId brille comme primitive de hunt. Parce que
l'identité est stable entre hôtes pour la même application, un seul
ProgramId suspect sur un hôte devient une requête que vous pouvez
exécuter contre l'Amcache de chaque autre hôte :
$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 WhenC'est le pivot de mouvement latéral. Si un seul hôte a un
ProgramId suspect, exécuter cette requête sur vos CSVs Amcache
collectés vous dit chaque autre hôte sur lequel la même application
est apparue, avec chemins et heures — typiquement un signal plus
serré que les pivots par hash seul, car le ProgramId survit aux
petites variations du binaire (re-signing, recompilation avec les
mêmes nom/éditeur/version).
Pour le playbook complet de mouvement latéral, voir
Mouvement latéral et pivot avec le ProgramId Amcache.
Quand ProgramId est le plus utile#
Quelques patterns d'enquête où ProgramId est le bon pivot :
Même famille, builds multiples#
Un attaquant peut compiler son outil plusieurs fois avec les mêmes
métadonnées de nom, éditeur et version — seul le binaire change. Les
hashes diffèrent. Le ProgramId est le même. Le hash seul rate
la famille ; ProgramId l'attrape.
Binaires renommés#
mimikatz.exe → svchost64.exe → update.exe. Le nom de fichier
change ; les métadonnées PE embarquées sont les mêmes. Si l'attaquant
ne s'est pas embêté à nettoyer la ressource version-info, le
ProgramId reste le même.
Outils redéployés dans un environnement#
L'attaquant dépose le même outil sur 20 hôtes alors qu'il se déplace
latéralement. Les hashes peuvent correspondre, les chemins
généralement pas. Le ProgramId est l'identifiant le plus cohérent
sur les 20 hôtes.
Quand ProgramId est le mauvais pivot#
Quelques cas où ProgramId sous-performe :
Outils à métadonnées tournantes#
Si l'attaquant recompile avec des nom/éditeur/version différents à
chaque fois, chaque build obtient un ProgramId différent. Pour
ceux-là, le hash de contenu du fichier (le SHA-1 dans Hash) est
le meilleur pivot cross-hôtes, car au moins un composant du build est
identique.
Binaires living-off-the-land#
net.exe, psexec.exe, certutil.exe — outils légitimes
détournés. Chaque hôte qui a exécuté l'un d'entre eux a le même
ProgramId pour eux. Les correspondances ProgramId sont
essentiellement dénuées de sens ici. Pivotez plutôt sur la ligne de
commande (4688 / Sysmon 1) ou sur le chemin depuis lequel le
LOLBIN a été exécuté.
Binaires véritablement inédits#
Un fichier apparaissant pour la toute première fois n'importe où a un
ProgramId qu'aucun autre hôte ne partage. Sans corpus contre lequel
comparer, ProgramId ne fait rien ; hash plus Publisher = '' et IsPeFile = True et FullPath sous \Users\ est le filtre de
triage qui fonctionne.
Confusions courantes#
Deux choses que ProgramId n'est pas :
Pas un hash du binaire#
Hash (ou FileId) est le hash de contenu. ProgramId est un hash
d'identité applicative, calculé à partir des métadonnées, pas des
octets du binaire. Deux binaires complètement différents avec des
métadonnées identiques obtiennent le même ProgramId ; le même
binaire recompilé avec des métadonnées différentes obtient un
ProgramId différent.
Pas un identifiant unique par hôte#
Une erreur fréquente est de supposer que ProgramId identifie un
install spécifique. Ce n'est pas le cas. Si un utilisateur installe
Notepad++ sur cinq hôtes, ces cinq hôtes partagent un seul
ProgramId pour Notepad++. Pour distinguer les installs, vous avez
besoin des dates d'installation, des sources ou des chemins en plus
du ProgramId.
Où vit ProgramId dans la sortie d'AmcacheParser#
AmcacheParser expose ProgramId dans chaque CSV de catégorie qui
l'a :
| CSV | Usage de ProgramId |
|---|---|
*_UnassociatedFileEntries.csv |
L'application à laquelle un fichier prétend appartenir (même si l'enregistrement applicatif parent est manquant). |
*_AssociatedFileEntries.csv |
L'application à laquelle le fichier est véritablement associé. |
*_ProgramEntries.csv |
L'identité propre de l'application (schéma legacy). |
*_ShortcutEntries.csv |
L'application sur laquelle pointe le raccourci. |
Pour les pivots, le pattern standard est : identifier une ligne
suspecte dans UnassociatedFileEntries, prendre son ProgramId, et
exécuter les patterns de requête ci-dessus.
Voir aussi#
- Référence complète Amcache — la vue d'ensemble haut niveau.
- Structure du registre Amcache —
où se trouve
ProgramIddans la ruche. - FileId Amcache expliqué —
l'identifiant de hash de contenu qui complète
ProgramId. - Horodatages Amcache expliqués
— comment borner dans le temps vos pivots
ProgramId. - Mouvement latéral et pivot avec le
ProgramIdAmcache — le playbook complet de hunt cross-hôtes.
Pour explorer les valeurs ProgramId sur votre propre ruche sans
rien installer, déposez un fichier sur la
page d'accueil de l'analyseur — il ne quitte jamais votre
navigateur.
Articles liés
- Volatility et Amcache : extraire la ruche depuis des images mémoire
Un guide pratique pour récupérer Amcache depuis une image mémoire Windows en utilisant Volatility — quand la récupération côté mémoire est la seule option, quels plugins utiliser, et comment passer le relais à AmcacheParser.
- Plugin amcache de RegRipper : ce qu'il fait et quand l'utiliser
Un guide pratique sur le plugin amcache de RegRipper — ce qu'il analyse, comment sa sortie texte diffère du CSV d'AmcacheParser, et quand l'utiliser à la place (ou en complément) de l'outil Zimmerman.
- Qu'est-ce que le ProgramId Amcache ? (glossaire)
ProgramId est le hash d'identité applicative de 44 caractères qu'Amcache attribue à chaque application logique. Le même ProgramId sur différents hôtes signifie la même installation d'application.
- Les colonnes de sortie d'AmcacheParser expliquées : chaque champ CSV décodé
Référence champ par champ pour la sortie CSV d'AmcacheParser — FileId, PathHash, ProgramId, LinkDate, BinFileVersion, IsPeFile et toutes les autres colonnes, avec les pivots qui comptent en DFIR.