Il y a traditionnellement deux façon pour les éditeurs anti-virus de détecter des codes malveillants. L’une via une analyse heuristique simple avec par exemple, le nom de l’exécutable et ses méta datas, puis l’autre via sa signature. Le principal défaut est qu’aujourd’hui, il est très facile pour un attaquant de modifier le nom de l’executable et sa signature, rendant l’analyse AV caduque.
Les éditeurs AV ont alors progressivement migrés leurs solutions vers de l’analyse dynamique. Seulement, pour le permettre, il faut leur octroyer des droits systèmes privilégiés. C’est alors qu’entre en jeu Microsoft et son architecture système Windows. Sur Windows, il y a 2 environnements isolés, l’un est le user space (fonctionnement des applications) et l’autre est le kernel space (fonctionnement de l’OS, des services et des pilotes).
Ainsi, les éditeurs ont développés des drivers pour entrer dans le kernel space et avoir accès à des informations types, liste des processus, etc. Des écrans de type BSOD sont apparu pour de nombreux utilisateurs de PC :
Le développement au niveau du kernel est très difficile et très sensible, la moindre erreur fait tomber le PC vers un écran bleu ou le ralenti fortement, et ceci à l’instar du user space.
Microsoft insatisfait que des éditeurs nuisent à la stabilité de son OS a donc développé dès Windows XP et 2003 PATCH GUARD (https://fr.wikipedia.org/wiki/Kernel_Patch_Protection). Cette protection permet d’éviter toute modification de structures critiques par d’autres services que le kernel. Son fonctionnement est simple :
Symantec ainsi bloqué par cette nouvelle fonctionnalité pour faire fonctionner son AV porte plainte. https://betanews.com/2007/02/28/symantec-vista-white-paper-links-to-patchguard-crack/
Microsoft a enfin compris la demande d’accès privilégié au kernel par les éditeurs AV et a développé le concept de Callback Objects. L’objectif c’est de permettre aux drivers d’obtenir des notifications sur les actions effectuées sur l’OS. Windows propose pour développer des drivers le WDF (Windows Driver Framework) qui lui comprend deux entités : KMDF (Kernel Mode Driver Framework) et UMDF (User Mode). Les éditeurs AV ont donc besoin du KMDF pour développer leur AV/EDR et accéder au kernel. La solution développée aura besoin du nom des processus créés, des DLL chargées et les arguments des fonctions utilisées et enfin des drivers pour accéder à la structure du kernel et modifier cette dernière.
Un driver KMDF possède la structure suivante :
Le kernel (NTOSKRNL) a pour but d’allouer de l’espace mémoire, créer un processus et l’exécuter. Avant cela, il va vérifier avant son exécution si un kernel callback est présent dans le but de monitorer sa création. Ex. : Demande de création d’un processus X.exe, puis notification au driver par l’intermédiaire du Callback Object, pour monitoring, et attente du retour du driver pour savoir s’il y aura exécution ou pas.
Pour cela, le driver doit intégrer les fonctions de kernel Callbacks proposées par l’OS. Par exemple, la fonction PsSetCreateProcessNotifyRoutine() pour monitorer la création de processus, une autre pour les threads, pour les DLL, l’accès aux ressources systèmes, aux clés de registre, etc. C’est donc un tableau de pointeurs stocké dans le kernel (PspCreateProcessNotifyRoutine) avec un nombre maximum de callbacks à 64.
La stratégie pour les éditeurs AV est alors de garder un driver au sein du kernel qui va enregistrer les callbacks et être notifié par le kernel puis un agent côté user space qui va encadrer la logique de détection. Les deux vont alors communiquer en permanence.
Ainsi, l’application dans le user space va appeler (ou pas d’ailleurs) Win32 API (kernel32.dll, etc.) puis interroge NTDLL.dll pour aller échanger vers le kernel space.
Rappelons que PatchGuard empêche de modifier le Kernel space, alors les éditeurs vont inventer une mécanisme de hooking de fonctions sur toutes les fonctions de la critiques de la NTDLL, afin de contrôler l’exécution.
L’EDR va alors injecter une DLL dans le processus côté user space afin d’agir comme un proxy.
Conclusion, le driver (côté kernel space) est interrogé par le NTOSKRNL qui ensuite interroge ses agents (côté user space) afin de prendre les corréler les informations et hooker les fonctions avec sa DLL, puis renvoyer son résultat au driver afin de prendre une décision sur la vie du processus vers NTOSKRNL.
Quick Links
Legal Stuff