Aller au contenu principal
Xsec

Internals EDR : architecture de télémétrie et limites de l'évasion

Publié le 38 min de lecture

Une analyse sourcée des chemins de télémétrie Endpoint Detection and Response (EDR, détection et réponse sur les endpoints) 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.

Cette distinction constitue le fil conducteur de l’article. La question utile n’est pas seulement de savoir si un callback ou un hook existe, mais ce que le 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. Aucune architecture unique ne décrit tous les produits : l’emplacement des capteurs, les schémas d’événements, la mise en mémoire tampon, 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.

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, les interfaces de pilotes de périphériques (Device Driver Interface, DDI), les signatures de callbacks et les règles d’ordonnancement. 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. Ils 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 fournie avec le matériel de recherche 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. La documentation du Windows Driver Kit (WDK) courant et la septième édition de Windows Internals prévalent pour les interfaces supportées. Le manuel Evasion Lab a servi de source secondaire pour la méthodologie WinDbg et de reverse engineering ; ses symboles privés, offsets et observations de lab sont explicitement traités comme propres à un build.

WarningFrontière de preuve

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 pilotes 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 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 pilotes. Il arbitre notamment la création des processus, les accès aux objets, les opérations de fichiers et une partie du traitement réseau. Un pilote EDR peut s’enregistrer auprès de mécanismes documentés pour être rappelé lorsque ces transitions se produisent. 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 par des appels système, des requêtes d’entrée/sortie (input/output, I/O), des objets partagés sous contrôle du noyau et des files d’événements. Ils 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

ComposantCe qu’il représenteRôle techniqueLimite à garder en tête
Application observéeLe processus dans lequel s’exécute le comportement : navigateur, interpréteur de scripts, outil d’administration ou binaire natifProduit les appels, chargements d’images, accès mémoire, fichiers et connexions qui deviendront éventuellement des signauxUne application ne décrit pas elle-même l’intention de l’opérateur
Capteur user-modeUn module chargé ou injecté dans certains processus, ou un composant qui consomme leurs interfacesInstrumente des chemins d’API, collecte du contexte d’appel et peut inspecter du contenu ou de la mémoireUn appel qui ne traverse pas le chemin instrumenté peut échapper à ce capteur précis
Service EDR localLe processus durable qui coordonne l’agent sur l’endpointReçoit les événements, normalise les champs, enrichit les identités, applique une politique locale, maintient des files et dialogue avec le backendUne notification reçue par un pilote n’est pas nécessairement conservée, enrichie ou transmise
Pilote EDRUn module privilégié chargé dans le noyau WindowsEnregistre des callbacks, des filtres de fichiers ou des composants réseau et peut appliquer certaines décisions synchrones documentéesUn pilote 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 traçage de Windows, organisée autour de providers, sessions, contrôleurs et consumersTransporte des événements structurés du noyau ou des applications vers un consumer temps réel ou un fichierUn provider enregistré n’est pas forcément activé ; une session active ne garantit pas la rétention de chaque événement
Antimalware Scan Interface (AMSI)Une interface d’inspection de contenu intégrée par certaines applications, notamment des moteurs de scriptsSoumet du contenu déchiffré ou reconstruit à un fournisseur antimalware au moment choisi par l’application hôteAMSI n’est ni un provider ETW, ni un capteur universel de tous les processus
Minifilter de fichiersUn pilote branché au Filter Manager de Windows pour une sélection d’opérations de système de fichiersObserve ou influence des créations, lectures, écritures, renommages ou suppressions selon son enregistrementSon altitude ordonne les filtres ; elle ne garantit pas qu’un événement sera analysé avant toute autre couche
Windows Filtering Platform (WFP)La plateforme de filtrage de la pile réseau WindowsClasse le trafic à des couches précises et peut invoquer un callout EDR sélectionné par un filtreLes métadonnées disponibles et la capacité de blocage dépendent de la couche WFP invoquée
Backend d’analyseUn moteur local ou distant qui reçoit les événements normalisésCorrèle plusieurs capteurs, conserve l’état, enrichit la réputation et produit détections ou réponsesLe 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.

