# Internals EDR : architecture de télémétrie et limites de l'évasion
> Une analyse sourcée des chemins de télémétrie EDR sous Windows, de leurs contrats documentés, de leurs limites d'application et de leur validation en red team.
Publié le 2026-07-21 | Tags: edr, windows, internals, red team, recherche
https://xsec.fr/evasion/edr-internals-technical-review/
---
import EdrTechnicalInfographic from '@shared/components/EdrTechnicalInfographic.astro'
import Callout from '@shared/components/Callout.astro'
> Une analyse sourcée des chemins de télémétrie Endpoint Detection and Response (EDR, détection et réponse sur les endpoints, c'est-à-dire les postes et serveurs supervisés) sous Windows, de leurs contrats documentés, de leurs limites d'application et d'une méthodologie de validation en red team.
Considérons une séquence courte : un processus démarre, mappe une image, ouvre un handle vers un autre processus, crée un thread, écrit un fichier puis établit une connexion réseau. Du point de vue d'un opérateur, il peut s'agir d'une seule action. Windows l'expose comme des transitions d'état séparées, observées à des couches et à des instants différents, avec des garanties différentes. Le système d'exploitation ne transmet pas une « attaque » à l'EDR. Celui-ci la reconstruit à partir d'événements incomplets.
Un **processus** est une instance en cours d'exécution d'un programme ; un **thread** est l'un des fils d'exécution à l'intérieur de ce processus. Une **image** est ici un fichier exécutable ou une bibliothèque mappée en mémoire, ce qui signifie que Windows associe ses pages à des adresses virtuelles du processus. Un **objet Windows** est une entité gérée par le système, par exemple un processus, un thread ou un fichier ; un **handle** est la référence accordée à un processus pour manipuler cet objet avec des droits précis.
Cette distinction constitue le fil conducteur de l'article. Un **callback** est une fonction qu'un composant enregistre auprès de Windows afin que le système l'appelle automatiquement lorsqu'une opération précise se produit. Un **hook** intercepte au contraire un chemin d'exécution existant pour observer ou modifier l'appel avant de rendre la main au code original. La question utile est donc ce que chaque mécanisme peut connaître à cet instant, ce qu'il peut modifier, ce qui peut disparaître avant l'analyse et quels signaux indépendants subsistent s'il est contourné.
Les solutions Endpoint Detection and Response combinent plusieurs mécanismes d'observation et d'application de politiques. Un **schéma d'événement** définit les champs, leurs types et leur signification ; la **mise en mémoire tampon** conserve temporairement les événements lorsque leur producteur et leur lecteur n'avancent pas au même rythme. Aucune architecture unique ne décrit tous les produits : l'emplacement des capteurs, ces schémas et buffers, les dépendances cloud et les capacités de réponse restent spécifiques à chaque implémentation. Les interfaces Windows sur lesquelles de nombreux produits s'appuient sont néanmoins suffisamment documentées pour établir une base technique précise.
La **télémétrie** désigne les données techniques produites pendant l'exécution, par exemple une création de processus, un accès à un fichier ou une connexion. Un **capteur** collecte une partie de ces données. L'**agent EDR** est l'ensemble des composants installés sur l'endpoint ; son service local et le **backend**, c'est-à-dire le moteur d'analyse placé derrière l'agent, normalisent et relient les événements pour produire une détection.
Cet article distingue trois classes de preuves :
1. **Les contrats documentés** regroupent les interfaces de programmation d'applications (Application Programming Interface, API) Windows publiques, que les programmes appellent, et les interfaces de drivers de périphériques (Device Driver Interface, DDI), qui définissent comment un driver dialogue avec le **noyau**, la partie centrale et privilégiée du système. Les signatures de callbacks et les règles d'ordonnancement font aussi partie de ces contrats. Ils constituent le fondement le plus solide des affirmations architecturales.
2. **Les détails d'implémentation observés** comprennent les symboles privés, tableaux internes, offsets de structures et routines produit obtenues par reverse engineering, c'est-à-dire par l'étude du binaire et de son exécution lorsque le code source n'est pas disponible. Un **symbole de débogage** associe une adresse machine à un nom de fonction, de variable ou de type ; privé signifie ici qu'il ne constitue pas une interface publique supportée. Un **offset** est la distance d'un champ par rapport au début d'une structure ; son **layout** est l'organisation complète des champs en mémoire. Un **build** est une version compilée précise du logiciel. Ces détails ne sont valides que pour les builds Windows et produit examinés.
3. **Le comportement produit** correspond à la télémétrie réellement conservée, enrichie, transmise et évaluée par une version et une politique EDR précises. Il doit être mesuré et ne peut pas être déduit de la seule disponibilité d'un callback.
La sixième édition de *Windows Internals* couvre Windows 7 et Windows Server 2008 R2. Elle reste utile pour les concepts architecturaux, mais ne constitue pas un contrat d'implémentation actuel. Le Windows Driver Kit (WDK) regroupe la documentation, les en-têtes et les outils nécessaires au développement de drivers Windows ; sa documentation courante et la septième édition de *Windows Internals* prévalent pour les interfaces supportées. WinDbg est le débogueur Microsoft utilisé pour observer l'état et l'exécution de Windows. Les symboles privés, offsets et observations tirés du débogage restent propres au build examiné.
Une structure non documentée observée dans WinDbg établit seulement le comportement du build examiné. Une DDI supportée établit un contrat ; l'implémentation d'un fournisseur exige encore une mesure directe.
## Architecture EDR multicouche
Une architecture EDR se comprend plus facilement en séparant les lieux où un comportement se produit, ceux où il peut être observé et ceux où il est finalement interprété. Un produit associe généralement un service en mode utilisateur à un ou plusieurs drivers en mode noyau, puis transmet une partie de leurs événements à un moteur d'analyse local ou distant. Cette description est un modèle fréquent, pas une spécification commune à tous les fournisseurs.
### Deux domaines d'exécution
Le **mode utilisateur** héberge les applications ordinaires et la majorité des services. Chaque processus y dispose de son propre **espace d'adressage**, l'ensemble isolé des adresses de mémoire virtuelle qu'il peut utiliser, et ne peut pas accéder directement à la mémoire du noyau. Un capteur user-mode peut observer des fonctions qu'un processus appelle, analyser certaines zones de sa mémoire ou recevoir des événements publiés par Windows. Sa visibilité dépend néanmoins du processus instrumenté et du chemin d'exécution réellement emprunté.
Le **mode noyau** exécute le cœur de Windows et les drivers. Un **driver** est un module privilégié qui permet au noyau de gérer un périphérique ou d'étendre une fonction du système. Un driver EDR peut s'enregistrer auprès de mécanismes documentés pour observer la création des processus, les accès aux objets, les opérations de fichiers ou une partie du traitement réseau. Cette position offre une observation plus proche de l'état du système, mais elle n'accorde ni une connaissance automatique de l'intention, ni un droit universel de bloquer chaque opération.
Les deux domaines communiquent notamment par des **appels système**, qui sont les passages contrôlés permettant à un programme de demander un service au noyau. Les requêtes d'entrée/sortie (input/output, I/O) représentent les échanges avec les fichiers, périphériques ou flux réseau. Des objets partagés sous contrôle du noyau et des files d'événements complètent ces échanges. Les deux domaines ne constituent donc pas deux copies complètes de la même réalité : chaque couche expose un contexte et des garanties différents.
### À quoi sert chaque composant
Un **callback noyau** est une fonction enregistrée par un driver que Windows appelle pendant le traitement d'une opération dans le noyau, par exemple la création d'un processus. Un **filtre** est un composant qui observe, autorise, bloque ou modifie une catégorie d'opérations. Un **minifilter** est un filtre spécialisé dans les fichiers ; il s'enregistre auprès du **Filter Manager**, le composant Windows qui organise ces filtres et leur transmet les opérations demandées.
Une **altitude** est un identifiant numérique écrit sous forme de texte qui positionne certains filtres ou callbacks dans leur chaîne de traitement. Une **pré-opération** intervient avant que la requête atteigne le système de fichiers ; une **post-opération** observe son résultat pendant le retour. Pour un minifilter, Windows appelle les pré-opérations des altitudes les plus élevées vers les plus basses, puis les post-opérations dans l'ordre inverse.
Une décision **synchrone** est prise avant que l'opération surveillée ne se termine, ce qui permet parfois de la bloquer immédiatement. Une action **asynchrone** intervient plus tard, après mise en file ou corrélation, par exemple lorsqu'un EDR termine un processus déjà démarré.
| Composant | Ce qu'il représente | Rôle technique | Limite à garder en tête |
|---|---|---|---|
| Application observée | Le processus dans lequel s'exécute le comportement : navigateur, interpréteur de scripts, outil d'administration ou binaire natif | Produit les appels, chargements d'images, accès mémoire, fichiers et connexions qui deviendront éventuellement des signaux | Une application ne décrit pas elle-même l'intention de l'opérateur |
| Capteur user-mode | Un module chargé ou injecté dans certains processus, ou un composant qui consomme leurs interfaces | Instrumente des chemins d'API, collecte du contexte d'appel et peut inspecter du contenu ou de la mémoire | Un appel qui ne traverse pas le chemin instrumenté peut échapper à ce capteur précis |
| Service EDR local | Le processus durable qui coordonne l'agent sur l'endpoint | Reçoit les événements, normalise les champs, enrichit les identités, applique une politique locale, maintient des files et dialogue avec le backend | Une notification reçue par un driver n'est pas nécessairement conservée, enrichie ou transmise |
| Driver EDR | Un module privilégié chargé dans le noyau Windows | Enregistre des callbacks, des filtres de fichiers ou des composants réseau et peut appliquer certaines décisions synchrones documentées | Un driver n'observe que les mécanismes auxquels il s'est enregistré et les opérations que ces mécanismes exposent |
| Event Tracing for Windows (ETW) | L'infrastructure de télémétrie intégrée à Windows | Le noyau et les applications y publient des événements structurés qu'un EDR peut collecter pour reconstituer une chronologie sans modifier le code observé | Une source enregistrée n'est pas forcément activée ; un canal de collecte actif ne garantit pas la conservation de chaque événement |
| Antimalware Scan Interface (AMSI) | Une interface que certaines applications, notamment les moteurs de scripts, utilisent pour présenter du contenu à un antivirus | Permet d'analyser un script ou un document après son déchiffrement ou sa reconstruction, au moment choisi par l'application | AMSI dépend de l'intégration de l'application et n'observe pas universellement tous les processus |
| Minifilter de fichiers | Un driver spécialisé dans la surveillance des opérations sur les fichiers | S'enregistre auprès du Filter Manager, le composant Windows qui organise ces filtres, puis reçoit des callbacks avant ou après une ouverture, lecture, écriture, modification ou suppression | Il ne reçoit que les opérations déclarées et sa présence ne garantit pas qu'un événement sera conservé par l'EDR |
| Windows Filtering Platform (WFP) | L'infrastructure de filtrage intégrée au traitement réseau Windows | Évalue le trafic à plusieurs points de contrôle et permet à un EDR de l'autoriser, le bloquer ou l'enrichir avec l'identité de l'application | Les informations disponibles et la capacité de blocage dépendent du point de contrôle utilisé |
| Backend d'analyse | Un moteur local ou distant qui reçoit les événements normalisés | Corrèle plusieurs capteurs, conserve l'état, enrichit la réputation et produit détections ou réponses | Le transport, la latence, la rétention et la politique peuvent modifier le résultat visible par l'analyste |
ETW, AMSI, les callbacks noyau, les minifilters et WFP ne sont donc pas des synonymes d'« EDR ». Ce sont des sources ou des points de contrôle que le produit peut combiner. Le service local et le backend transforment ensuite ces observations en entités, relations, alertes et actions.
### Parcours concret d'un événement
Prenons le lancement d'un interpréteur de scripts qui charge une bibliothèque, ouvre un fichier puis initie une connexion. Windows peut notifier la création du processus au driver, publier des événements ETW, signaler le mapping de l'image et présenter les opérations de fichiers au minifilter. Si l'interpréteur intègre AMSI, le contenu du script peut aussi être soumis à l'interface. La connexion atteint ensuite une ou plusieurs couches WFP.
Ces notifications n'arrivent pas nécessairement dans le même format, avec le même identifiant temporel ni dans l'ordre où le backend les affichera. Le service local doit les associer à une identité de processus, copier les champs encore valides, résoudre ce qui peut l'être sans bloquer le système, puis décider quoi conserver ou transmettre. Le backend peut enfin relier le contenu du script, l'image chargée, le fichier touché et la destination réseau à une même entité.
Le driver kernel constitue ainsi un capteur parmi plusieurs, et non le propriétaire universel de toute la télémétrie endpoint. La livraison d'un callback ne démontre pas non plus qu'un événement est conservé ou transmis. La pression sur les files, la configuration des sources, l'échantillonnage, les exclusions, la politique locale et l'**ingestion backend**, l'entrée des événements dans la plateforme d'analyse, peuvent chacun modifier l'ensemble de preuves final.
L'endpoint se représente plus justement comme un graphe ordonné dans le temps. Processus, threads, fichiers, clés de registre, handles, images, **sockets**, les extrémités logiques d'une communication réseau, et identités sont des nœuds ; les opérations observées sont des arêtes. Chaque capteur n'apporte qu'une partie de ce graphe. La disparition d'une arête peut réduire la confiance, sans effacer les autres nœuds, leur état antérieur ni les arêtes rapportées par des capteurs indépendants.
## Télémétrie des callbacks kernel
### Création de processus
`PsSetCreateProcessNotifyRoutineEx` est une fonction d'enregistrement du gestionnaire de processus Windows, pas le chemin parcouru par chaque création. Elle associe un callback `PCREATE_PROCESS_NOTIFY_ROUTINE_EX` que Windows appellera ensuite. Lors d'une création, ce callback reçoit un pointeur `PEPROCESS`, qui désigne l'objet noyau représentant le processus, ainsi qu'un identifiant de processus et une structure `PS_CREATE_NOTIFY_INFO` contenant les informations documentées disponibles à cet instant.
Dans la suite, l'identifiant de processus correspond au Process Identifier (PID) et l'identifiant de thread au Thread Identifier (TID). Ces identifiants sont pratiques pour relier des événements, mais leur valeur peut être réutilisée après la fin de l'objet.
L'appel d'enregistrement et le chemin ultérieur de livraison de l'événement sont distincts. Les symboles privés représentant par exemple un tableau interne de callbacks peuvent être utiles au débogage d'un build donné, mais ne doivent pas être présentés comme des interfaces architecturales stables.
Le callback Ex s'exécute à `PASSIVE_LEVEL` dans le contexte du thread qui crée le processus. L'Interrupt Request Level (IRQL) est le niveau de priorité d'exécution du noyau ; plus il est élevé, plus les opérations autorisées sont limitées. `PASSIVE_LEVEL` est son niveau ordinaire et le moins contraignant. Le callback n'est pas purement observationnel : l'affectation d'une erreur à `CreationStatus` peut empêcher la création. L'utilisation de cette capacité par un EDR dépend du produit et de sa politique. `EPROCESS` est la structure interne par laquelle le noyau représente un processus ; un pointeur `PEPROCESS` y fait référence, mais ne constitue pas une copie sérialisée de tous ses champs. Aucun champ ne doit être présenté comme collecté si le capteur ne le lit pas et ne l'enregistre pas explicitement.
**Intérêt pour la détection.** Les relations parent-enfant, l'identité du créateur, la provenance de l'image et la sémantique de la ligne de commande peuvent alimenter les analyses de chaînes de processus. Un **token** est l'objet Windows qui porte l'identité et les privilèges de sécurité d'un processus ou d'un thread ; un **broker** est un processus intermédiaire chargé d'effectuer une opération pour un autre. Aucun de ces éléments n'est concluant isolément. Le parentage modifié, les créations via broker, les images renommées et les lignes de commande incomplètes imposent une corrélation avec les tokens, handles, images et signaux d'exécution.
L'extrait WDK suivant reste volontairement limité au contrat documenté du callback. Il distingue une notification de fin (`CreateInfo == NULL`) d'une notification de création et traite les chaînes optionnelles comme telles. `DbgPrintEx` écrit un message dans la sortie du débogueur ; il convient à une sonde dans un lab contrôlé, pas au transport de télémétrie d'un produit.
```c title="process-notify.c" {8,12-17,21,25}
#include
static VOID ProcessNotify(
PEPROCESS Process,
HANDLE ProcessId,
PPS_CREATE_NOTIFY_INFO CreateInfo)
{
UNREFERENCED_PARAMETER(Process);
// A NULL CreateInfo denotes process exit.
if (CreateInfo == NULL) {
return;
}
// ImageFileName is documented as optional.
if (CreateInfo->ImageFileName != NULL) {
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL,
"create pid=%p image=%wZ\n", ProcessId, CreateInfo->ImageFileName);
}
}
NTSTATUS StartProcessProbe(VOID)
{
return PsSetCreateProcessNotifyRoutineEx(ProcessNotify, FALSE);
}
VOID StopProcessProbe(VOID)
{
(VOID)PsSetCreateProcessNotifyRoutineEx(ProcessNotify, TRUE);
}
```
### Création et fin de thread
`PsSetCreateThreadNotifyRoutine` enregistre un callback dont la signature classique ne contient que `ProcessId`, `ThreadId` et un booléen `Create`. `ETHREAD` est la structure interne qui représente un thread dans le noyau, mais la signature classique du callback ne fournit aucun argument de ce type. Lors de la création, la routine s'exécute dans le contexte du thread ayant créé le nouveau thread, à un IRQL inférieur ou égal à `APC_LEVEL`. Une Asynchronous Procedure Call (APC) est une fonction placée en attente pour être exécutée dans le contexte d'un thread ; `APC_LEVEL` impose donc davantage de restrictions que `PASSIVE_LEVEL`.
L'événement identifie le processus cible et le nouveau thread, mais n'établit pas à lui seul une **injection de thread distant**, qui consiste à provoquer l'exécution d'un thread dans un autre processus pour lui faire exécuter du code choisi. Une conclusion robuste exige d'autres preuves : contexte créateur, accès préalable à un handle de processus, opérations de mémoire virtuelle, provenance de l'adresse de départ ou **call stack**, la liste des fonctions imbriquées ayant conduit à l'opération. Les variantes étendues modifient le contrat d'exécution disponible ; l'API d'enregistrement exacte doit donc être relevée pendant les tests.
### Mapping d'images exécutables
`PsSetLoadImageNotifyRoutine` enregistre une routine `PLOAD_IMAGE_NOTIFY_ROUTINE`. Le **mapping** associe les pages d'un fichier exécutable à l'espace d'adressage virtuel d'un processus ; il prépare leur accès en mémoire sans signifier que leur code a déjà été exécuté. Windows invoque la routine après ce mapping et avant le **point d'entrée**, la première adresse à laquelle le chargeur doit transférer l'exécution. Le callback reçoit un nom complet optionnel, l'identifiant du processus cible et des données `IMAGE_INFO` telles que l'adresse de base et la taille.
La routine retourne `VOID`, donc aucune valeur, et ne peut pas renvoyer directement une décision d'autorisation ou de blocage. Une **signature numérique** relie un fichier à un éditeur et permet de vérifier qu'il n'a pas été modifié depuis sa signature. Un **hash** est une empreinte calculée à partir du contenu ; la **prévalence** indique à quelle fréquence ce fichier a été observé dans le parc. Ces informations, comme les catalogues de signatures et la réputation, ne sont pas des champs intrinsèques du callback. Un capteur peut les ajouter par d'autres mécanismes.
### Opérations sur le registre
Le **registre** est la base de configuration hiérarchique de Windows. Son sous-système noyau, le **Configuration Manager**, permet à un driver de filtrage de s'enregistrer via `CmRegisterCallbackEx`, puis invoque son callback pour les opérations identifiées par `REG_NOTIFY_CLASS`. Les API de registre user-mode et les routines kernel `Zw*`, qui sont des points d'entrée natifs appelables depuis un driver, peuvent toutes deux atteindre ce chemin.
La plupart des classes d'opérations exposent des notifications pre et post accompagnées de structures propres à l'opération. Un pre-callback peut inspecter, bloquer ou, dans les cas supportés, modifier une opération ; un post-callback observe le statut et la sortie obtenus. Les champs disponibles dépendent de la classe de notification. Affirmer que chaque événement contient un chemin complet, un PID, un TID, les données de la valeur et les permissions est donc excessif. La résolution des noms et l'attribution de l'appelant peuvent demander un traitement supplémentaire au capteur.
**Intérêt pour la détection.** Les clés de persistance, configurations de fournisseurs de sécurité, définitions de services et modifications de politiques prennent leur sens lorsqu'elles sont corrélées à l'identité initiatrice, à la lignée de processus, à la confiance de l'image et à la séquence temporelle. L'accès au registre n'identifie pas à lui seul l'intention.
### Opérations sur les objets processus et thread
Dans ce mécanisme, chaque handle porte un masque de droits sur l'objet Windows visé. `ObRegisterCallbacks` enregistre des routines pre-operation et post-operation pour les opérations supportées sur les handles de processus, de threads et de bureaux. `OB_OPERATION_HANDLE_CREATE` et `OB_OPERATION_HANDLE_DUPLICATE` distinguent la création et la duplication de handles.
Un `ObjectPreCallback` doit retourner `OB_PREOP_SUCCESS` ; il ne renvoie pas un statut arbitraire de refus. `DesiredAccess` est un masque de bits dans lequel chaque bit représente un droit demandé, par exemple écrire dans la mémoire ou créer un thread. Pour les droits modifiables, le callback peut retirer des bits de ce masque, mais ne peut pas ajouter de droits absents de la requête initiale. Un post-callback peut observer le statut final et l'accès accordé, sans modifier rétroactivement l'opération terminée.
Ce mécanisme permet de protéger des processus sensibles en limitant des droits liés à l'accès mémoire, à la création de threads, à la modification de contexte ou à la duplication de handles. Les handles kernel et les opérations issues de composants de confiance ou protégés doivent être interprétés avec prudence. Un handle bloqué ou réduit ne démontre pas une intention de vol d'identifiants sans le comportement environnant.
Le cœur de politique ci-dessous montre le modèle d'application supporté. L'enregistrement, le choix de l'altitude, la durée de vie de la cible et la synchronisation de la politique sont omis, mais l'opération sur le masque utilise les structures pre-operation documentées. Le prédicat de cible doit rester étroit ; appliquer ce masque à tous les processus casserait des logiciels légitimes.
```c title="object-pre-callback.c" {7-9,12-18,20}
static OB_PREOP_CALLBACK_STATUS ProcessHandlePreOperation(
PVOID RegistrationContext,
POB_PRE_OPERATION_INFORMATION Info)
{
UNREFERENCED_PARAMETER(RegistrationContext);
if (Info->ObjectType != *PsProcessType ||
!IsProtectedTarget((PEPROCESS)Info->Object)) {
return OB_PREOP_SUCCESS;
}
ACCESS_MASK *desired = NULL;
if (Info->Operation == OB_OPERATION_HANDLE_CREATE) {
desired = &Info->Parameters->CreateHandleInformation.DesiredAccess;
} else if (Info->Operation == OB_OPERATION_HANDLE_DUPLICATE) {
desired = &Info->Parameters->DuplicateHandleInformation.DesiredAccess;
}
if (desired != NULL) {
*desired &= ~(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE);
}
return OB_PREOP_SUCCESS;
}
```
### Minifilters du système de fichiers
Un **minifilter** est un driver spécialisé dans la surveillance des opérations sur les fichiers. Il s'enregistre auprès du **Filter Manager** (`FltMgr.sys`), le composant Windows qui organise ces filtres, puis reçoit des callbacks avant ou après les opérations qu'il a déclarées. Un **volume** est la cible logique portant un système de fichiers, par exemple une partition montée ; l'attachement d'un minifilter à un volume constitue une **instance**.
Dans le modèle de drivers Windows, une grande partie de ces opérations est transportée par des paquets de requête d'entrée/sortie (I/O Request Packet, IRP), des structures qui décrivent au noyau l'action demandée et son état. L'altitude attribuée positionne l'instance dans la pile ; le nom d'un produit ne définit aucun ordre fixe entre EDR et antivirus.
Pour une opération donnée, les pre-operation callbacks s'exécutent de l'altitude la plus haute vers le système de fichiers. La complétion remonte ensuite dans les post-operation callbacks de l'altitude la plus basse vers la plus haute. Un pre-callback peut laisser passer la requête, demander un post-callback, la mettre en attente, la synchroniser ou la terminer avec un statut final. La présence et le contexte d'exécution du post-callback dépendent du résultat pre-operation et du type d'opération.
**Intérêt pour la détection.** Les opérations de création, écriture, renommage, disposition, c'est-à-dire la demande de suppression d'un fichier, synchronisation de section et modification de métadonnées peuvent alimenter les détections de ransomware, de **staging**, la préparation ou le regroupement de données avant leur transfert, d'altération et de collecte. L'**entropie** mesure ici la dispersion des valeurs d'octets et peut signaler un contenu fortement transformé ou chiffré, sans constituer une preuve à elle seule. Le chemin, le contenu, l'entropie, le contexte du volume et l'attribution au processus sont des enrichissements produit, non un schéma universel d'événement minifilter.
Un minifilter déclare les opérations qu'il souhaite recevoir. Cette table statique ne crée aucun rapport d'ordre fixe avec le filtre d'un autre fournisseur ; FltMgr l'associe à l'altitude de l'instance au runtime.
```c title="minifilter-operations.c" {2-4,6}
CONST FLT_OPERATION_REGISTRATION Operations[] = {
{ IRP_MJ_CREATE, 0, PreCreate, PostCreate },
{ IRP_MJ_WRITE, 0, PreWrite, PostWrite },
{ IRP_MJ_SET_INFORMATION, 0, PreSetInformation, PostSetInformation },
{ IRP_MJ_OPERATION_END }
};
```
## Event Tracing for Windows
Event Tracing for Windows (ETW) est l'infrastructure de télémétrie intégrée à Windows : le noyau et les applications y publient des événements structurés décrivant leur activité. Un EDR peut les collecter et les corréler pour reconstituer une chronologie, par exemple la création d'un processus ou le chargement d'une Dynamic Link Library (DLL), une bibliothèque de code réutilisable chargée par un processus, sans devoir modifier directement le code observé.
Un **provider** est le composant qui produit les événements. Un **contrôleur** démarre une **session**, c'est-à-dire le canal temporaire et ses buffers mémoire, puis choisit les providers à activer. Un **consumer** lit les événements de cette session en temps réel ou depuis un fichier Event Trace Log (ETL). Un service EDR peut être à la fois contrôleur et consumer, mais le contrôleur ne relaie pas chaque événement entre le provider et le consumer.
Les enregistrements peuvent contenir un identifiant de provider, un identifiant et une version d'événement, un **niveau** représentant sa gravité, un **keyword** utilisé comme catégorie d'activation, un horodatage, des PID et TID, des identifiants d'activité et un **payload**, c'est-à-dire les données propres à l'événement. Son schéma provient d'un manifeste, des métadonnées auto-descriptives TraceLogging, du Managed Object Format (MOF) ou d'un fichier Trace Message Format (TMF), qui indiquent au consumer comment décoder les champs. ETW ne garantit ni l'activation d'un provider, ni la conservation de chaque événement, ni sa pertinence en matière de sécurité.
Les événements PowerShell, .NET, kernel et Microsoft-Windows-Threat-Intelligence appartiennent à des familles de providers distinctes, avec des conditions d'activation et d'accès différentes. **.NET** est la plateforme Microsoft qui exécute du code managé, c'est-à-dire du code dont l'exécution et la mémoire sont supervisées par un environnement dédié. AMSI est une interface séparée d'inspection de contenu. Ses signaux peuvent être corrélés à ETW, mais AMSI ne constitue pas une catégorie de provider ETW.
## Télémétrie réseau avec WFP
Windows Filtering Platform (WFP) est l'infrastructure de filtrage intégrée à la pile réseau Windows. La **pile réseau** est la succession de composants qui transforme les données d'une application en paquets, puis effectue le trajet inverse à la réception. WFP expose des **couches**, c'est-à-dire des points de contrôle correspondant à des étapes précises de ce traitement.
À chaque couche, un **filtre WFP** est une règle composée de conditions et d'une action. Le moteur de filtrage évalue ces règles ; il peut autoriser ou bloquer directement le trafic, ou appeler un **callout**, une fonction fournie par un driver pour effectuer un traitement spécialisé. Le Base Filtering Engine (BFE, moteur de filtrage de base) gère la configuration de la plateforme. Les couches Application Layer Enforcement (ALE, application des politiques au niveau applicatif) ajoutent notamment l'identité de l'application ou de l'utilisateur à la décision.
Le BFE coordonne la politique et la configuration persistante en mode utilisateur ; la **classification**, c'est-à-dire la comparaison du trafic avec les filtres applicables, s'exécute en mode noyau aux couches réseau et transport. Un **flux** regroupe les échanges appartenant à une même communication. Aux couches ALE, ses métadonnées peuvent inclure l'application, l'utilisateur, le protocole, ainsi que les adresses et ports locaux ou distants. Leur disponibilité dépend de la couche et du type d'événement.
Un callout EDR ne se place donc pas avant WFP. Il est invoqué parce qu'un filtre correspondant à une couche sélectionne ce callout. La fonction de classification peut inspecter les métadonnées et contribuer à l'action selon l'**arbitrage WFP**, les règles de priorité qui déterminent l'action finale lorsque plusieurs filtres correspondent. Le **payload réseau** est la donnée transportée par les paquets ; le **réassemblage de flux** reconstruit une suite continue à partir de ces paquets. Leur inspection et la sémantique finale de blocage dépendent de la couche, de l'implémentation du callout et des droits associés à l'action.
## Instrumentation des API en mode utilisateur
Certains EDR injectent ou chargent un capteur user-mode et détournent des **exports**, les fonctions qu'un module rend appelables par d'autres composants, dans des bibliothèques telles que `ntdll.dll`. Un **inline hook** modifie les premières instructions d'une fonction, appelées son **prologue**, afin de brancher l'exécution vers le capteur. Un **trampoline** est un petit bloc de code qui rejoue les instructions déplacées puis ramène l'exécution vers la suite de la fonction originale.
Ce pattern n'est pas universel. Les produits peuvent employer d'autres stratégies d'injection, frameworks d'instrumentation, sources d'événements et règles limitant l'instrumentation de processus sensibles. Un **appel système direct** demande un service au noyau sans traverser l'export user-mode instrumenté. Il peut donc contourner ce detour précis, mais pas l'appel système lui-même, les callbacks kernel, providers ETW, couches WFP, minifilters, contrôles de handles, scanners mémoire ou corrélations interprocessus indépendants.
Les identifiants et **stubs** d'appels système dépendent de l'architecture et du build. Un stub est la courte séquence de code machine qui prépare l'identifiant de l'opération puis effectue la transition vers le noyau. La fixation d'un identifiant unique comme technique Windows générale est incorrecte. Microsoft Visual C++ ne supporte pas non plus l'assembleur inline pour l'architecture x86 64 bits (x64) sous la forme souvent présentée dans les exemples simplifiés. Un outil de recherche doit résoudre et valider le build cible au lieu de supposer un stub fixe.
## Sémantique des capteurs et qualité des données
### Identité et durée de vie des objets
Les identifiants Windows constituent des clés de corrélation pratiques, mais pas des identités permanentes. Les PID et TID peuvent être réutilisés après la fin d'un objet. Une **époque** désigne ici une période d'exécution unique délimitée par le redémarrage de Windows ou du capteur. Un modèle robuste associe donc l'identifiant à l'heure de création et à cette époque, puis idéalement à un identifiant d'entité généré par le produit. La corrélation tardive d'un événement réseau ou fichier avec le propriétaire actuel d'un PID réutilisé peut autrement créer une fausse lignée.
Les callbacks kernel exposent également les objets à des étapes différentes de leur cycle de vie. Un callback de création de processus s'exécute avant que le thread initial commence son exécution, tandis qu'un callback d'image arrive après la création du mapping mais avant l'exécution de son point d'entrée. Un post-callback objet observe une opération de handle terminée. Ces événements décrivent des transitions d'état différentes et ne doivent pas être réduits à un horodatage générique tel que « démarrage du processus ».
Les pointeurs d'objets ne sont valides que selon le contrat et les règles de durée de vie du callback qui les reçoit. Conserver un pointeur brut pour un traitement asynchrone, donc exécuté plus tard, sans prendre une référence appropriée est dangereux. Les capteurs de production copient généralement les champs stables dans un enregistrement borné et délèguent l'enrichissement coûteux à un **worker**, une tâche ou un thread de fond, ou au service user-mode.
### Temps d'événement et ordre causal
L'ordre d'invocation des callbacks n'est pas l'ordre d'arrivée au backend. Un **buffer** est une zone mémoire temporaire qui absorbe un écart de vitesse entre le producteur et le lecteur ; le **batching** regroupe plusieurs événements pour les transporter ensemble. Les événements peuvent traverser des buffers par unité centrale de traitement (Central Processing Unit, CPU), files kernel-vers-user, stockage local, compression, batching, transport et ingestion cloud avant de devenir interrogeables. Deux enregistrements produits dans un ordre kernel connu peuvent être observés dans l'ordre inverse après des chemins de buffering indépendants.
Plusieurs horloges peuvent coexister : temps système, temps d'interruption, compteur de performance haute résolution, timestamps ETW, temps de réception par le service local et temps d'ingestion backend. Un **domaine d'horloge** est la source de temps et l'origine utilisées pour produire un timestamp. Un modèle défendable préserve ce domaine original et documente l'incertitude de conversion. Le temps backend ne doit pas remplacer le temps de génération pour reconstruire des séquences subsecondes de processus, threads, handles ou flux réseau.
### Champs optionnels, résolution des noms et races
Le caractère optionnel documenté a des conséquences analytiques. `ImageFileName` et `CommandLine` dans `PS_CREATE_NOTIFY_INFO` peuvent être absents. `FullImageName` dans un callback de chargement peut être nul. Les callbacks registre reçoivent des structures propres à chaque opération plutôt qu'un chemin universel entièrement résolu. Les métadonnées réseau diffèrent selon les couches WFP. L'absence d'une donnée ne démontre donc pas une altération.
Les noms constituent aussi des vues mutables des objets. Une **race** apparaît lorsque l'objet change entre l'événement et sa résolution ultérieure. Un **reparse point** peut rediriger la résolution d'un chemin, tandis qu'un **hard link** donne plusieurs noms au même fichier. Un fichier peut donc être renommé ou résolu différemment après sa création ; les capteurs qui enrichissent de manière asynchrone doivent distinguer les valeurs capturées au moment de l'événement de celles résolues plus tard.
### Débit, backpressure et perte d'événements
La **backpressure** apparaît lorsqu'un producteur génère des événements plus vite que le composant suivant ne peut les traiter. Chaque chemin de collecte possède donc un budget de performance : les callbacks kernel s'exécutent dans des contextes contraints, les minifilters se trouvent sur des chemins I/O sensibles à la latence, les callouts WFP peuvent affecter le débit réseau et les sessions ETW utilisent des buffers finis. Un capteur peut échantillonner, agréger, supprimer des répétitions ou abandonner des événements de faible priorité. En mode **fail-open**, il laisse l'opération continuer lors d'une panne ou d'une saturation afin de préserver la disponibilité, au prix d'une visibilité ou d'un contrôle réduit.
Les contrôleurs ETW peuvent exposer des statistiques de buffers et d'événements perdus. Les files produit peuvent publier des compteurs de santé, des logs de diagnostic ou des **heartbeats**, de petits messages périodiques confirmant que le capteur fonctionne encore. Un résultat négatif reste ininterprétable sans les indicateurs de santé et de perte. « Aucun événement trouvé » peut signifier une absence d'instrumentation, un filtrage, une perte, un retard d'ingestion, l'expiration de la rétention, une erreur de requête ou un contournement effectif.
## Frontières entre observation et application
L'interface native détermine ce qu'un callback peut effectuer de façon synchrone. Les capacités de réponse du produit peuvent ajouter des actions ultérieures, mais elles ne doivent pas être attribuées à l'API de collecte elle-même.
| Mécanisme | Observation native | Influence synchrone native | Frontière importante |
|---|---|---|---|
| Process notify Ex | Création, fin et métadonnées documentées | `CreationStatus` peut faire échouer la création | Le produit peut employer le callback uniquement pour la télémétrie |
| Thread notify | PID cible, TID et état création/suppression | Aucun retour allow/deny documenté | L'injection exige une corrélation au-delà du callback |
| Image-load notify | Métadonnées du mapping d'image | Aucun retour allow/deny ; callback `VOID` | Le mapping existe déjà lors de la notification |
| Registry callback | Données pre/post typées | Le pre-callback peut bloquer ou modifier les opérations supportées | Les champs et modifications dépendent de `REG_NOTIFY_CLASS` |
| Object callback | Création ou duplication d'un handle process/thread | Les bits d'accès supportés peuvent être retirés | Le pre-callback retourne success ; ce n'est pas un hook de refus générique |
| Minifilter pre-op | Opérations de système de fichiers enregistrées | Laisser passer, pendre, modifier, synchroniser ou terminer | L'ordre dépend de l'altitude et des opérations enregistrées |
| Consumer ETW | Événements émis vers une session activée | Aucune via le rôle de consumer | Activation du provider et rétention sont des décisions séparées |
| Callout WFP | Métadonnées de flux, stream, packet ou ALE propres à la couche | La classification peut contribuer à permit/block | Droits, arbitrage et données disponibles varient selon la couche |
| Detour user-mode | Arguments, contexte appelant, retour et données produit | Le hook peut altérer ou refuser l'appel user-mode | Seuls les appels traversant le chemin instrumenté sont observés |
La réponse asynchrone doit être modélisée séparément. Un capteur peut observer un mapping d'image puis terminer le processus quelques millisecondes plus tard, ou enregistrer un flux réseau et isoler l'hôte après corrélation backend. Ce comportement est préventif au niveau produit, sans constituer une prévention synchrone par la source initiale de l'événement.
## Confiance plateforme, exécution protégée et autoprotection
Les API d'enregistrement kernel imposent leurs propres conditions de confiance. Les callbacks processus Ex peuvent par exemple échouer si l'image contenant le callback ne possède pas la caractéristique d'intégrité exigée ; l'enregistrement d'object callbacks peut être refusé si les routines ne résident pas dans une image kernel signée. Ces contrôles augmentent le coût d'un enregistrement arbitraire sans garantir la sécurité de chaque driver signé.
Protected Process Light (PPL) est un niveau de protection Windows qui réserve certaines opérations sur un processus aux composants possédant un niveau de signature suffisant. Il peut limiter l'inspection user-mode ou l'acquisition de handles par un composant EDR dont le niveau de confiance est insuffisant. Certains produits de sécurité emploient des services protégés et des processus antimalware-light ; leur configuration exacte reste propre au fournisseur et au déploiement.
Un **hyperviseur** est la couche logicielle qui crée et isole des environnements d'exécution sous le système principal. Virtualization-Based Security (VBS, sécurité fondée sur la virtualisation) utilise cette isolation pour protéger certaines décisions et données. **Code Integrity** est le mécanisme Windows qui vérifie qu'un binaire respecte les exigences de signature et de politique avant son exécution. Hypervisor-Protected Code Integrity (HVCI, intégrité du code protégée par l'hyperviseur) s'appuie sur l'environnement isolé pour renforcer cette vérification du code autorisé à s'exécuter dans le noyau. La blocklist Microsoft refuse des drivers connus comme vulnérables, tandis qu'App Control applique une politique définissant les exécutables et drivers autorisés. Ces mécanismes réduisent l'exposition aux drivers connus ou non fiables, mais ne transforment pas les données kernel non documentées en frontière de sécurité supportée.
Kernel Patch Protection, souvent appelé PatchGuard, vérifie périodiquement l'intégrité de certains codes et structures critiques du noyau sur les systèmes 64 bits supportés. Il ne doit pas être décrit comme un détecteur complet, immédiat et publiquement spécifié de toute manipulation de callbacks ou d'ETW. Sa couverture et sa temporisation sont des détails d'implémentation. Un crash après une modification non supportée démontre une instabilité plateforme, pas un résultat fiable de détection EDR.
L'autoprotection du produit ajoute une couche. Une liste de contrôle d'accès (Access Control List, ACL) indique quelles identités peuvent agir sur un service ou un device de driver. Un **watchdog** surveille qu'un composant reste actif et tente de le relancer ou de signaler sa défaillance. Services protégés, contrôles de santé des callbacks, intégrité des modules, signature de configuration et état backend peuvent aussi contribuer. L'**anti-tamper**, qui vise à empêcher ou détecter la modification du produit, reste distinct de la détection comportementale.
## De la télémétrie à la détection
Un **pipeline EDR** est la succession d'étapes qui transforme des observations brutes de l'endpoint en données exploitables, puis éventuellement en détection ou en action. La collecte n'en constitue que la première étape ; la qualité de détection dépend aussi de la normalisation, de l'enrichissement, de l'état et de la corrélation.
| Étape | Fonction typique | Principaux modes de défaillance |
|---|---|---|
| Collecte | Recevoir callbacks, événements, I/O, flux et signaux user-mode | Capteur désactivé, callback absent, provider non activé, perte d'événements |
| Normalisation | Convertir les enregistrements produit dans un schéma interne stable | Champs manquants, identité ambiguë, dérive d'horloge ou de schéma |
| Enrichissement | Résoudre signature, hash, réputation, token, chemin, lignée et contexte asset | Dépendance réseau, cache périmé, races de chemin, objets inaccessibles |
| Corrélation | Relier les événements entre processus, threads, sessions et hôtes | Réutilisation d'identifiants, fenêtres incomplètes, échantillonnage, délai backend |
| Décision | Scorer, alerter, bloquer, isoler ou collecter des preuves | Différences de politique, seuil de modèle, suppression, latence de réponse |
La présence d'un callback ne doit pas être assimilée à une visibilité complète. Inversement, le contournement d'un callback ou d'un detour user-mode ne doit pas être assimilé à une perte de détection. L'unité d'analyse pertinente est le graphe complet du comportement et l'ensemble des capteurs indépendants capables de le décrire.
## Limites de l'évasion
Une technique d'évasion doit être décrite par le chemin de visibilité précis qu'elle affecte. Les expressions « désactiver l'EDR » ou « devenir invisible » sont trop larges sans identification du produit, de sa version, de sa politique, de l'état des capteurs et du résultat mesuré.
Un **bypass**, c'est-à-dire le contournement effectif d'un contrôle précis, reste limité au chemin de collecte ou d'application testé. La perte d'un signal n'établit pas la perte du graphe comportemental, de la prévention ou de la détection backend.
### Unhooking user-mode et appels système directs
Ces techniques peuvent supprimer ou contourner certains detours user-mode. Les preuves résiduelles peuvent inclure les callbacks de processus et de threads, opérations de handles, mappings d'images, ETW, WFP, les minifilters, l'état de la mémoire distante et les corrélations backend. La restauration des hooks peut elle-même produire des anomalies d'intégrité ou de protection mémoire.
### Altération d'ETW
`EtwEventWrite` est l'une des fonctions qu'un provider peut appeler pour publier un événement ETW. Modifier sa copie dans un processus n'affecte que les appels qui traversent cette copie et ce chemin de code ; cela ne désactive ni les providers kernel, ni les autres processus, ni les autres points d'entrée ETW, ni les capteurs non ETW. La modification de pages exécutables peut également constituer un signal d'intégrité observable. L'état ETW kernel est spécifique à l'implémentation et ne doit pas être représenté par un offset ou un layout stable.
### Manipulation des callbacks kernel
La suppression d'un callback par des structures internes non documentées exige une **primitive d'écriture kernel**, c'est-à-dire une capacité permettant de modifier une adresse choisie dans la mémoire du noyau, ainsi qu'une découverte propre au build. Un code de contrôle d'entrée/sortie (Input/Output Control, IOCTL) est une commande structurée envoyée par un processus à un driver ; il n'existe pas d'IOCTL Windows générique « remove callback ». Un driver vulnérable expose son propre protocole de device et ses propres primitives. L'exploitation doit donc implémenter sa sémantique de lecture/écriture et résoudre l'état kernel cible sur le build exact. Les mécanismes d'intégrité, l'autoprotection du produit, le réenregistrement des callbacks, les crashs et les autres capteurs modifient le résultat.
### Drivers signés vulnérables
Une signature valide établit une relation de confiance pour le chargement ; elle ne garantit pas l'absence de vulnérabilité exploitable. Les contrôles modernes comprennent HVCI, la blocklist Microsoft des drivers vulnérables, les politiques App Control et une règle Attack Surface Reduction (ASR, réduction de la surface d'attaque) contre l'abus de drivers signés vulnérables. Leur couverture n'est pas absolue et l'état de la blocklist doit être vérifié sur l'endpoint testé.
## Internals propres au build et reverse engineering
Le débogage kernel et le reverse engineering deviennent nécessaires lorsque la question de recherche porte sur l'implémentation réelle plutôt que sur le contrat documenté. Ils exigent un format de preuve plus strict.
ETW Threat Intelligence (ETW-TI) est un provider Windows orienté sécurité qui publie certaines opérations sensibles ; il reste une source ETW parmi d'autres, soumise à ses propres conditions d'accès et d'activation. Le **désassemblage** traduit le code machine d'un binaire en instructions processeur ; le **pseudocode** en propose une représentation de plus haut niveau, plus lisible mais reconstruite par l'outil. Les routines de notification, enregistrements de callbacks, nœuds de minifilters et entrées encodées peuvent ainsi être étudiés à l'aide de symboles privés et du désassemblage. Une primitive issue d'un driver vulnérable peut parfois permettre de modifier la mémoire kernel. Ces techniques démontrent seulement que le build examiné peut être inspecté ou altéré ; elles ne rendent pas portables les noms de symboles internes, tailles de tableaux, encodages de pointeurs, layouts de listes ou offsets de champs.
Chaque affirmation portant sur un internal devrait enregistrer :
- les versions, hashes, timestamps et adresses de chargement exacts du kernel et des drivers ;
- la source du **symbol server**, le dépôt qui fournit les informations de débogage, l'identité du fichier Program Database (PDB) associé au binaire et l'état de chargement de ces symboles, qui relient des adresses machine à des noms, fonctions et types ;
- l'emplacement de désassemblage ou de pseudocode établissant l'utilisation de l'objet interne ;
- le layout de structure dérivé des symboles ou du code, et non copié depuis un autre build ;
- les hypothèses de synchronisation et de durée de vie requises avant toute lecture ou modification ;
- les états avant et après, y compris réenregistrement du callback, santé du capteur, stabilité système et télémétrie résiduelle.
La propriété d'une routine par un driver de sécurité doit être établie en résolvant son adresse vers le module chargé, puis en examinant l'appel d'enregistrement ou l'implémentation de la routine. Des labels tels que `WdFilter.sys`, `MsSecFlt.sys` ou un driver tiers sont des observations sur un système, pas des membres obligatoires d'une liste de callbacks Windows. L'ordre de chargement, la version produit, les fonctions activées et les composants de sécurité plateforme en modifient la population.
Les expériences de suppression sont particulièrement faciles à surinterpréter. Effacer une entrée, détacher un nœud, désactiver un flag d'activation ou restaurer des octets peut produire un état temporaire tout en laissant intacts des pointeurs en cache, des **références de rundown**, qui empêchent la destruction d'un objet encore utilisé, des files de workers, watchdogs, callbacks alternatifs et preuves backend. Une écriture réussie n'équivaut pas à un contournement propre ou durable du capteur.
Un symbole privé, un layout ou un offset doit être redécouvert et prouvé sur le build cible. Une valeur observée sur une autre version ne constitue pas un fait actuel.
## Erreurs d'analyse fréquentes
1. **Confondre enregistrement et flux d'événements.** Une API de setup appelée lors de l'initialisation du driver n'est pas traversée par chaque événement.
2. **Présenter des symboles privés comme architecture publique.** Les noms et offsets internes exigent un build et une source de preuve explicites.
3. **Inventer des champs d'événement universels.** Arguments du callback, enrichissement produit et schéma backend sont des couches séparées.
4. **Assimiler notification et prévention.** Les callbacks `VOID` ne retournent pas de décision ; la réponse asynchrone du produit doit être décrite séparément.
5. **Assimiler un bypass à la désactivation de l'EDR.** Le hook, provider, callback, callout ou la file affectés doivent être nommés précisément.
6. **Prendre une alerte pour seule vérité terrain.** La télémétrie brute, la prévention, la santé du capteur et l'ingestion backend doivent aussi être examinées.
7. **Omettre les contrôles négatifs.** Un test exige une **baseline**, c'est-à-dire une capture de référence comparable, et une opération bénigne de même forme API.
8. **Ignorer la récupération.** Watchdogs, réenregistrement, redémarrage, actualisation de politique et mises à jour peuvent annuler une modification transitoire.
9. **Supposer un numéro d'appel système fixe.** L'architecture et le build Windows déterminent le stub ; les exemples codés en dur, donc fixés directement dans le code, vieillissent immédiatement.
10. **Assimiler driver signé et comportement fiable.** Signature, état de vulnérabilité, couverture de blocklist et politique runtime sont des propriétés distinctes.
## Matrice de couverture expérimentale
Un plan de test exhaustif doit faire varier indépendamment le comportement et le chemin de collecte. Le tableau décrit les preuves minimales et non une alerte attendue propre à un produit.
| Famille de test | Source primaire testée | Sources résiduelles indépendantes | Preuves de résultat requises |
|---|---|---|---|
| Création de processus | Callback Process Ex | Mapping image, ETW, lignée de handles, audit de service | Statut de création, événement brut, lignée d'entité, action de politique |
| Comportement de thread distant | Thread callback ou hook user-mode | Object callbacks, mémoire, ETW-TI, état de la cible | Identités source/cible, droits, adresse de départ, résultat du thread |
| Introduction d'image | Callback image-load | Minifilter, Code Integrity, scan mémoire, ETW | État du mapping, signature/hash enrichis, résultat d'exécution |
| Persistance registre | Registry callback | Lignée processus, télémétrie services/tâches, activation ultérieure | Statut pre/post, clé et valeur résolues, identité initiatrice |
| Accès à un processus sensible | Object callback | Événements d'audit, lectures mémoire, threads, état de protection | Accès original/réduit, handle accordé, opération suivante |
| Transformation de fichiers | Minifilter | Process/thread, analyse de contenu ou entropie, volume | Résultat pre/post, identité chemin/octets, débit et périmètre |
| Script ou code managé | Chemin ETW/AMSI | Processus, images, fichiers, réseau, mémoire | Activation provider, contenu disponible, comportement aval |
| Connexion réseau | WFP/ALE | Domain Name System (DNS), lignée processus, proxy, Transport Layer Security (TLS), logs distants | Couche, direction, endpoints, identité application, action |
| Contournement d'un hook user | Export instrumenté | Callbacks kernel, ETW, WFP, minifilter, mémoire | Intégrité du hook, chemin réel, graphe d'événements résiduel |
| Chargement ou abus d'un driver | Code Integrity et politique drivers | Callback image, registre service, minifilter, télémétrie kernel | Décision de chargement, politique, hash/version, accès device |
La conclusion la plus solide est rarement binaire. La couverture peut être complète, partielle, retardée, échantillonnée, enrichie seulement dans le backend ou suffisante pour détecter malgré l'absence d'un événement primaire. Chaque dimension doit être enregistrée séparément.
## Méthodologie de recherche
Une expérimentation défendable sur les internals EDR doit enregistrer assez d'état pour permettre la reproduction ou la contestation de la conclusion.
1. **Figer l'environnement.** Relever l'édition, le build et le niveau de servicing Windows, l'état de la virtualisation et de VBS, les versions du produit et du capteur EDR, l'identifiant de politique et la connectivité réseau.
2. **Définir le comportement.** Décrire l'opération de processus, thread, image, registre, objet, fichier, ETW ou réseau générée. Un nom d'alerte ne constitue pas une définition du comportement.
3. **Inventorier les capteurs attendus.** Relever les callbacks documentés, drivers chargés, instances et altitudes des minifilters, sessions ETW et providers activés, filtres et callouts WFP et modules user-mode.
4. **Capturer une référence.** Exécuter un contrôle bénin de même forme API et collecter les enregistrements locaux et backend avant toute condition d'évasion.
5. **Modifier une seule variable.** Désactiver, contourner ou altérer un seul chemin de collecte en conservant le comportement et la politique.
6. **Mesurer la visibilité résiduelle.** Comparer les événements bruts, enregistrements normalisés, alertes, actions de prévention, temps d'arrivée backend et effets de bord endpoint.
7. **Répéter après redémarrage et mise à jour.** Les callbacks, sessions de providers, blocklists et protections peuvent être restaurés ou modifiés par le servicing et les contrôles de santé du capteur.
Les résultats doivent distinguer au minimum quatre situations : l'événement ciblé disparaît ; l'événement reste mais perd des champs ; la télémétrie reste tandis que l'alerte disparaît ; ou la prévention change tandis que la télémétrie demeure. Ces résultats appartiennent à des couches différentes du pipeline et ne doivent pas être regroupés sous une affirmation unique de « bypass réussi ».
L'inventaire en lecture seule suivant fournit un point de départ reproductible sur un hôte Windows du lab. Il n'identifie pas chaque capteur EDR, mais capture trois surfaces fréquemment mal comprises avant le début du test.
```powershell title="Collect-EdrSurface.ps1" {4-6,8-9,11-13}
$EvidenceRoot = Join-Path $env:TEMP ("edr-surface-" + (Get-Date -Format "yyyyMMdd-HHmmss"))
New-Item -ItemType Directory -Path $EvidenceRoot | Out-Null
fltmc filters | Out-File (Join-Path $EvidenceRoot "minifilters.txt")
logman query -ets | Out-File (Join-Path $EvidenceRoot "etw-sessions.txt")
logman query providers | Out-File (Join-Path $EvidenceRoot "etw-providers.txt")
$WfpState = Join-Path $EvidenceRoot "wfp-state.xml"
netsh wfp show state "file=$WfpState"
Get-CimInstance Win32_SystemDriver |
Select-Object Name, State, StartMode, PathName |
Export-Csv (Join-Path $EvidenceRoot "drivers.csv") -NoTypeInformation
```
Cet instantané doit être associé aux versions du système d'exploitation (operating system, OS) et du capteur, à l'état de la politique, aux timestamps et aux preuves backend. `fltmc` confirme les instances et altitudes des minifilters, `logman` distingue les providers enregistrés des sessions actives et `netsh wfp` exporte l'état WFP et Internet Protocol Security (IPsec) courant.
## Un modèle mental durable
Reprenons la séquence d'ouverture. La création du processus établit une identité et une lignée. Les notifications d'image décrivent des mappings exécutables, sans décider si ces mappings sont malveillants. Un callback objet peut observer ou réduire l'accès demandé à un autre processus, tandis qu'une notification de thread ultérieure indique seulement qu'un thread est apparu. Les télémétries fichier et WFP ajoutent des effets extérieurs au processus. ETW peut apporter du contexte d'exécution. La valeur analytique naît de leur relation temporelle, pas d'un événement isolé.
Une affirmation sur la visibilité EDR peut donc être examinée avec quatre questions :
1. **Quelle transition d'état Windows s'est produite ?** Un comportement doit être décrit indépendamment d'une alerte ou d'un nom d'outil.
2. **Quel mécanisme documenté peut l'observer ou l'influencer ?** Enregistrement, livraison, normalisation, détection et réponse sont des étapes distinctes.
3. **Quels champs et quelles garanties d'ordre existent réellement ?** Les données optionnelles, la réutilisation des PID, le transport asynchrone et les pertes d'événements limitent chaque conclusion.
4. **Quelles preuves indépendantes subsistent si ce mécanisme disparaît ?** Les signaux résiduels de processus, handles, images, fichiers, ETW ou réseau déterminent si une évasion retire un événement ou rompt réellement la chaîne analytique.
Les internals EDR se comprennent plus justement comme un système distribué partiellement observable. L'endpoint produit des preuves fragmentées, les composants locaux les transforment, le transport peut les retarder ou les perdre, puis un backend reconstruit le comportement sous le contrôle d'une politique. Ce modèle reste utile d'un produit et d'un build Windows à l'autre, car il sépare la sémantique stable du système d'exploitation de l'implémentation propre au fournisseur.
## Hiérarchie des sources et limites
Le WDK public définit les interfaces supportées, mais pas toutes les structures internes de dispatch utilisées par un build Windows particulier. *Windows Internals* explique les concepts d'implémentation tout en avertissant explicitement que les internals non documentés peuvent évoluer. Les symboles de débogage kernel et le reverse engineering peuvent établir le fonctionnement d'un build donné ; ils n'établissent pas un contrat compatible avec les versions futures. Le comportement d'un fournisseur exige une observation directe, car l'existence d'une fonction OS ne démontre pas la manière dont un produit la configure ou la consomme.
Une expérimentation fondée sur les symboles WinDbg et une primitive de lecture ou d'écriture issue d'un driver vulnérable peut établir le comportement du système examiné. Elle ne prouve pas que les offsets, layouts internes, propriétaires de callbacks ou états de providers sont identiques sur un autre build.
## Références
- Microsoft, [PsSetCreateProcessNotifyRoutineEx](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreateprocessnotifyroutineex) et [PS_CREATE_NOTIFY_INFO](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_ps_create_notify_info).
- Microsoft, [PsSetCreateThreadNotifyRoutine](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreatethreadnotifyroutine) et [PCREATE_THREAD_NOTIFY_ROUTINE](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ddi/ntddk/nc-ntddk-pcreate_thread_notify_routine).
- Microsoft, [PsSetLoadImageNotifyRoutine](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetloadimagenotifyroutine) et [PLOAD_IMAGE_NOTIFY_ROUTINE](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ddi/ntddk/nc-ntddk-pload_image_notify_routine).
- Microsoft, [Enregistrement des notifications du registre](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/kernel/registering-for-notifications) et [REG_NOTIFY_CLASS](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ddi/wdm/ne-wdm-_reg_notify_class).
- Microsoft, [ObRegisterCallbacks](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ddi/wdm/nf-wdm-obregistercallbacks), [OB_OPERATION_REGISTRATION](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ddi/wdm/ns-wdm-_ob_operation_registration) et [OB_PRE_CREATE_HANDLE_INFORMATION](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ddi/wdm/ns-wdm-_ob_pre_create_handle_information).
- Microsoft, [handles d'objets](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/kernel/object-handles) et [priorités matérielles et IRQL](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/kernel/managing-hardware-priorities).
- Microsoft, [Concepts du Filter Manager](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ifs/filter-manager-concepts), [ordre des callbacks pre/post](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ifs/writing-preoperation-and-postoperation-callback-routines) et [groupes de chargement et altitudes](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ifs/load-order-groups-and-altitudes-for-minifilter-drivers).
- Microsoft, [Présentation d'Event Tracing](https://learn.microsoft.com/fr-fr/windows/win32/etw/about-event-tracing).
- Microsoft, [Antimalware Scan Interface](https://learn.microsoft.com/fr-fr/windows/win32/amsi/antimalware-scan-interface-portal).
- Microsoft, [`logman query`](https://learn.microsoft.com/fr-fr/windows-server/administration/windows-commands/logman-query).
- Microsoft, [architecture de Windows Filtering Platform](https://learn.microsoft.com/fr-fr/windows-hardware/drivers/network/windows-filtering-platform-architecture-overview), [composants WFP et Base Filtering Engine](https://learn.microsoft.com/fr-fr/windows/win32/fwp/about-windows-filtering-platform), [Application Layer Enforcement](https://learn.microsoft.com/fr-fr/windows/win32/fwp/application-layer-enforcement--ale-) et [fonctionnement de WFP](https://learn.microsoft.com/fr-fr/windows/win32/fwp/basic-operation).
- Microsoft, [`netsh wfp`](https://learn.microsoft.com/fr-fr/windows-server/administration/windows-commands/netsh-wfp).
- Microsoft, [Detours : Using Detours](https://github.com/microsoft/Detours/wiki/Using-Detours).
- Microsoft, [contrôle des entrées et sorties de périphériques avec IOCTL](https://learn.microsoft.com/fr-fr/windows/win32/devio/device-input-and-output-control-ioctl-) et [protection des services antimalware](https://learn.microsoft.com/fr-fr/windows/win32/services/protecting-anti-malware-services-).
- Microsoft, [règles recommandées de blocage des drivers](https://learn.microsoft.com/fr-fr/windows/security/application-security/application-control/app-control-for-business/design/microsoft-recommended-driver-block-rules).
- Microsoft, [intégrité de la mémoire, VBS et HVCI](https://learn.microsoft.com/fr-fr/windows/security/hardware-security/enable-virtualization-based-protection-of-code-integrity?tabs=intune).
- Yosifovich, Ionescu, Russinovich et Solomon, [*Windows Internals*, septième édition, première partie](https://learn.microsoft.com/fr-fr/sysinternals/resources/windows-internals), Microsoft Press, 2017.
- Russinovich, Solomon et Ionescu, *Windows Internals*, sixième édition, première partie, Microsoft Press, 2012. Consulté uniquement pour l'architecture historique.
- Altered Security, *Evasion Lab Manual*, objectifs d'apprentissage 9 à 11, 2025. Support de cours hors ligne consulté pour sa méthodologie de débogage propre au lab.