Aller au contenu

Chapitre 4 — Détection de malwares par machine learning

Présentation de ce chapitre

🖥 Ouvrir les diapositives

1. Limites de la détection par signatures pour les malwares

Les antivirus traditionnels reposent largement sur des signatures (empreintes de fichiers malveillants connus). Cette approche est mise en échec par le polymorphisme (le malware modifie son code à chaque propagation tout en gardant le même comportement) et le métamorphisme, ainsi que par le volume considérable de nouvelles variantes produites quotidiennement, rendant la maintenance d'une base de signatures exhaustive impraticable.

1.1 Signatures « exactes » vs signatures « floues »

Il est utile de distinguer plusieurs générations de signatures pour comprendre pourquoi le ML s'est imposé comme complément :

  • Signatures cryptographiques exactes (empreinte MD5/SHA-256 d'un fichier connu) : très rapides à vérifier, mais rendues inefficaces par la moindre modification du fichier, même triviale (un seul octet changé produit une empreinte totalement différente).
  • Signatures floues (fuzzy hashing, ex. ssdeep) : tolèrent de petites variations entre fichiers similaires, offrant une résistance partielle au polymorphisme simple, mais restent limitées face à des transformations plus profondes du code.
  • Règles YARA : combinent des motifs textuels ou binaires (chaînes de caractères, séquences d'octets) avec une logique booléenne, permettant de couvrir des familles entières de malwares partageant des caractéristiques communes, mais nécessitant une expertise humaine pour être rédigées et maintenues à jour.

Le ML se positionne en complément de ces approches : plutôt que de rechercher une correspondance exacte ou approximative à un motif connu, il apprend à généraliser à partir d'exemples pour reconnaître des caractéristiques statistiquement associées aux comportements malveillants, y compris sur des fichiers jamais rencontrés auparavant.

2. Deux approches d'analyse pour l'extraction de caractéristiques

Approche Principe Avantage Limite
Analyse statique examen du fichier sans l'exécuter (structure du binaire, chaînes de caractères, imports de fonctions système, entropie) rapide, sans risque d'exécution contournable par obfuscation, chiffrement du code (packers)
Analyse dynamique exécution du fichier dans un environnement contrôlé (sandbox) et observation du comportement (appels système, connexions réseau, modifications de fichiers/registre) détecte le comportement réel, résiste mieux à l'obfuscation plus lente, coûteuse en ressources, certains malwares détectent la sandbox et modifient leur comportement

2.1 Une troisième voie : l'analyse hybride

De nombreux systèmes de détection modernes ne choisissent pas entre analyse statique et dynamique, mais les combinent en une analyse hybride, souvent structurée en cascade pour optimiser le compromis rapidité/précision :

  1. Une première passe statique, rapide et peu coûteuse, filtre la grande majorité des fichiers manifestement sains ou manifestement suspects (score très élevé ou très faible).
  2. Seuls les fichiers dans une zone d'incertitude (score intermédiaire) sont soumis à une analyse dynamique en sandbox, plus coûteuse mais plus fiable, ce qui limite le volume de fichiers nécessitant cette étape onéreuse.

Cette architecture en cascade illustre un principe général en sécurité opérationnelle : combiner un filtre rapide et peu coûteux avec une analyse approfondie réservée aux cas ambigus, plutôt que d'appliquer uniformément la méthode la plus coûteuse à l'ensemble du flux.

3. Caractéristiques exploitées en analyse statique

  • Métadonnées du fichier (taille, en-têtes, section PE pour les exécutables Windows).
  • Entropie du fichier ou de ses sections (une entropie élevée peut indiquer un chiffrement/compression, fréquent dans les malwares packés).
  • N-grammes d'octets ou d'instructions assembleur.
  • Fonctions de l'API système importées (ex. appels réseau, manipulation de la mémoire, techniques d'injection de processus).

3.1 L'entropie, un indicateur simple mais puissant

L'entropie de Shannon mesure le degré de « désordre » ou d'imprévisibilité d'une séquence d'octets. Pour une section de fichier donnée, elle se calcule à partir de la distribution de fréquence des valeurs d'octets (0 à 255) :

$$H = -\sum_{i=0}^{255} p_i \log_2(p_i)$$

où $p_i$ est la fréquence relative de la valeur d'octet $i$ dans la section considérée. Une valeur proche de 8 (le maximum théorique pour des octets sur 8 bits) indique une distribution quasi uniforme des valeurs d'octets, typique de données chiffrées ou fortement compressées ; à l'inverse, du code exécutable ou du texte non compressé présente généralement une entropie plus modérée, car certaines valeurs d'octets (instructions fréquentes, caractères communs) reviennent plus souvent que d'autres.

import numpy as np

def entropie_shannon(donnees_octets: bytes) -> float:
    """Calcule l'entropie de Shannon (en bits) d'une séquence d'octets."""
    if len(donnees_octets) == 0:
        return 0.0
    valeurs, comptes = np.unique(
        np.frombuffer(donnees_octets, dtype=np.uint8), return_counts=True
    )
    probabilites = comptes / len(donnees_octets)
    return -np.sum(probabilites * np.log2(probabilites))

# Exemple pédagogique
with open("exemple_binaire.exe", "rb") as f:
    contenu = f.read()

print(f"Entropie globale du fichier : {entropie_shannon(contenu):.2f} bits")

En pratique, on calcule souvent l'entropie section par section (plutôt que sur le fichier entier) pour repérer une section spécifique anormalement chiffrée au sein d'un exécutable par ailleurs normal — une signature typique d'un packer utilisé pour dissimuler le code malveillant réel. L'entropie n'est cependant qu'un indicateur parmi d'autres : de nombreux logiciels légitimes utilisent également compression et chiffrement (mises à jour logicielles, protections anti-piratage), d'où un risque de faux positifs si elle est utilisée isolément.

3.2 N-grammes d'octets : principe et compromis

Un n-gramme d'octets est une sous-séquence contiguë de n octets consécutifs extraite du fichier. En comptant la fréquence de chaque n-gramme observé (souvent pour n = 2, 3 ou 4), on construit un vecteur de caractéristiques numériques exploitable par un modèle de classification, de façon conceptuellement proche du bag-of-words utilisé en NLP (chapitre 5) mais appliqué à des octets plutôt qu'à des mots.

from collections import Counter

def compte_ngrammes(donnees_octets: bytes, n: int = 3) -> Counter:
    """Compte les n-grammes d'octets consécutifs dans un fichier binaire."""
    return Counter(
        donnees_octets[i:i + n] for i in range(len(donnees_octets) - n + 1)
    )

ngrammes = compte_ngrammes(contenu, n=3)
ngrammes_frequents = ngrammes.most_common(10)

Le principal compromis réside dans le choix de n : une valeur faible (n = 1 ou 2) capture peu d'information contextuelle mais reste peu coûteuse à calculer ; une valeur plus élevée capture des motifs plus spécifiques (proches de séquences d'instructions réelles) mais fait exploser le nombre de caractéristiques possibles ($256^n$ combinaisons théoriques), nécessitant des techniques de réduction de dimension (sélection des n-grammes les plus discriminants, hachage de caractéristiques) avant d'alimenter un modèle.