Schéma technique
ARCHITECTURE EDR MULTICOUCHE: Des capteurs indépendants deviennent utiles lorsqu'un service corrèle leurs observations partielles.ARCHITECTURE ENDPOINT · PIPELINE DE TÉLÉMÉTRIEARCHITECTURE EDR MULTICOUCHEDes capteurs indépendants deviennent utiles lorsqu'un service corrèle leurs observations partielles.ENDPOINT · MODE UTILISATEURENDPOINT · MODE NOYAUAGENT LOCALANALYSE / CONTRÔLEuserkernelfluxtamponreprisedécisionconfiguration / politiqueCOMPORTEMENTApplicationsProcessus · scriptsSIGNAUX USERHooks API · AMSIETWAppels · contenu · événementsWINDOWSGestionnairessystèmeProcessus · objets · I/OCAPTEURS KERNELCallbacksminifiltersCallouts WFPSERVICE EDRNormaliser+ enrichirIdentité · politique · santéFILE LOCALEBuffer + repriseRétention bornéeANALYSECorrélerle comportementDétecter · investiguerRÉPONSEPolitique + actionAlerter · isoler · contenirUN COMPORTEMENT · PLUSIEURS POINTS D'OBSERVATION · NORMALISATION LOCALE · TRANSPORT BUFFERISÉ · CORRÉLATION BACKEND
Architecture conceptuelle. Le placement des capteurs, le traitement local, le transport, l'analyse backend et la réponse restent propres au produit et à sa politique.Lecture du schémaLes deux lignes de l'endpoint se lisent de gauche à droite : les applications exposent des signaux user-mode, tandis que les gestionnaires Windows exposent des transitions kernel. Les deux alimentent le service EDR local. Celui-ci normalise et met les événements en tampon avant leur corrélation ; la politique revient par un chemin de contrôle distinct du flux de télémétrie.

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 pilote, 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 pilote 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 providers, l’échantillonnage, les exclusions, la politique locale et l’ingestion backend peuvent chacun modifier l’ensemble de preuves final.

SummaryUn graphe, pas un flux

L’endpoint se représente plus justement comme un graphe ordonné dans le temps. Processus, threads, fichiers, clés de registre, handles, images, sockets 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 enregistre un callback PCREATE_PROCESS_NOTIFY_ROUTINE_EX. Lors d’une création, ce callback reçoit un pointeur PEPROCESS, un identifiant de processus et une structure PS_CREATE_NOTIFY_INFO. Les champs documentés comprennent notamment l’identifiant du processus parent, les identifiants du processus et du thread créateurs, l’objet fichier de l’exécutable, le nom de l’image et la ligne de commande lorsqu’ils sont disponibles.

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.

Schéma technique
CALLBACK DE CRÉATION DE PROCESSUS: L'enregistrement et la livraison d'événement sont deux chemins distincts.TÉLÉMÉTRIE KERNEL · PROCESS MANAGERCALLBACK DE CRÉATION DE PROCESSUSL'enregistrement et la livraison d'événement sont deux chemins distincts.MODE UTILISATEURMODE NOYAUenregistreroutine stockéeDÉCLENCHEURCréer un processusThread créateurINIT PILOTEPilote EDRImage kernel signéeENREGISTREMENTPsSetCreateProcessNotifyRoutineExCallback ajouté une foisÉVÉNEMENTProcess ManagerChemin de créationDISPATCHNotify routinesPASSIVE_LEVELCALLBACK EDRCorréler la télémétrieObserver ou définirCreationStatusDONNÉES LIVRÉES · PEPROCESS · PID PROCESSUS · PID PARENT · TID CRÉATEUR · IMAGE · LIGNE DE COMMANDE
Chemin documenté du process-notify. Contrairement à une notification passive, le callback Ex peut refuser la création via CreationStatus.Lecture du schémaLe chemin pointillé supérieur représente l'enregistrement unique du pilote ; le chemin inférieur, la livraison de chaque événement processus. PASSIVE_LEVEL décrit les contraintes d'exécution et le contexte du thread créateur indique où le callback s'exécute : aucun des deux ne prouve une intention sans corrélation.

Le callback Ex s’exécute à PASSIVE_LEVEL dans le contexte du thread qui crée le processus. Il 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. Un pointeur PEPROCESS n’équivaut pas à une structure EPROCESS sérialisée ; 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. 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 convient à une sonde dans un lab contrôlé, pas au transport de télémétrie d’un produit.

process-notify.c
#include <ntddk.h>
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. La documentation ne définit aucun argument ETHREAD. Lors de la création, la routine s’exécute dans le contexte du thread ayant créé le nouveau thread, à un niveau de requête d’interruption (Interrupt Request Level, IRQL) inférieur ou égal à APC_LEVEL, le niveau associé aux Asynchronous Procedure Calls (APC).

