← Blog
VeilleWindowsEDRWESPAM-PPLETW

WESP : ce que l'analyse d'Elastic dit vraiment de l'EDR hors du noyau Windows

28 octobre 2026 · 18 min de lecture · Niveau : Avancé

Illustration : une plateforme de sécurité WESP à l'écran d'un portable Windows, un bloc « Mode utilisateur » lumineux posé sur un bloc « Mode noyau » fissuré, et une menace rouge pixelisée qui attaque le noyau

Depuis la panne CrowdStrike du 19 juillet 2024, Microsoft veut sortir les solutions de sécurité du noyau Windows. Le cadre prévu s’appelle le Windows Endpoint Security Platform (WESP). Il est arrivé dans des builds Windows Insider sous la forme de deux binaires : wesp.sys, un pilote noyau, et espclient.dll, l’API que les éditeurs appelleront depuis le mode utilisateur.

Le 26 octobre 2026, Pavel Yosifovich a publié chez Elastic Security Labs Kernel eviction notice, une analyse menée sous débogueur noyau. WESP n’est pas documenté, mais Microsoft publie ses symboles, et on peut aller assez loin. Sa conclusion la plus reprise : un client WESP en mode utilisateur ne pourrait pas, pour l’instant, bloquer la création d’un processus. Pour un EDR, la différence est énorme. Un outil qui ne fait qu’observer ne fait plus le même métier qu’un outil qui empêche.

On a relu cette analyse capture par capture et on l’a recoupée avec les autres travaux publics. Précision importante : rien n’a été testé ici. Les captures sont celles d’Elastic, créditées sous chaque image, et les schémas les résument.

En bref

  • Établi : WESP est livré dans des builds Insider. wesp.sys est un mini-filtre de système de fichiers qui démarre au boot, et il dialogue avec le mode utilisateur par un port de filtre, \EspFilterPort, que deux sources indépendantes ont vu.
  • Montré par Elastic : wesp.sys s’abonne aux créations de processus, à celles de threads et aux chargements d’images. Côté client, espclient.dll reçoit et envoie des messages, mais n’importe pas FilterReplyMessage, la fonction qui sert à répondre au pilote.
  • Ce que ça indique : le client n’utilise pas la fonction de réponse prévue par l’API de filtre. C’est un indice fort, pas une preuve : une réponse peut passer par un autre canal, Elastic écrit lui-même « at least not yet », et une autre source décrit des règles évaluées directement dans le noyau.
  • Côté éditeurs : Elastic annonce que son EDR, Elastic Defend, se prépare à prendre en charge WESP.
  • Pour un SOC : rien à industrialiser pour l’instant. Les artefacts sont connus et vérifiables sur une VM Insider. Il faut surveiller l’API de réponse, l’exigence PPL et la journalisation.

Comment un EDR fonctionne aujourd’hui

Un EDR classique tient en deux morceaux : un service en mode utilisateur, qui analyse, applique des règles et remonte au serveur, et un pilote noyau propre à l’éditeur. C’est ce pilote qui s’abonne aux événements du système et les fait remonter. Elastic rappelle qu’il y a un mécanisme d’abonnement par famille d’événements :

Événements Mécanisme actuel
Processus, threads, images chargées, handles Fonctions d’enregistrement avec callback
Registre Fonctions d’enregistrement avec callback
Système de fichiers Mini-filtre
Réseau Pilote callout WFP

Le pilote donne surtout un pouvoir que le mode utilisateur n’a pas : refuser une opération. L’exemple type est PsSetCreateProcessNotifyRoutineEx. Son callback est appelé pendant la création d’un processus et peut lui imposer un statut d’échec, par exemple après avoir lu une ligne de commande jugée malveillante. Depuis le mode utilisateur, on peut savoir qu’un processus démarre, pas l’en empêcher.