4. Caractéristiques exploitées en analyse dynamique (sandbox)

  • Séquence d'appels système (syscalls) effectués.
  • Connexions réseau initiées (domaines contactés, protocoles).
  • Modifications du système de fichiers et de la base de registre.
  • Techniques de persistance observées (création de tâches planifiées, clés de démarrage).

4.1 De la séquence brute au vecteur de caractéristiques

Une séquence d'appels système observée en sandbox peut être exploitée de deux façons principales, avec un arbitrage classique entre simplicité et richesse d'information :

  • Approche « sac d'appels » (bag-of-syscalls) : on compte simplement la fréquence de chaque type d'appel système observé pendant l'exécution, sans tenir compte de leur ordre — une approche simple, analogue au bag-of-words du NLP, mais qui perd toute l'information relative à la séquence des actions (par exemple, l'ordre « ouverture de fichier puis chiffrement puis suppression de l'original », caractéristique d'un ransomware, disparaît si l'on ne compte que les occurrences).
  • Approche séquentielle : on conserve l'ordre des appels et on utilise un modèle capable de traiter des séquences (chaînes de Markov, réseaux de neurones récurrents, Transformers), capturant ainsi des dépendances temporelles significatives du comportement malveillant, au prix d'une complexité de modélisation plus importante.