Schéma technique
SIGNAL DE CYCLE DE VIE D'UN THREAD: Un notify callback est une primitive de corrélation, pas un verdict d'injection.TÉLÉMÉTRIE KERNEL · THREAD MANAGERSIGNAL DE CYCLE DE VIE D'UN THREADUn notify callback est une primitive de corrélation, pas un verdict d'injection.MODE UTILISATEURMODE NOYAUroutine enregistréecontexteDÉCLENCHEURCréer un threadLocal ou distantENREGISTREMENTPsSetCreateThreadNotifyRoutine[Ex]Initialisation piloteÉVÉNEMENTThread ManagerCréation · finDONNÉES CALLBACKProcessId · ThreadIdCreate = TRUE/FALSECONTEXTE D'EXÉCUTIONThread créateurÀ la créationCORRÉLATION EDRHypothèse d'injectionAutres signaux requisUNE DÉTECTION FIABLE EXIGE UNE CORRÉLATION · CONTEXTE CRÉATEUR · HANDLES · MÉMOIRE · CALL STACK
Le callback classique reçoit ProcessId, ThreadId et Create. Il ne reçoit ni structure ETHREAD ni champ processus source.Lecture du schémaLe callback identifie le processus cible, le nouveau thread et l'état création ou fin. Le contexte créateur ajoute une provenance, mais l'injection distante reste une hypothèse tant que des preuves de handle, mémoire, adresse de départ ou call stack ne la corroborent pas.

L’événement identifie le processus cible et le nouveau thread, mais n’établit pas à lui seul une injection de thread distant. 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. 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. Windows l’invoque après le mapping d’une image exécutable en mémoire virtuelle et avant l’exécution de son point d’entrée. Le callback reçoit un nom complet optionnel, l’identifiant du processus cible et des données IMAGE_INFO comprenant des propriétés de mapping telles que l’adresse de base et la taille.

Schéma technique
NOTIFICATION DE CHARGEMENT D'IMAGE: La notification arrive après le mapping et avant l'exécution du point d'entrée.TÉLÉMÉTRIE KERNEL · MAPPING D'IMAGENOTIFICATION DE CHARGEMENT D'IMAGELa notification arrive après le mapping et avant l'exécution du point d'entrée.MODE UTILISATEURMODE NOYAUREQUÊTELoadLibraryEXE · DLLLOADERMapper l'imageSection imageÉTATImage mappéeEntrypoint non exécutéNOTIFYCallbacks dechargementPASSIVE_LEVELEDREnrichir+ scorerHash · signer · pathLIMITE SÉMANTIQUECallback VOIDaucun retour Allow/DenyLe blocage exige un autre contrôleDONNÉES CALLBACK · NOM COMPLET (OPTIONNEL) · PROCESS ID · BASE · TAILLE · FLAGS
PLOAD_IMAGE_NOTIFY_ROUTINE retourne void. Il observe le mapping mais ne peut pas renvoyer directement Allow ou Deny.Lecture du schémaLa frontière essentielle est temporelle : le mapping existe déjà quand la notification est livrée, mais son point d'entrée n'a pas encore été exécuté. Le callback rapporte cette transition ; l'enrichissement de réputation et une éventuelle terminaison relèvent d'autres contrôles.

La routine retourne VOID et ne peut pas renvoyer directement une décision d’autorisation ou de blocage. Le statut de signature, la réputation du hash, les informations de catalogue et la prévalence ne sont pas des champs intrinsèques du callback. Un capteur peut enrichir l’événement par d’autres mécanismes. Une action préventive exige un contrôle distinct ou un chemin de réponse propre au produit.

Opérations sur le registre

Sur les versions actuelles de Windows, un pilote de filtrage du registre s’enregistre via CmRegisterCallbackEx. Le Configuration Manager invoque le callback pour des opérations identifiées par REG_NOTIFY_CLASS. Les API de registre user-mode et les routines kernel Zw* peuvent toutes deux atteindre ce chemin.