Le revers est connu : une erreur non gérée dans ce pilote, un accès mémoire invalide par exemple, arrête tout le système avec un écran bleu. Le 19 juillet 2024, un fichier de configuration défectueux a fait planter le pilote de CrowdStrike sur environ 8,5 millions de machines. WESP inverse le modèle : un seul pilote, écrit et testé par Microsoft, et des éditeurs qui restent en mode utilisateur. Le risque noyau ne disparaît pas pour autant, Elastic en relève d’ailleurs l’ironie : wesp.sys reste du code noyau. Il se concentre simplement dans un pilote au lieu d’un par éditeur.

Schéma comparant l’architecture EDR actuelle, avec un pilote noyau propre à chaque éditeur, et l’architecture WESP, où le service de l’éditeur reste en mode utilisateur et dialogue avec wesp.sys de Microsoft par le port \EspFilterPort

Schéma d’après l’analyse d’Elastic. La ligne rouge en pointillés sépare le mode utilisateur du mode noyau.

Ce que montrent les binaires

Un mini-filtre chargé au démarrage

Première trace : la clé de service du pilote.

Éditeur du registre ouvert sur HKLM\SYSTEM\CurrentControlSet\Services\wesp : DependOnService FltMgr, Group FSFilter Anti-Virus, ImagePath system32\drivers\wesp.sys, Start 0, Type 2

Capture : Pavel Yosifovich, Elastic Security Labs.

Chaque valeur dit quelque chose. Type = 2 désigne un pilote de système de fichiers. Start = 0 veut dire qu’il est chargé au démarrage, avant la plupart des pilotes. Group = FSFilter Anti-Virus est le groupe de chargement des filtres antivirus, et DependOnService = FltMgr montre qu’il dépend du gestionnaire de filtres. Une clé wespelam apparaît juste en dessous, ce qui va dans le sens du pilote de démarrage précoce wesp_elam.sys décrit par le dépôt marcosd4h/wesp-research.

Sous WinDbg, !drvobj wesp f confirme ce profil. Extrait de la sortie publiée par Elastic :

lkd> !drvobj wesp f
Driver object (ffffc0e9fe2e6310) is for:
 \FileSystem\wesp
[00] IRP_MJ_CREATE            fffff805d07a14d0  nt!IopInvalidDeviceRequest
[0e] IRP_MJ_DEVICE_CONTROL    fffff805d07a14d0  nt!IopInvalidDeviceRequest
Device Object stacks:
Processed 0 device objects.

L’objet pilote est rangé sous \FileSystem, comme les mini-filtres. Toutes les routines de dispatch pointent vers le gestionnaire par défaut du noyau, et il n’existe aucun objet périphérique. Il n’y a donc rien à ouvrir avec CreateFile et aucun DeviceIoControl possible : la communication passe forcément par un autre canal.

Les abonnements du pilote

Total PE affichant les imports de wesp.sys : FLTMGR.SYS (82 fonctions), ntoskrnl.exe (196), HAL.dll (1), avec PsSetCreateProcessNotifyRoutineEx2, PsSetCreateThreadNotifyRoutineEx et PsSetLoadImageNotifyRoutineEx surlignés

Capture : Pavel Yosifovich (outil Total PE), Elastic Security Labs.

wesp.sys importe 82 fonctions du gestionnaire de filtres, 196 du noyau et une de la HAL. Les trois lignes surlignées sont celles d’un EDR : notification de création de processus (PsSetCreateProcessNotifyRoutineEx2), de threads et de chargement d’images. Le point compte pour la suite : PsSetCreateProcessNotifyRoutineEx2 enregistre le même type de callback que la fonction Ex décrite plus haut, celui qui peut faire échouer la création d’un processus. Le mécanisme de blocage est donc présent côté noyau. La question est de savoir s’il est mis à disposition des clients.

fltmc donne l’altitude du filtre, c’est-à-dire sa place dans la pile. Extrait de la sortie publiée par Elastic :

Filter Name     Num Instances    Altitude    Frame
bindflt                 1        409800        0
UCPD                    5        385250.5      0
wesp                    7        329500        0
WdFilter                5        328010        0