4.2 Techniques anti-sandbox employées par les malwares

Les auteurs de malwares connaissent l'existence des sandboxes d'analyse et développent des techniques pour les détecter ou les contourner, ce qui a une conséquence directe sur la fiabilité des caractéristiques dynamiques collectées :

  • Détection de l'environnement virtualisé : recherche d'artefacts propres aux machines virtuelles (pilotes spécifiques, adresses MAC caractéristiques, ressources matérielles limitées typiques d'un environnement de test).
  • Temporisation (sleep evasion) : le malware reste inactif pendant une durée dépassant le temps d'observation typique d'une sandbox automatisée, avant de déclencher son comportement réel.
  • Détection d'interaction humaine : certains malwares vérifient la présence de mouvements de souris, de documents récents ou d'un historique de navigation réaliste avant de s'activer, l'absence de ces signaux suggérant un environnement d'analyse automatisé plutôt qu'un poste utilisateur réel.

Ces techniques expliquent pourquoi un score de « comportement bénin » obtenu en sandbox ne garantit jamais l'innocuité réelle d'un fichier — un principe à retenir pour l'évaluation critique des résultats d'analyse dynamique.

5. Modèles utilisés

  • Classification supervisée (Random Forest, gradient boosting, réseaux de neurones) sur des caractéristiques extraites statiquement et/ou dynamiquement : approche la plus répandue dans les solutions commerciales (EDR de nouvelle génération).
  • Modèles de séquence (RNN, Transformers) pour modéliser directement la séquence d'appels système observée en sandbox, capturant mieux les dépendances temporelles du comportement.
  • Clustering de familles de malwares pour regrouper des variantes proches et prioriser l'analyse humaine.

5.1 Exemple pédagogique : classifieur sur caractéristiques statiques

L'extrait suivant illustre, sur un jeu de caractéristiques statiques fictif, l'entraînement d'un classifieur de gradient boosting — une famille d'algorithmes fréquemment utilisée en pratique pour ce type de problème car elle combine bonne performance et robustesse aux variables hétérogènes (numériques et catégorielles mélangées) :

from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import cross_val_score

# X : caractéristiques statiques (entropie par section, taille,
# nombre de fonctions importées suspectes, présence d'un packer connu, ...)
# y : 1 = malveillant, 0 = sain (exemple pédagogique)
modele = GradientBoostingClassifier(
    n_estimators=300, max_depth=4, learning_rate=0.05, random_state=42
)

scores = cross_val_score(modele, X, y, cv=5, scoring="f1")
print(f"F1-score moyen (validation croisée) : {scores.mean():.3f}")

modele.fit(X, y)

# Importance des variables : utile pour comprendre quelles
# caractéristiques statiques pèsent le plus dans la décision
importances = sorted(
    zip(X.columns, modele.feature_importances_), key=lambda t: -t[1]
)
print("Caractéristiques les plus discriminantes :", importances[:5])

L'inspection de l'importance des variables (feature_importances_) est particulièrement utile en détection de malwares : elle permet de vérifier, avant tout déploiement, que le modèle s'appuie bien sur des caractéristiques légitimement liées au comportement malveillant, et non sur un artefact fortuit du jeu de données d'entraînement (par exemple, une caractéristique corrélée par hasard avec la source d'où proviennent les échantillons collectés, plutôt qu'avec leur nature réellement malveillante).

6. Techniques d'évasion contre les détecteurs ML

  • Obfuscation et packing : rend l'analyse statique moins efficace en masquant les caractéristiques exploitables.
  • Détection d'environnement virtualisé/sandbox : le malware modifie son comportement (ou reste inactif) s'il détecte qu'il s'exécute dans un environnement d'analyse.
  • Exemples adversariaux : modification minime d'un binaire (ajout d'octets inoffensifs, réorganisation de sections) pour franchir la frontière de décision d'un modèle sans changer le comportement malveillant réel — approfondi au chapitre 6.