Schéma technique
CHEMIN DE FILTRAGE DU REGISTRE: Les appels user-mode et kernel-mode convergent vers le Configuration Manager.TÉLÉMÉTRIE KERNEL · CONFIGURATION MANAGERCHEMIN DE FILTRAGE DU REGISTRELes appels user-mode et kernel-mode convergent vers le Configuration Manager.APPELANTSCHEMIN REGISTRE KERNELstatutUSER MODEAPI Reg*Create · set · queryKERNEL MODERoutines Zw*Appelant piloteDISPATCHConfigurationManagerOpération typéePRE-NOTIFYRegistryCallbackInspecter · bloquerModifierPOST-NOTIFYRegistryCallbackObserver le résultatOPÉRATIONRuche registreExécuter si autoriséEDRCorrélerAlerterDONNÉES SPÉCIFIQUES · KEY OBJECT · VALUE NAME · DATA · CONTEXTE PROCESS/THREAD · STATUT
CmRegisterCallbackEx enregistre une routine recevant des notifications pre/post typées par REG_NOTIFY_CLASS.Lecture du schémaLes deux chemins d'appel convergent vers le même manager. Une pre-notification peut influencer une opération supportée avant son exécution ; la post-notification rapporte le statut obtenu. Les champs et modifications possibles dépendent du REG_NOTIFY_CLASS exact, pas d'un schéma registre universel.

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

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.

Schéma technique
CONTRÔLE DES HANDLES PROCESS / THREAD: Les object callbacks interviennent sur la création et la duplication de handles.TÉLÉMÉTRIE KERNEL · OBJECT MANAGERCONTRÔLE DES HANDLES PROCESS / THREADLes object callbacks interviennent sur la création et la duplication de handles.MODE UTILISATEURMODE NOYAUrestreindreSOURCEOpenProcess /DuplicateHandleAccès demandéSYSTEM CALLObject ManagerOpération handlePRE-OPCallback EDRInspecter la requêteACTION SUPPORTÉEDesiredAccess &= allowed_maskRetirer des droits, jamais en ajouterRÉSULTATHandleDroits réduitsPOST-OPTélémétrieStatut finalPRE-OP · TYPE D'OBJET · CREATE/DUPLICATE · ACCÈS ORIGINAL · DESIRED ACCESS MODIFIABLE · KERNEL HANDLE
ObjectPreCallback doit retourner OB_PREOP_SUCCESS. La protection retire des droits supportés de DesiredAccess ; elle ne renvoie pas Deny.Lecture du schémaDesiredAccess représente l'ensemble des capacités demandées pour le futur handle. Le pre-callback peut retirer des bits supportés avant son émission : l'ouverture peut réussir tout en produisant un handle incapable d'écrire en mémoire, de créer un thread ou d'exécuter une autre action protégée.

Un ObjectPreCallback doit retourner OB_PREOP_SUCCESS ; il ne renvoie pas un statut arbitraire de refus. Pour les droits de processus et de thread modifiables, le callback peut retirer des bits de DesiredAccess, 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.

object-pre-callback.c
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

FltMgr.sys gère les instances de minifilters attachées aux volumes. Chaque minifilter s’enregistre seulement pour les opérations d’entrée/sortie (input/output, I/O) sélectionnées. Dans le modèle de pilotes Windows, celles-ci sont transportées par des paquets de requête d’entrée/sortie (I/O Request Packet, IRP). L’altitude attribuée détermine la position relative du minifilter dans la pile ; le nom d’un produit ne définit aucun ordre fixe entre EDR et antivirus.

Schéma technique
PILE I/O DES MINIFILTERS: L'altitude, et non le nom du produit, détermine l'ordre des callbacks.TÉLÉMÉTRIE KERNEL · FILTER MANAGERPILE I/O DES MINIFILTERSL'altitude, et non le nom du produit, détermine l'ordre des callbacks.UN VOLUME · INSTANCES MINIFILTER ORDONNÉESPOST-OP · LOW → HIGHPRE-OP · HIGH → LOWORIGINERequête I/OCreate · read · writeROUTEURFltMgr.sysOpérations inscritesALTITUDE HAUTEMinifilter APre premierPost dernierALTITUDE BASSEMinifilter BPre après · post avantSTOCKAGEFile systemTerminer l'opérationCOMPLÉTIONStatut · octetsMétadonnéesChemin retourPRE-OP PEUT LAISSER PASSER · DEMANDER UN POST-OP · PENDRE · SYNCHRONISER · OU TERMINER L'I/O
FltMgr appelle les pre-operation de la plus haute à la plus basse altitude ; le retour post-operation suit l'ordre inverse.Lecture du schémaLe chemin supérieur suit la requête : les instances de haute altitude s'exécutent avant les plus basses. Le chemin inférieur suit la complétion : les post-operation remontent dans l'ordre inverse. Seules les opérations enregistrées par chaque minifilter participent à ce trajet.

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, synchronisation de section et modification de métadonnées peuvent alimenter les détections de ransomware, staging, altération et collecte. 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.