Un filtre d’altitude plus haute reçoit les opérations avant ceux qui sont en dessous. wesp (329500) passe donc juste avant WdFilter (328010), le filtre de Microsoft Defender.

Le canal vers le mode utilisateur

Faute de périphérique, wesp.sys utilise un port de communication de filtre : il importe FltCreateCommunicationPort, et WinObj montre le port à la racine de l’espace de noms.

WinObj affichant à la racine l’objet EspFilterPort de type FilterConnectionPort, à côté des ports MicrosoftMalwareProtection de Defender

Capture : Pavel Yosifovich (outil WinObj de Sysinternals), Elastic Security Labs.

\EspFilterPort est de type FilterConnectionPort, voisin des ports MicrosoftMalwareProtection…PortWD de Defender. Le dépôt marcosd4h décrit le même port comme plan de contrôle de WESP : c’est le seul artefact technique vu par deux sources indépendantes.

L’API cliente

Total PE affichant les exports de espclient.dll : 120 fonctions préfixées Esp, dont EspConnectClient, EspCreateFileFilter, EspCreateEventQueue, EspArmEventNotification et EspCompleteEventNotification

Capture : Pavel Yosifovich (outil Total PE), Elastic Security Labs.

espclient.dll expose 120 fonctions en C, toutes préfixées Esp. On y lit des familles cohérentes avec un EDR : connexion (EspConnectClient), filtres par type d’objet (EspCreateFileFilter, EspCreateDiskFilter…), règles (EspCloseRule) et files d’événements (EspCreateEventQueue). Ces filtres permettent d’écarter les événements sans intérêt dès le pilote, au lieu de tout remonter en mode utilisateur.

Côté imports, le DLL n’utilise que trois fonctions de FltLib.dll : FilterConnectCommunicationPort, FilterGetMessage et FilterSendMessage.

Le nœud du problème : qui peut bloquer ?

Il manque une fonction, et Elastic le relève : « A missing function (in my mind) is FilterReplyMessage, which allows a direct reply to a message from the driver. » Sans elle, le client peut recevoir une notification et envoyer des messages au pilote. Il ne peut pas répondre à une notification en attente pour dire « refuse ce processus ». Elastic en conclut que la réponse du client vers le pilote n’est « probably not implemented, at least not yet ».

Schéma de décision : pendant la création d’un processus, le callback de wesp.sys peut imposer un échec. Chemin A, le client répond au pilote : absent, faute de FilterReplyMessage. Chemin B, des règles compilées à l’avance sont évaluées dans le noyau : non démontré

Schéma de synthèse. Le chemin A vient d’Elastic, le chemin B du dépôt marcosd4h et des tests d’Adrian’s Security Research.

Pour le chemin A, il faut séparer trois niveaux :

  • Observation : FilterReplyMessage n’apparaît pas dans les imports de espclient.dll, dans le build examiné par Elastic.
  • Déduction : le client n’utilise pas le mécanisme de réponse que l’API de filtre prévoit pour ça.
  • Limite : ça ne prouve pas qu’aucune réponse n’existe. Une table d’imports ne montre pas les fonctions résolues à l’exécution (GetProcAddress). Surtout, FilterSendMessage, bien présent, pourrait porter un verdict : le pilote garderait la création en attente jusqu’à recevoir la décision du client par un message séparé. C’est notre interprétation, aucune source ne décrit ce montage, mais il suffit à empêcher de conclure.

L’absence de l’import est donc un indice architectural fort, pas une preuve du comportement à l’exécution.

Le chemin B est décrit ailleurs. Le dépôt marcosd4h explique que l’espace utilisateur « compiles detection rules into binary decision graphs, and the kernel evaluates them directly during pre-operation callbacks ». Le client confierait ses règles à l’avance, et le callback du noyau déciderait seul, sans aller-retour. L’absence de FilterReplyMessage serait alors un choix de conception plutôt qu’un manque. Les noms de règles et de filtres dans les exports de espclient.dll vont dans ce sens, sans le prouver.

