Imphash, Rich header et TLSH : regrouper les échantillons
Comment l'imphash, l'empreinte du Rich header et TLSH regroupent des exécutables Windows apparentés, comment chacun se calcule et où il atteint ses limites.
En bref. Un SHA-256 change dès qu'un octet change : il ne peut donc pas vous dire que deux fichiers sont apparentés. Trois autres empreintes le peuvent : l'imphash (ce que le programme importe), l'empreinte du Rich header (quels composants de la chaîne de compilation Microsoft l'ont produit) et TLSH (à quel point les octets se ressemblent). Chacune a des défaillances connues. Utilisez-les pour former des groupes, puis confirmez avec d'autres éléments.
Imphash : l'empreinte des imports
Mandiant a introduit l'empreinte des imports en 2014 (Tracking Malware with Import Hashing). L'implémentation la plus utilisée est get_imphash() dans pefile :
- Pour chaque DLL importée, dans l'ordre du fichier, prendre le nom en minuscules et retirer l'extension
.dll,.ocxou.sys. - Pour chaque fonction, prendre son nom en minuscules. Les fonctions importées par ordinal sont nommées d'après les tables de pefile pour
ws2_32,wsock32etoleaut32, et écritesordNdans les autres cas. - Joindre les paires
dll.functionpar des virgules et calculer le MD5.
Comme le linker écrit les imports dans l'ordre où le code les utilise, les builds issus d'une même arborescence de sources tendent à partager un imphash, alors que des programmes sans rapport le partagent rarement. Dans l'échantillon chargé par le PE Parser, les deux builds de m64.exe ont des SHA-256 différents mais le même imphash, et le tableau du lot les étiquette family 1.
Ses limites : les fichiers packés (l'imphash décrit le stub du packer, partagé par des milliers d'échantillons sans rapport), les assemblies .NET (elles n'importent que mscoree.dll!_CorExeMain), et les très petits programmes dont les quelques imports sont communs à tous. Les imports en chargement différé (delay-load) ne font pas partie de l'imphash de pefile. Voir l'entrée du glossaire sur l'imphash.
Empreinte du Rich header : la signature de la chaîne de compilation
Le linker de Microsoft écrit un bloc non documenté dans le stub DOS : une liste de valeurs comp.id (identifiant de produit et numéro de build de chaque compilateur, assembleur, linker et bibliothèque d'import ayant fourni des objets), chacune avec un compteur, masquée par XOR avec une clé et terminée par le mot Rich. La clé n'est pas aléatoire : c'est une somme de contrôle de l'en-tête DOS et des entrées, comme l'a décrit Daniel Pistelli dans Microsoft's Rich Signature (undocumented).
Cela apporte deux choses :
- une empreinte du Rich header (
get_rich_header_hash()de pefile : MD5 de l'en-tête décodé), partagée par les programmes compilés avec la même combinaison d'outils — souvent le même projet ; - un contrôle de cohérence : si la clé stockée ne correspond pas à la somme de contrôle recalculée, l'en-tête a été modifié ou transplanté.
La falsification est une réalité. Kaspersky a montré que l'échantillon d'Olympic Destroyer portait un Rich header copié depuis une autre famille pour tromper l'attribution (The devil's in the Rich header). Des travaux comme ceux de Webster et al., Finding the Needle: A Study of the PE32 Rich Header and Respective Malware Triage (DIMVA 2017), montrent son efficacité de regroupement en pratique. L'entrée sur le Rich header résume le format ; PE Parser traduit les comp.id en versions de Visual Studio grâce à la liste publique maintenue par le projet richprint.
Ses limites : les chaînes de compilation non Microsoft (MinGW, Go, Rust avec la cible GNU, Delphi) n'écrivent pas de Rich header, et celui-ci peut être supprimé ou mis à zéro.
TLSH : l'empreinte de similarité des octets
TLSH (Trend Micro Locality Sensitive Hash) résume la distribution des trigrammes d'octets en un condensé de 70 chiffres hexadécimaux, préfixé par T1. Deux condensés se comparent par une distance : 0 signifie identique, et plus elle est faible, plus les fichiers se ressemblent. Les variantes proches d'un même programme obtiennent généralement de faibles distances ; il n'existe pas de seuil universel, calibrez-vous donc sur des fichiers dont vous savez qu'ils sont apparentés ou non dans votre propre collection. TLSH a besoin d'au moins 50 octets suffisamment variés pour produire un condensé.
La vue de comparaison de PE Parser affiche la distance TLSH entre deux fichiers chargés quelconques. ssdeep, l'autre hachage flou courant, n'est pas inclus : son implémentation de référence est sous licence GPL, et nous n'en avons pas trouvé sous licence permissive.
Ses limites : le packing ou la compression modifient entièrement les octets ; de grosses ressources partagées (icônes, runtimes embarqués) peuvent faire paraître proches des fichiers sans rapport.
Les combiner
| Empreinte | Regroupe par | Résiste à la recompilation | Résiste au packing | Falsifiable |
|---|---|---|---|---|
| SHA-256 | octets exacts | non | non | non |
| Imphash | liste des imports | souvent | non (hache le stub) | oui, facilement |
| Empreinte du Rich header | combinaison d'outils | souvent | parfois (le stub peut le conserver) | oui |
| TLSH | distribution des octets | en partie | non | avec effort |
Une démarche solide : regrouper une collection par imphash et empreinte du Rich header, vérifier les distances TLSH et les horodatages de chaque groupe (horodatages PE), et seulement ensuite écrire « même famille » dans un rapport — en listant les éléments de preuve.
FAQ
Qu'est-ce qu'un imphash ?
Un MD5 de la liste ordonnée des fonctions importées, écrites sous forme de paires dll.fonction en minuscules jointes par des virgules. Deux builds du même programme le partagent souvent, même quand chaque octet de leur code diffère.
Le Rich header est-il fiable pour l'attribution ?
C'est un indice utile, mais il peut être copié ou falsifié : le malware Olympic Destroyer portait un Rich header emprunté à une autre famille. Vérifiez la cohérence de sa somme de contrôle et mettez-le en balance avec d'autres éléments.
Pourquoi PE Parser ne propose-t-il pas ssdeep ?
L'implémentation de référence de ssdeep est sous licence GPL et nous n'avons trouvé aucune implémentation sous licence permissive ; l'outil utilise donc TLSH (Apache-2.0) pour la similarité.