minifilter-operations.c
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

ETW comprend des providers, sessions, contrôleurs et consumers. Un contrôleur démarre et configure une session puis active des providers. Les providers activés écrivent leurs événements dans les buffers de session. Un consumer lit ces événements en temps réel ou depuis un fichier Event Trace Log (ETL). Un service EDR peut cumuler les rôles de contrôleur et de consumer, mais le contrôleur ne constitue pas une étape intermédiaire du flux d’événements.

Schéma technique
FLUX D'UNE SESSION ETW: Le contrôleur configure ; les providers écrivent ; les consumers lisent.TÉLÉMÉTRIE SYSTÈME · EVENT TRACING FOR WINDOWSFLUX D'UNE SESSION ETWLe contrôleur configure ; les providers écrivent ; les consumers lisent.PLAN DE CONTRÔLEPLAN DE DONNÉES ÉVÉNEMENTconfigureactivegèreécritlitCONTRÔLEURService EDRDémarrer sessionActiver providersTRACE SESSIONPolicy + buffer poolLevel · keywords · modePROVIDERSApplicationsComposants systèmeUser mode · kernelBUFFERS SESSIONFlux ordonnéTemps réel et/ou ETLCONSUMERService EDRDécoder · filtrerANALYTIQUECorrélerDétection · alerteEVENT RECORD · IDENTIFIANTS PROVIDER / ÉVÉNEMENT / ACTIVITÉ · LEVEL · KEYWORD · TIMESTAMP · PID/TID · PAYLOAD
Le contrôleur appartient au plan de contrôle, pas au flux d'événements. Les providers écrivent dans les buffers lus en temps réel ou via ETL.Lecture du schémaLe plan supérieur configure les providers, classes d'événements, buffers et modes de livraison de la session. Le plan inférieur transporte les données : les providers écrivent les enregistrements dans les buffers et les consumers les lisent. Un même service peut tenir les deux rôles sans faire du contrôleur un relais d'événements.

Les enregistrements peuvent contenir un identifiant de provider, un identifiant et une version d’événement, un niveau, un keyword, un horodatage, des PID et TID, des identifiants d’activité et un payload défini par le provider. Le schéma exact provient du manifeste, des métadonnées TraceLogging, du Managed Object Format (MOF) ou d’un fichier Trace Message Format (TMF). ETW est une infrastructure de transport et d’instrumentation ; elle 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. 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 expose des couches de filtrage à des points sélectionnés de la pile réseau. Des shims extraient les valeurs classifiables et invoquent le filter engine. Les filtres évaluent leurs conditions à une couche et peuvent sélectionner une action intégrée ou invoquer un callout enregistré pour 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) permettent notamment une classification tenant compte de l’application et de l’utilisateur.

Schéma technique
CHEMIN DE CLASSIFICATION WFP: Un filtre correspondant invoque éventuellement un callout à une couche WFP.TÉLÉMÉTRIE RÉSEAU · WINDOWS FILTERING PLATFORMCHEMIN DE CLASSIFICATION WFPUn filtre correspondant invoque éventuellement un callout à une couche WFP.POLITIQUE / GESTIONCLASSIFICATION KERNELgèrefiltresmatchclasseSERVICE EDRPolicy providerAjouter filtres + contexteBFEPolitique filtresConfiguration persistanteTRAFICSocket / flowPacket · streamALESHIMPile TCP/IPExtraireles conditionsCOUCHEFilter engineClasser + arbitrerOPTIONNELCallout EDRInspecter · annoterACTIONPermettreou bloquerDécisionCHEMINRéseauContinuerLES MÉTADONNÉES ALE LIENT LE FLUX AU PROCESSUS · APPLICATION · UTILISATEUR · ADRESSES · PORTS · PROTOCOLE
Un shim amène le trafic à une couche WFP ; le filter engine évalue les conditions et peut invoquer le callout EDR avant d'appliquer l'action.Lecture du schémaLa couche est un point d'observation, le filtre exprime une politique à ce point et le callout est du code spécialisé optionnel sélectionné par un filtre correspondant. Les métadonnées et le pouvoir du callout sont donc bornés par la couche d'invocation et les règles d'arbitrage WFP.