Mallory.ai, un agrégateur qui semble produire ses résumés automatiquement, rapporte les tests d’Adrian’s Security Research, dont l’article d’origine n’a pas pu être consulté. Un client restreint y pose une règle de refus ProcessCreate. La règle retourne E_ACCESSDENIED, et le binaire de test s’exécute quand même. Selon ce résumé, les règles de blocage seraient réservées aux clients AM-PPL.

Les exports contiennent aussi EspArmEventNotification et EspCompleteEventNotification. Leur rôle n’est pas documenté, et aucune source ne dit s’ils transportent une décision : on ne peut rien en tirer.

Trois explications restent donc ouvertes pour l’absence de blocage observée : des règles évaluées dans le noyau mais réservées à l’AM-PPL, une fonction pas encore terminée (l’hypothèse d’Elastic), ou les deux à la fois.

Qui peut se connecter à WESP

Sur le contrôle d’accès, les sources concordent sur l’essentiel mais divergent sur le niveau de protection exigé.

  • Elastic indique que les processus clients doivent être élevés, et qu’ils devront « likely » tourner en Protected Process Light signé par Microsoft, comme la plupart des services EDR aujourd’hui.
  • Jonathan Johnson, qui a travaillé sur le build 29661, décrit un contrôle par l’attribut de jeton WESP://Permission. Il relève deux valeurs, 10000000 et 1000000000, dont la seconde exige le niveau AM-PPL (0x31). Il a pu se connecter depuis un processus élevé, avec le test signing activé.
  • Adrian’s Security Research, via Mallory.ai, rapporte la même chose sur le build 29695.1001 : un processus SYSTEM sans AM-PPL s’enregistre comme client restreint, énumère les produits de sécurité installés et reçoit de la télémétrie noyau.

L’écart entre « PPL probablement requis » et « connexion possible sans PPL » tient plus vraisemblablement à l’état préliminaire des builds qu’à un vrai désaccord. Les analyses ne portent pas sur le même build : 29661 pour Johnson, une plage 10.0.29641 à 10.0.29667 pour marcosd4h, 29695.1001 pour Adrian, et un build non précisé pour Elastic.

Les artefacts à connaître

Artefact Ce qu’on en sait Source Fiabilité
C:\Windows\System32\drivers\wesp.sys Pilote noyau, mini-filtre, altitude 329500 Elastic Binaire corroboré, altitude d’Elastic seul (sortie fltmc publiée)
HKLM\SYSTEM\CurrentControlSet\Services\wesp Type 2, Start 0, Group FSFilter Anti-Virus, DependOnService FltMgr Elastic Capture publiée
\EspFilterPort Port de communication de filtre, type FilterConnectionPort Elastic, marcosd4h Corroboré
C:\Windows\System32\espclient.dll API cliente en C, 120 exports Esp* Elastic, Johnson Corroboré
Imports de espclient.dll FilterConnectCommunicationPort, FilterGetMessage, FilterSendMessage, sans FilterReplyMessage Elastic Source unique
Imphash de wesp.sys 4a4fa95ce752110a09344c510470b783, affiché par Total PE Elastic Capture publiée, build non identifié
wesp_elam.sys, clé wespelam Synchronisation au démarrage précoce marcosd4h, capture d’Elastic Clé visible, rôle décrit par un dépôt sans revue
HKLM\SYSTEM\CurrentControlSet\Services\wesp\PersistedStore\Clients\<client-guid> Stockage persistant des clients enregistrés Johnson Source unique, clé illisible depuis un SYSTEM en PPL WinTcb (accès refusé)
Attribut de jeton WESP://Permission Valeurs 10000000 et 1000000000, la seconde exige AM-PPL Johnson Source unique

