FileId Amcache expliqué : le format de hash SHA-1 que Windows stocke
FileId dans Root\InventoryApplicationFile est l'un des champs les plus utiles de toute la ruche, et l'un des plus mal compris. C'est un hash de contenu. Ce n'est pas tout à fait un SHA-1 standard. Il ne hache pas tout à fait le fichier entier. Cette page est la référence complète.
Pour le contexte plus large, voir la Référence Amcache complète. Pour la structure du registre entourant tout cela dans la ruche, voir Structure du registre Amcache.
À quoi ressemble la valeur#
Un FileId typique d'une vraie ruche :
0000da39a3ee5e6b4b0d3255bfef95601890afd80709
41 caractères au total :
- Les quatre premiers sont toujours
"0000". Tag de type fixe. - Les 40 restants sont le digest hex SHA-1.
Le préfixe "0000" est un artefact historique. Les premiers builds de l'appraiser anticipaient plusieurs algorithmes de hash avec différents préfixes. Seul SHA-1 a été expédié. Le préfixe est constant depuis des années.
AmcacheParser scinde cela en deux colonnes CSV :
| Colonne | Valeur |
|---|---|
FileId |
Chaîne complète de 41 caractères avec préfixe. |
Hash |
40 caractères hex, SHA-1 seul. |
Utilisez toujours Hash (ou retirez le préfixe vous-même) pour joindre contre des feeds externes. VirusTotal, feeds TI, bases d'allowlist veulent tous du SHA-1 sur 40 caractères. Ils ne matcheront rien en silence si vous incluez les "0000".
Ce qu'il hache réellement#
Le piège qui attrape presque tout nouvel analyste :
Le SHA-1 hache les 31 premiers MiB du fichier, pas le fichier entier.
Pour les fichiers plus petits que 31 MiB (la plupart des EXE et DLL), le hash de préfixe équivaut au SHA-1 du fichier entier. Indistinguables.
Pour les fichiers plus gros, la valeur d'Amcache est un hash de préfixe. Toujours assez distinctif pour identifier un build précis d'un binaire précis. Mais ce n'est pas ce que sha1sum vous donnerait sur le fichier complet.
Pourquoi ça compte#
- Matches VirusTotal. Sous 31 MiB, le SHA-1 Amcache correspond au SHA-1 indexé par VT. Les fichiers plus gros (installeurs, certains binaires de jeu, gros logiciels entreprise) ne matchent souvent pas, et une réponse "pas d'enregistrement" de VT ne signifie rien d'utile.
- Bases de hashes maison. Si vous maintenez une allowlist interne, stockez le même type de hash que celui contre lequel vous comparerez. Soit stockez des SHA-1 de contenu complet (et acceptez les mismatches sur gros binaires), soit maintenez une colonne parallèle de hash de préfixe.
- Vérification. Si vous avez le binaire d'origine et voulez vérifier, hachez uniquement les 31 premiers MiB :
import hashlib
PREFIX_BYTES = 31 * 1024 * 1024
def amcache_sha1(path: str) -> str:
h = hashlib.sha1()
with open(path, 'rb') as f:
h.update(f.read(PREFIX_BYTES))
return h.hexdigest()Pièges du monde réel#
Une poignée d'écueils qui apparaissent sur les vrais dossiers.
N'incluez pas le préfixe dans les lookups#
# Faux
search_virustotal('0000da39a3ee5e6b4b0d3255bfef95601890afd80709')
# Juste
search_virustotal('da39a3ee5e6b4b0d3255bfef95601890afd80709')L'API VirusTotal attend le hash nu. Inclure le préfixe renvoie en silence un résultat vide, identique à "ce fichier est inconnu". Ça gaspille du temps de triage et produit des conclusions fausses.
Les collisions SHA-1 sont théoriques mais pas impossibles#
Des attaques de collision SHA-1 réelles existent. Dans un contexte non adversarial, c'est sans objet. Trouver une collision contre une entrée Amcache précise est absurdement disproportionné par rapport à ce qu'un attaquant y gagne. Mais pour un matching à haute confiance dans une investigation à fort enjeu, ne traitez pas un match SHA-1 comme une identité cryptographique. Combinez avec la taille du fichier, le link date et au moins un autre champ.
Ne faites pas confiance au FileId d'une ligne non-PE#
Amcache enregistre parfois des valeurs FileId pour des fichiers non-PE que l'appraiser a vus. Le hash est toujours réel, mais les outils en aval qui supposent un contexte PE (recherches PE-aware de VirusTotal, règles Yara contre octets PE) renvoient des résultats moins utiles.
Plusieurs lignes, même hash#
Si vous trouvez le même Hash sur plusieurs lignes *_UnassociatedFileEntries.csv sur le même hôte, c'est significatif. Le même contenu binaire a été inventorié à plusieurs chemins. Raisons courantes :
- L'attaquant a copié l'outil à plusieurs endroits pour tester celui qui s'exécute.
- Un installeur légitime a déposé la même DLL dans plusieurs répertoires produit.
- Un utilisateur a copié un fichier manuellement.
Cluster par Hash, puis regarder FullPath et KeyLastWriteTimestamp pour chaque instance. Les timestamps donnent la séquence. Les chemins donnent l'intention.
Plusieurs hashes, même FullPath#
Le pattern inverse. Même chemin, Hash différent sur plusieurs lignes signifie que le binaire à ce chemin a changé entre inventaires. Signal fort de remplacement de binaire :
- Légitime : mise à jour logicielle a écrasé le fichier.
- Suspect : l'attaquant a remplacé un binaire système ou un outil utilisateur exécuté régulièrement par une copie trojanisée.
Triez les lignes par KeyLastWriteTimestamp pour voir quand chaque nouveau hash est apparu. Corréler avec les événements de patch ou les événements Sysmon File Create autour de ces moments.
Pivots qui méritent leur place#
Chasse de hash inter-hôtes#
# Pivoter un SHA-1 connu-malveillant sur les CSV Amcache de chaque hôte
$badHash = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
Get-ChildItem -Recurse -Filter *_UnassociatedFileEntries.csv |
ForEach-Object {
Import-Csv $_.FullName |
Where-Object { $_.Hash -eq $badHash } |
Select @{n='Host';e={$_.PSChildName.Split('_')[0]}},
FullPath, KeyLastWriteTimestamp, Size
} |
Sort-Object HostC'est comme cela que vous passez de "on a trouvé ce hash sur un hôte" à "tous les hôtes du parc qui ont déjà eu ce binaire".
Enrichissement VirusTotal#
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) # rate-limit de l'API publique VTMême à bas volume contre l'API publique, on obtient une liste serrée de hashes confirmés-malveillants sur un hôte infecté typique.
Corrélation Sysmon Image Loaded#
L'Event ID 7 de Sysmon enregistre le SHA-1 de chaque DLL chargée par chaque processus. Joindre le Hash Amcache au champ Hashes de Sysmon 7 vous dit exactement quels processus ont chargé une DLL d'attaquant donnée, et quand.
Pour aller plus loin#
- Documentation de l'API VirusTotal pour l'endpoint de lookup de hash v3.
- Deep dive Amcache.hve de Yogesh Khatri.
- Le projet HashLookup au CIRCL.
Liens#
Articles liés
- Qu'est-ce que le FileId Amcache ? (glossaire)
FileId, c'est '0000' plus le SHA-1 des 31 premiers MiB du fichier. Retirez le préfixe avant de taper VirusTotal, sinon il vous renverra rien en silence.
- Où se trouve Amcache.hve sur le disque (et comment le collecter)
Chemin : C:\Windows\AppCompat\Programs\Amcache.hve plus les fichiers .LOG. Toujours les trois. Et la bonne façon de collecter depuis un hôte vivant et depuis des clichés.
- Récupérer la preuve de binaires supprimés depuis Amcache
Amcache survit aux binaires qu'elle enregistre. Chemin, SHA-1, éditeur, link date et moment d'inventaire persistent des mois après que l'attaquant a effacé le fichier. Le workflow pratique.
- Amcache : la référence forensique complète de la ruche Windows .hve
Amcache est la ruche dans laquelle le Compatibility Appraiser inscrit chaque PE sur disque, avec SHA-1, chemin complet, éditeur, link date et un horodatage d'écriture de clé. La référence, du format à l'usage investigatif.