Le BFE coordonne la politique et la configuration persistante en mode utilisateur ; la classification aux couches réseau et transport s’exécute en mode noyau. Aux couches ALE, les métadonnées peuvent relier un flux à l’identité d’une application ou d’un utilisateur, au protocole et aux extrémités locales ou distantes. 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 les règles d’arbitrage WFP. L’inspection de payload, le réassemblage de flux 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 sélectionnés de modules tels que ntdll.dll. Un inline hook courant remplace le prologue d’une fonction par un branchement vers le code du capteur, produit la télémétrie, puis utilise un trampoline pour exécuter les instructions déplacées avant de reprendre le chemin original.

Schéma technique
CHEMIN D'UN APPEL NTDLL HOOKÉ: Un detour ajoute un point d'observation avant le chemin syscall original.TÉLÉMÉTRIE USER-MODE · INLINE DETOURCHEMIN D'UN APPEL NTDLL HOOKÉUn detour ajoute un point d'observation avant le chemin syscall original.MODE UTILISATEURMODE NOYAUévénementAPPELANTApplicationNtCreateThreadExEXPORTEntrée ntdllPrologue patchéDETOURHook EDRInspecter + émettreTRAMPOLINEOctetsoriginauxReprendre l'exécutionTRANSITIONStub syscallIdentifiant propreau buildSORTIE CAPTEURFile locale → service EDRSpécifique au produitSERVICE SYSTÈMEExécution kernelSIGNAUX USER-MODE POSSIBLES · PARAMÈTRES · VALEUR RETOUR · CALL STACK · MODULE APPELANT · INTÉGRITÉ MÉMOIRE
C'est un pattern courant, pas un contrat universel des EDR. Un syscall direct saute seulement ce detour user-mode ; les autres capteurs restent actifs.Lecture du schémaLe detour observe les appels qui traversent l'export patché ; le trampoline rejoue ensuite les instructions déplacées et rejoint le stub normal. Contourner cet export retire ce point d'observation, pas l'opération kernel ni les changements d'état indépendamment observables qu'elle peut produire.

Ce pattern n’est pas universel. Les produits peuvent employer d’autres stratégies d’injection, frameworks d’instrumentation, sources d’événements et politiques de processus protégés. Un appel système direct peut contourner le detour d’un export user-mode, mais il ne contourne ni l’appel système lui-même ni 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. 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. Un modèle robuste associe donc l’identifiant à l’heure de création, à l’époque de boot ou du capteur et, 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 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 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. 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, interrupt time, performance counter, timestamps ETW, temps de réception par le service local et temps d’ingestion backend. Un modèle défendable préserve le domaine d’horloge 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. Un fichier peut être renommé après sa création ; un chemin peut inclure des reparse points, device paths, hard links ou redirecteurs réseau ; le nom d’une image processus peut diverger de l’état ultérieur sur disque. 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

Chaque chemin de collecte possède 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, abandonner des événements de faible priorité ou fonctionner en mode fail-open lorsqu’une file est saturée.

Les contrôleurs ETW peuvent exposer des statistiques de buffers et d’événements perdus. Les files produit peuvent publier des compteurs de santé, logs de diagnostic ou heartbeats. 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écanismeObservation nativeInfluence synchrone nativeFrontière importante
Process notify ExCréation, fin et métadonnées documentéesCreationStatus peut faire échouer la créationLe produit peut employer le callback uniquement pour la télémétrie
Thread notifyPID cible, TID et état création/suppressionAucun retour allow/deny documentéL’injection exige une corrélation au-delà du callback
Image-load notifyMétadonnées du mapping d’imageAucun retour allow/deny ; callback VOIDLe mapping existe déjà lors de la notification
Registry callbackDonnées pre/post typéesLe pre-callback peut bloquer ou modifier les opérations supportéesLes champs et modifications dépendent de REG_NOTIFY_CLASS
Object callbackCréation ou duplication d’un handle process/threadLes bits d’accès supportés peuvent être retirésLe pre-callback retourne success ; ce n’est pas un hook de refus générique
Minifilter pre-opOpérations de système de fichiers enregistréesLaisser passer, pendre, modifier, synchroniser ou terminerL’ordre dépend de l’altitude et des opérations enregistrées
Consumer ETWÉvénements émis vers une session activéeAucune via le rôle de consumerActivation du provider et rétention sont des décisions séparées
Callout WFPMétadonnées de flux, stream, packet ou ALE propres à la coucheLa classification peut contribuer à permit/blockDroits, arbitrage et données disponibles varient selon la couche
Detour user-modeArguments, contexte appelant, retour et données produitLe hook peut altérer ou refuser l’appel user-modeSeuls 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 pilote signé.