L’imphash identifie la table d’imports d’un build donné, pas le fichier : il changera avec les builds. Aucune source ne publie de hash de fichier, et aucune CVE n’est associée à WESP.

Ce qu’un défenseur peut voir aujourd’hui

Côté télémétrie, la seule source est le résumé de Mallory.ai, pour un seul build :

  • le fournisseur ETW noyau de WESP journalise les enregistrements de clients, mais cette collecte n’est pas activée par défaut ;
  • aucun canal Event Log ni autologger propre à WESP n’a été trouvé ;
  • ni l’événement Security 4703 ni l’événement Sysmon 25 n’ont enregistré l’ajout de l’attribut de jeton.

Si ces constats se confirment, l’enregistrement d’un client WESP passerait inaperçu avec une télémétrie Windows standard. C’est gênant pour une plateforme qui donne accès à la télémétrie noyau et qui se place devant Defender dans la pile de filtres.

Le même résumé évoque une faiblesse possible du stockage persistant des clients : il serait modifiable par un administrateur, et les clients enregistrés seraient restaurés au démarrage avec une confiance totale. Aucune exploitation n’est démontrée. Johnson constate d’ailleurs que la clé de registre reste illisible depuis un processus SYSTEM en PPL WinTcb. C’est une piste à surveiller, pas un fait établi.

Vérifier soi-même sur une VM Insider

Tout ce qui précède se contrôle avec des outils standards, sur une VM de labo isolée avec un build Insider qui livre WESP. Les commandes ci-dessous sont en lecture seule. Elles n’ont pas été exécutées pour cet article : ce sont les vérifications à faire, pas des résultats.

# Le mini-filtre est-il chargé, à quelle altitude, avec combien d'instances ?
fltmc filters
fltmc instances -f wesp

# Configuration du service (à comparer avec la capture d'Elastic)
reg query HKLM\SYSTEM\CurrentControlSet\Services\wesp
sc.exe qc wesp

# Empreintes des binaires, absentes de toutes les sources : à consigner avec le numéro de build
Get-FileHash C:\Windows\System32\drivers\wesp.sys, C:\Windows\System32\espclient.dll -Algorithm SHA256
[System.Environment]::OSVersion.Version

Pour aller plus loin : WinObj de Sysinternals pour retrouver \EspFilterPort, et un outil d’analyse PE (dumpbin /imports, PE-bear ou Total PE) pour vérifier les imports de espclient.dll, FilterReplyMessage en premier. Refaire l’exercice d’un build à l’autre : c’est la seule façon de voir le jour où la réponse du client apparaît.

Verdict par hypothèse

Hypothèse Verdict Confiance
Le client n’utilise pas FilterReplyMessage Observé dans les imports publiés par Elastic (source unique), n’exclut pas une réponse par un autre canal Moyenne
Le pilote dispose du mécanisme pour bloquer une création de processus Import de PsSetCreateProcessNotifyRoutineEx2 visible, usage réel non observé Haute pour le mécanisme
Blocage par règles précompilées dans le noyau, réservé à l’AM-PPL Compatible avec les sources, non démontrée Faible
Réponse du client simplement pas encore implémentée Hypothèse d’Elastic (« at least not yet »), non vérifiable aujourd’hui Faible
Accès réservé aux processus élevés, AM-PPL pour certaines permissions Élévation corroborée, exigence PPL finale incertaine Moyenne
Enregistrement des clients peu visible par défaut Rapportée par une source secondaire, sur un build Faible

La phrase « un client WESP en mode utilisateur ne peut pas bloquer la création d’un processus » ne se défend donc que pour le canal de réponse prévu par l’API de filtre, dans les builds examinés, et reste un indice plutôt qu’une preuve. La phrase « WESP ne permet pas de bloquer » ne se défend pas : le pilote en a les moyens, reste à savoir s’il les ouvrira aux clients, et à qui.

Ce que ça change pour un SOC