6.1 Pourquoi les exemples adversariaux sont particulièrement efficaces contre les modèles statiques

Une caractéristique propre au domaine des malwares (contrairement, par exemple, à la classification d'images) est l'existence de nombreuses transformations qui modifient les caractéristiques statiques extraites sans modifier le comportement fonctionnel du fichier : ajout d'octets inutilisés en fin de fichier, insertion de sections vides, réordonnancement de sections non référencées par le code, ajout de chaînes de caractères inoffensives. Ces transformations peuvent suffire à déplacer un fichier au-delà de la frontière de décision d'un modèle statique entraîné sur des caractéristiques superficielles (taille, entropie globale, présence de certaines chaînes), sans que le fichier cesse d'être malveillant à l'exécution.

Ce constat a une conséquence pédagogique importante : un modèle de détection statique performant sur un jeu de test doit être évalué non seulement sur sa performance brute, mais aussi sur sa robustesse face à ce type de manipulation triviale — une dimension d'évaluation trop souvent négligée dans les démonstrations commerciales de solutions de détection.

7. Limites et bonnes pratiques

Un détecteur ML de malwares doit être régulièrement réentraîné (nouvelles familles), évalué sur des échantillons réellement représentatifs (pas seulement des échantillons « faciles »), et combiné avec des mécanismes complémentaires (réputation de fichiers, analyse comportementale en production, threat intelligence) plutôt qu'utilisé comme unique ligne de défense.

7.1 Le biais de collecte des échantillons d'entraînement

Un piège méthodologique fréquent dans la constitution d'un jeu de données de malwares mérite une attention particulière : les échantillons « bénins » et « malveillants » proviennent souvent de sources très différentes (par exemple, des logiciels sains téléchargés depuis un dépôt officiel d'un côté, des échantillons malveillants soumis à un service d'analyse en ligne de l'autre). Un modèle entraîné sur un tel jeu de données risque d'apprendre à distinguer la source de collecte plutôt que la nature réellement malveillante du fichier (par exemple, des différences systématiques de format de compilation, de signature numérique, ou de métadonnées propres à chaque source) — un phénomène apparenté au raccourci d'apprentissage (shortcut learning) documenté dans d'autres domaines du machine learning. Une performance apparemment excellente en test peut ainsi masquer une généralisation très faible en conditions réelles.

La bonne pratique consiste à constituer, autant que possible, des échantillons bénins et malveillants issus de contextes de collecte comparables, et à évaluer systématiquement le modèle sur des familles de malwares et des sources absentes de l'ensemble d'entraînement, pour estimer sa capacité de généralisation réelle plutôt que sa capacité à reconnaître les biais du jeu de données.

À retenir

  • L'analyse statique est rapide mais contournable par obfuscation ; l'analyse dynamique observe le comportement réel mais coûte plus cher et peut être détectée par le malware ; l'analyse hybride en cascade combine les deux pour optimiser le compromis coût/précision.
  • L'entropie et les n-grammes d'octets sont des caractéristiques statiques simples mais puissantes ; leur interprétation nécessite néanmoins prudence (compression légitime, choix du paramètre n).
  • Les malwares emploient des techniques actives de détection de sandbox, ce qui limite la fiabilité d'un verdict « bénin » obtenu uniquement par analyse dynamique automatisée.
  • Les modèles de classification supervisée sur caractéristiques extraites sont l'approche la plus répandue en pratique ; l'inspection de l'importance des variables aide à détecter un apprentissage fondé sur des artefacts non pertinents du jeu de données.
  • Les techniques d'évasion (obfuscation, détection de sandbox, exemples adversariaux) rappellent qu'un détecteur ML n'est jamais une solution unique et définitive.
  • Le biais de collecte entre échantillons sains et malveillants est un piège méthodologique fréquent, pouvant conduire un modèle à apprendre la source des données plutôt que leur nature réellement malveillante.

Dr. Zakaria Sawadogo — École Polytechnique de Ouagadougou