Protected Process Light restreint l’accès aux processus protégés selon le niveau de signature et l’opération demandée. Ce mécanisme 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.

Virtualization-Based Security (VBS, sécurité fondée sur la virtualisation) et Hypervisor-Protected Code Integrity (HVCI, intégrité du code protégée par l’hyperviseur) déplacent ou appliquent certaines décisions d’intégrité depuis un environnement isolé. La blocklist des pilotes vulnérables et App Control ajoutent une politique sur les images kernel autorisées au chargement. Ces mécanismes réduisent l’exposition aux pilotes 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 surveille certains codes et structures kernel critiques 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 : listes de contrôle d’accès (Access Control List, ACL) des services et des devices de pilotes, services protégés, watchdogs, contrôles de santé des callbacks, intégrité des modules, signature de configuration et état de santé backend peuvent tous contribuer. Anti-tamper et détection comportementale restent distincts. Empêcher l’arrêt d’un service ne prouve pas la visibilité d’une attaque, et détecter une modification mémoire ne prouve pas la collecte du comportement initial.

De la télémétrie à la détection

La collecte ne constitue que la première étape d’un pipeline EDR. La qualité de détection dépend de la normalisation, de l’enrichissement, de l’état et de la corrélation.

ÉtapeFonction typiquePrincipaux modes de défaillance
CollecteRecevoir callbacks, événements, I/O, flux et signaux user-modeCapteur désactivé, callback absent, provider non activé, perte d’événements
NormalisationConvertir les enregistrements produit dans un schéma interne stableChamps manquants, identité ambiguë, dérive d’horloge ou de schéma
EnrichissementRésoudre signature, hash, réputation, token, chemin, lignée et contexte assetDépendance réseau, cache périmé, races de chemin, objets inaccessibles
CorrélationRelier les événements entre processus, threads, sessions et hôtesRéutilisation d’identifiants, fenêtres incomplètes, échantillonnage, délai backend
DécisionScorer, alerter, bloquer, isoler ou collecter des preuvesDiffé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é.

ImportantRègle d'interprétation

Un résultat de bypass reste limité à un chemin de collecte ou d’application. La perte d’un signal n’établit pas la perte du graphe comportemental, de la prévention ou de la détection backend.

Schéma technique
ÉVASION ≠ INVISIBILITÉ: Chaque bypass vise un chemin de collecte ; des contrôles indépendants voient encore le comportement.MODÈLE RED TEAM · COUVERTURE CAPTEURSÉVASION ≠ INVISIBILITÉChaque bypass vise un chemin de collecte ; des contrôles indépendants voient encore le comportement.VISIBILITÉ CIBLÉEANGLE MORT TENTÉVISIBILITÉ / CONTRÔLE RÉSIDUELHOOKS USER-MODEDetours ntdllBYPASSUnhook / syscall directENCORE VISIBLECallbacks · ETW · WFP · mémoireCHEMIN ETW LOCALÉcriture providerBYPASSPatcher un seul processusENCORE VISIBLEKernel / autres providers · intégritéCALLBACK KERNELNotify routineBYPASSPrimitive d'écriture kernelRISQUE / CONTRÔLEIntégrité · crash · télémétrieCONFIANCE KERNELPolitique pilotes signésATTAQUEPilote signé vulnérableMITIGATIONHVCI · blocklist · App ControlRÈGLE DE VALIDATION · NOMMER LE CAPTEUR · TESTER LE BUILD CIBLE · MESURER LES SIGNAUX RÉSIDUELS · INTÉGRITÉ
Le modèle utile relie la technique au capteur précisément affecté, puis inventorie la visibilité résiduelle et les mitigations plateforme.Lecture du schémaChaque ligne se lit de gauche à droite : identifier le capteur visé, formuler précisément l'angle mort tenté, puis mesurer les signaux et contrôles restants. La colonne centrale ne démontre jamais à elle seule une invisibilité globale de l'endpoint.

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