À ce stade, pas grand-chose en production, et c’est déjà une information. WESP n’existe que dans des builds Insider, n’est pas documenté et change d’un build à l’autre. Il ne faut pas bâtir de détection ni de durcissement sur ses capacités actuelles. Cette recommandation est déduite des sources, aucune ne la formule telle quelle.

Les éditeurs, eux, s’y préparent : Elastic écrit qu’Elastic Defend se prépare à prendre en charge WESP, et le dit dans un article qui rappelle que le calendrier de ses fonctionnalités reste à sa discrétion. Cinq points sont à suivre jusqu’à la disponibilité générale :

  • les mécanismes de décision réellement offerts aux clients : réponse au pilote, quel qu’en soit le canal, ou règles évaluées dans le noyau ;
  • des résultats de tests reproductibles, build par build, plutôt qu’une lecture des imports seule ;
  • l’exigence finale d’AM-PPL pour les permissions sensibles ;
  • la journalisation : activation par défaut du fournisseur ETW, canaux Event Log, visibilité des enregistrements de clients ;
  • l’inventaire : quels produits s’enregistrent comme clients WESP sur le parc, et avec quelles permissions.

Limites de cette synthèse

  • Builds preview : imports, exports, altitude, permissions et télémétrie peuvent changer avant la disponibilité générale. Le build analysé par Elastic n’est pas précisé.
  • Analyse statique : imports et exports disent ce qu’un binaire peut appeler, pas ce qu’il fait à l’exécution. Sur le blocage, le seul test en conditions réelles est celui d’Adrian, connu par un résumé.
  • Source unique pour une partie des faits d’Elastic : l’altitude 329500 et l’absence de FilterReplyMessage ne sont confirmées par aucune source indépendante, même si les captures et les sorties publiées les rendent vérifiables. La reprise de daily.dev ne compte pas comme une confirmation.
  • Tests d’Adrian : connus uniquement par un résumé automatique, l’article d’origine n’a pas pu être consulté.
  • Discours d’intention : la page Microsoft de la Windows Resiliency Initiative et la presse décrivent ce que WESP doit permettre (« enables Windows protection and security solutions to run outside the kernel »), pas ce qu’il fait réellement. L’annonce d’Elastic sur Elastic Defend est celle d’un éditeur concerné.

Chronologie

Date Événement Source
19 juillet 2024 Panne CrowdStrike, environ 8,5 millions de machines Windows touchées Elastic, Winaero
Novembre 2024 Annonce de la Windows Resiliency Initiative Jonathan Johnson
Juin 2025 Annonce d’un aperçu privé de WESP pour des partenaires SecurityWeek
9 septembre 2026 Yarden Shafir signale que le build preview 29661 livre wesp.sys cr3ghost sur X
24 octobre 2026 Mallory.ai publie son résumé des tests d’Adrian Mallory.ai
26 octobre 2026 Publication de l’analyse de Pavel Yosifovich chez Elastic Elastic

Conclusion

L’analyse d’Elastic est solide sur ce qu’elle montre : wesp.sys a dans ses imports de quoi refuser un processus, et espclient.dll n’utilise pas la fonction de réponse prévue pour ça. Sa conclusion a été reprise plus largement qu’elle ne le permet, et Elastic lui-même ajoute « pas encore ». Un EDR hors du noyau pourrait encore bloquer, par une réponse passant par un autre canal ou par des règles confiées à l’avance au noyau, sous réserve de tourner en AM-PPL. Les builds actuels ne permettent ni de le confirmer ni de l’exclure. Ce qu’il faudra regarder, build après build : quels mécanismes de décision WESP ouvre réellement aux clients, à quel niveau de protection, et si un test reproductible finit par montrer un processus bloqué.

Sources


Niveau de traitement : L2, analyse et recoupement de sources publiques (quatre analyses techniques indépendantes, de fiabilité inégale : Elastic, Jonathan Johnson et marcosd4h lus directement ; les tests d’Adrian’s Security Research connus uniquement par un résumé tiers). Aucune expérimentation propre.