Le patch de EtwEventWrite dans un processus affecte les appels traversant cette copie et ce chemin de code. Il 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 et une découverte propre au build. L’opération ne correspond pas à un code de contrôle d’entrée/sortie (Input/Output Control, IOCTL) générique « remove callback ». Un pilote vulnérable expose son propre protocole de device et ses propres primitives ; l’exploitation doit implémenter la sémantique de lecture/écriture du pilote 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.

Pilotes 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 Hypervisor-Protected Code Integrity, la blocklist Microsoft des pilotes vulnérables, les politiques App Control et la règle Attack Surface Reduction contre l’abus de pilotes 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.

Le manuel de lab fourni énumère les routines de notification de processus, threads et images à l’aide de symboles kernel privés, examine les enregistrements de callbacks registre et objets, parcourt les callback nodes des minifilters et résout l’état du provider ETW Threat Intelligence (ETW-TI). Il masque également les entrées encodées de callbacks et utilise une primitive issue d’un pilote vulnérable pour modifier la mémoire kernel. Ces techniques démontrent que le build du lab peut être inspecté et 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 pilotes ;
  • la source du symbol server, l’identité du fichier Program Database (PDB), l’état de chargement des symboles et la présence éventuelle d’informations de types privées ;
  • 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 pilote 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 pilote 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, références de rundown, files de workers, watchdogs, callbacks alternatifs et preuves backend. Une écriture réussie n’équivaut pas à un contournement propre ou durable du capteur.

WarningPérimètre du support de lab

Le manuel fourni est utile comme protocole expérimental. Ses symboles privés et offsets ne sont pas repris comme faits actuels ; chacun doit être redécouvert et prouvé sur le build cible.

Erreurs d’analyse fréquentes

  1. Confondre enregistrement et flux d’événements. Une API de setup appelée lors de l’initialisation du pilote 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 comparable et une opération bénigne de même forme API.
  8. Ignorer la récupération. Watchdogs, réenregistrement, reboot, refresh de politique et mises à jour peuvent annuler une modification transitoire.
  9. Supposer un numéro de syscall fixe. L’architecture et le build Windows déterminent le stub ; les exemples hardcodés vieillissent immédiatement.
  10. Assimiler pilote 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 testSource primaire testéeSources résiduelles indépendantesPreuves de résultat requises
Création de processusCallback Process ExMapping image, ETW, lignée de handles, audit de serviceStatut de création, événement brut, lignée d’entité, action de politique
Comportement de thread distantThread callback ou hook user-modeObject callbacks, mémoire, ETW-TI, état de la cibleIdentités source/cible, droits, adresse de départ, résultat du thread
Introduction d’imageCallback image-loadMinifilter, Code Integrity, scan mémoire, ETWÉtat du mapping, signature/hash enrichis, résultat d’exécution
Persistance registreRegistry callbackLignée processus, télémétrie services/tâches, activation ultérieureStatut pre/post, clé et valeur résolues, identité initiatrice
Accès à un processus sensibleObject callbackÉvénements d’audit, lectures mémoire, threads, état de protectionAccès original/réduit, handle accordé, opération suivante
Transformation de fichiersMinifilterProcess/thread, analyse de contenu ou entropie, volumeRésultat pre/post, identité chemin/octets, débit et périmètre
Script ou code managéChemin ETW/AMSIProcessus, images, fichiers, réseau, mémoireActivation provider, contenu disponible, comportement aval
Connexion réseauWFP/ALEDomain Name System (DNS), lignée processus, proxy, Transport Layer Security (TLS), logs distantsCouche, direction, endpoints, identité application, action
Contournement d’un hook userExport instrumentéCallbacks kernel, ETW, WFP, minifilter, mémoireIntégrité du hook, chemin réel, graphe d’événements résiduel
Chargement ou abus d’un piloteCode Integrity et politique pilotesCallback image, registre service, minifilter, télémétrie kernelDé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, pilotes 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.

Collect-EdrSurface.ps1
$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

Ce snapshot 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.
ImportantL'idée transférable

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.

Les sections du manuel Evasion Lab consacrées à l’énumération de callbacks, à la manipulation des minifilters et à ETW Threat Intelligence démontrent une méthode de lab fondée sur les symboles WinDbg et une primitive de lecture/écriture issue d’un pilote vulnérable. Ces exercices constituent une preuve de méthode sur le build fourni, pas une preuve que les offsets, layouts internes, propriétaires de callbacks ou états de providers sont identiques sur un autre système.

Références

Utiliser avec une IA

Actions