

Windows divise son architecture en deux domaines de privilèges distincts : le Mode Noyau et le Mode Utilisateur.
En Mode Noyau, la couche Executive implémente les services principaux du système d’exploitation à travers des gestionnaires spécialisés :
- Le Gestionnaire de Processus gère la création, terminaison et planification des tâches
- Le Gestionnaire de Mémoire contrôle les espaces d’adressage virtuels et les opérations de pagination
- Le Gestionnaire E/S orchestre le flux de données entre les applications et le matériel en routant les Paquets de Requête E/S (IRP) à travers les piles de pilotes appropriées
- Le Gestionnaire d’Objets fournit un cadre unifié pour créer et gérer les ressources du noyau comme les mutex, événements et sémaphores via des tables de handles
- L’application de la sécurité incombe au Moniteur de Référence de Sécurité (SRM), qui valide les jetons d’accès contre les Listes de Contrôle d’Accès pour chaque opération sur ressource protégée
Sous l’Executive se trouve le Noyau lui-même, gérant la planification fondamentale du CPU, la distribution des interruptions et la synchronisation multiprocesseur en utilisant des primitives comme les spinlocks et objets dispatcher. La Couche d’Abstraction Matérielle (HAL) crée une interface cohérente vers diverses plateformes matérielles, isolant le noyau des détails spécifiques au processeur comme la gestion d’alimentation ACPI et les protocoles de communication multiprocesseur. Les Pilotes de Périphériques, bien qu’exécutés en Mode Noyau, sont des composants modulaires pouvant être chargés et déchargés dynamiquement pour contrôler les périphériques matériels ou fournir des services système.
En Mode Utilisateur, les applications s’exécutent avec des privilèges restreints, incapables d’accéder directement au matériel ou aux structures système critiques. Les Sous-systèmes d’Environnement fournissent des implémentations d’API que les applications utilisent pour demander des services système :
- Le sous-système Win32 sert d’interface primaire pour les applications Windows traditionnelles
- Les ajouts plus récents comme le Windows Subsystem for Linux (WSL2) permettent la compatibilité binaire Linux via la virtualisation légère
Les applications utilisateur n’interagissent jamais directement avec les composants du noyau ; elles invoquent plutôt des fonctions API documentées exposées par ces sous-systèmes. Ces appels sont traduits en requêtes de services système qui transitent du Mode Utilisateur vers le Mode Noyau à travers des points d’entrée soigneusement contrôlés. Par exemple, lorsqu’une application appelle CreateFile(), la requête passe par kernel32.dll et finalement ntdll.dll, qui exécute une transition supervisée vers le Mode Noyau où le service système NtCreateFile est effectué.
Architecture des Processus Windows


Ce diagramme illustre la structure interne et les composants qui constituent un processus Windows. Au centre se trouve la structure EPROCESS, qui agit comme la représentation du processus par le noyau. Elle fournit des informations sur l’identité du processus, l’espace mémoire, les threads, les handles, les jetons d’accès et les détails d’environnement.
Le Process ID sert d’identifiant unique attribué à chaque processus, permettant au système de suivre et gérer les processus individuellement. L’Espace d'Adressage Virtuel est le bac à sable mémoire alloué au processus, contenant des sections comme le code, les données, la pile et le tas. Cet espace est géré via des tables de pages, qui mappent les adresses virtuelles vers la mémoire physique.
Les Threads, représentés par des objets ETHREAD, sont les unités d’exécution au sein d’un processus. Chaque thread a un TEB (Thread Environment Block) associé, qui contient des informations en mode utilisateur telles que la pile et le stockage local au thread. Plusieurs threads peuvent appartenir au même processus, supportant le parallélisme.
Les Handles font référence aux ressources avec lesquelles le processus interagit, telles que les fichiers ouverts, clés de registre, mutex et sections de mémoire partagée. Ces handles lient le processus aux objets et ressources du noyau qu’il utilise durant l’exécution.
Le Jeton d'Accès contient le contexte de sécurité du processus, définissant les SID d’utilisateur et de groupe, les Privilèges spécifiques, et le Niveau d'Intégrité du processus. Ce jeton gouverne ce que le processus peut accéder et exécuter en fonction des politiques de sécurité du système.
Le PEB (Process Environment Block) est une structure en mode utilisateur contenant des métadonnées spécifiques au processus comme les variables d’environnement, arguments de ligne de commande, modules chargés (DLL) et tas mémoire. Il est crucial pour lier les fonctionnalités entre le noyau et les applications en mode utilisateur.
Enfin, l’image exécutable décrit le code et les données du programme chargés en mémoire pour exécution. Elle inclut les En-têtes PE (format Portable Executable) et les sections telles que le code compilé et les données initialisées.
Moteur de Gestion Processus/Thread


Le Moteur de Gestion Processus/Thread gouverne le cycle de vie et l’exécution des threads via un modèle piloté par états. Les threads transitent entre les états Prêt, En Cours, En Attente et Terminé. Un thread commence dans l’état Prêt, entre en Cours lorsque le planificateur le distribue à un cœur CPU, et peut revenir à Prêt s’il est préempté par un thread de priorité supérieure. Lorsqu’un thread émet une requête E/S, il passe à l’état En Attente jusqu’à ce que l’opération se termine. La terminaison se produit lorsqu’un thread se termine ou est forcé à s’arrêter, déclenchant le nettoyage des ressources.
Windows emploie un planificateur préemptif basé sur les priorités avec 32 niveaux de priorité (0–31). Les priorités sont divisées en deux catégories : priorité de base, attribuée statiquement via des API comme SetPriorityClass, et priorité dynamique, ajustée par le planificateur pour optimiser la réactivité (par ex., augmenter les threads liés aux E/S dans les applications en premier plan). Les tranches de temps d’exécution (quantum) sont configurables via les paramètres de registre sous HKLM\SYSTEM\CurrentControlSet\Control\PriorityControl, permettant un réglage fin pour des charges de travail spécifiques.
Les structures de données clés du noyau sous-tendent ce système. La structure KPROCESS stocke les métadonnées à l’échelle du processus, incluant les statistiques de mémoire virtuelle, tables de handles et contexte de sécurité. KTHREAD suit les détails spécifiques au thread tels que le Thread Environment Block (TEB), les états de registres CPU et les files d’attente Asynchronous Procedure Call (APC). Le Dispatcher Header gère la synchronisation en signalant les transitions d’état des threads (par ex., acquisition de mutex) entre états signalé et non-signalé.
Sous-système de Mémoire Virtuelle


Le Sous-système de Mémoire Virtuelle gère comment Windows alloue, mappe et optimise la mémoire à travers les espaces physique et virtuel. À son cœur, le Gestionnaire de Mémoire traduit les adresses virtuelles utilisées par les applications en adresses physiques via une structure de pagination à 4 niveaux (PML4 → Pointeur de Répertoire de Pages → Répertoire de Pages → Table de Pages). Cette hiérarchie prend en charge les tailles de pages de 4KB et 2MB, équilibrant granularité et efficacité pour diverses charges de travail.
L’Espace d’Adressage Virtuel d’un processus est partitionné en sections logiques (code, données, pile) et mappé aux Tables de Pages, qui suivent l’emplacement de chaque page en mémoire physique ou disque. L’Ensemble de Travail—un sous-ensemble de ces pages résidant activement en RAM—est géré par un algorithme d’horloge qui évince les pages les moins récemment utilisées pour libérer de l’espace. Les pages dans l’ensemble de travail sont catégorisées comme Valides (immédiatement accessibles) ou Transition (en cours de chargement ou d’écriture sur disque).
La Base de Données de Numéro de Cadre de Page (PFN) agit comme un index global de toutes les pages de mémoire physique, enregistrant leurs états (actif, standby, modifié ou libre). Lorsqu’un Défaut de Page se produit, le Gestionnaire de Mémoire détermine son type : un Défaut Dur nécessite de récupérer la page depuis le disque (pagefile.sys), tandis qu’un Défaut Doux implique de remapper une page déjà en mémoire physique (par ex., opérations copy-on-write).
Mécanique du Sous-système E/S


La Mécanique du Sous-système E/S dans Windows orchestre le flux complexe de données entre les applications et le matériel via une architecture par paquets en couches. Lorsqu’une application initie une opération E/S, le Gestionnaire E/S crée un Paquet de Requête E/S (IRP), une structure de données représentant l’opération tout au long de son cycle de vie. Cet IRP contient des champs essentiels : le code MajorFunction identifiant le type d’opération (tel que IRP_MJ_READ ou IRP_MJ_WRITE), les Paramètres spécifiques au périphérique et à l’opération (adresses de buffer, offsets, longueurs), et une adresse de callback Routine de Complétion pour notification asynchrone lorsque l’opération se termine.
Une fois créé, l’IRP traverse une pile de pilotes, chacun gérant une couche spécifique d’abstraction. Le Gestionnaire E/S route l’IRP vers le pilote de système de fichiers approprié, tel que NTFS, qui interprète les métadonnées de fichier via sa Table de Fichiers Maîtres (MFT) pour localiser l’emplacement de stockage physique. NTFS passe ensuite l’IRP traité aux pilotes de gestion de volumes comme VolMgr, qui traduisent les volumes logiques en partitions physiques. Enfin, l’IRP atteint les pilotes de port de stockage tels que Storport, qui communiquent avec des pilotes miniport spécifiques au matériel conçus pour des contrôleurs de stockage particuliers.
Au niveau matériel, les opérations de stockage modernes exploitent l’Accès Direct à la Mémoire (DMA) pour transférer des données entre la mémoire et les périphériques sans intervention du CPU. Le pilote de disque prépare des listes scatter/gather qui mappent des buffers mémoire potentiellement non contigus dans un format que le matériel peut traiter efficacement. Ce mappage permet au contrôleur de stockage de lire ou écrire directement dans la mémoire système, réduisant significativement la charge CPU lors des transferts de données.
Lorsque le matériel termine l’opération, il signale le système via une interruption. Cette interruption déclenche le pilote de disque pour traiter l’état de complétion et propager les résultats vers le haut de la pile de pilotes. Chaque pilote dans la chaîne peut effectuer un post-traitement avant de passer le contrôle vers le haut. Finalement, le Gestionnaire E/S reçoit l’IRP complété et soit notifie l’application directement (pour les appels synchrones) soit invoque la routine de complétion enregistrée (pour les opérations asynchrones).
Couche d’Application de la Sécurité


La Couche d’Application de la Sécurité dans Windows implémente un modèle de contrôle d’accès centré sur le Moniteur de Référence de Sécurité (SRM), un composant en mode noyau qui valide toutes les tentatives d’accès aux ressources. Lorsqu’une application ou un processus tente d’accéder à un objet sécurisé, le SRM évalue la requête en comparant le Jeton d’Accès du demandeur contre le Descripteur de Sécurité de l’objet. Ce jeton sert de contexte de sécurité du processus, contenant l’Identifiant de Sécurité (SID) de l’utilisateur, les appartenances aux groupes, et des Privilèges spécifiques tels que SeDebugPrivilege ou SeBackupPrivilege qui accordent des capacités spéciales au-delà des permissions standard.
Les Descripteurs de Sécurité attachés à chaque objet sécurisable contiennent deux listes de contrôle d’accès critiques. La Liste de Contrôle d’Accès Discrétionnaire (DACL) définit quels utilisateurs ou groupes peuvent accéder à l’objet et quelles opérations ils peuvent effectuer via des Entrées de Contrôle d’Accès (ACE). Chaque ACE spécifie un SID et les permissions autorisées ou refusées. La Liste de Contrôle d’Accès Système (SACL) active l’audit de sécurité en définissant quelles tentatives d’accès doivent générer des entrées dans le journal d’événements de sécurité, essentiel pour la surveillance de conformité et l’analyse forensique.
Windows étend ce modèle avec le Contrôle d’Intégrité Obligatoire, qui attribue des niveaux d’intégrité (Bas, Moyen, Haut, Système) aux processus et objets. Un processus ne peut pas modifier des objets avec des niveaux d’intégrité supérieurs indépendamment des permissions DACL, créant un système de protection hiérarchique. Cela empêche les processus moins privilégiés de falsifier des composants système plus sensibles. Pour une protection améliorée des données d’identification, Windows implémente Credential Guard, qui isole le Service de Sous-système d’Autorité de Sécurité Locale (LSASS) dans un environnement sécurisé virtualisé utilisant la technologie Hyper-V, empêchant les malwares d’extraire les jetons d’authentification et hashes même s’ils obtiennent un accès au niveau système (normalement)…
Exemple pratique
Warning
Toutes les actions suivantes sont effectuées dans un contexte de haute intégrité.
En utilisant WinDbg, nous pouvons interagir avec le noyau et modifier le Token d’un processus Windows :

Changeons par exemple le Token du processus cmd.exe. Nous devons d’abord récupérer son EPROCESS_ID :
!process 0 0 cmd.exe
Puis regarder l’offset actuel de la valeur Token :
dt nt!_eprocess <SYSTEM_EPROCESS> Token
Nous pouvons voir que son offset est 0x4b8 et son type est _EX_FAST_REF.
Récupérons l’adresse Eprocess du système depuis system :
!process 0 0 system
Et obtenons la valeur Token de system en ajoutant l’offset :
imagedt _EX_FAST_REF <SYSTEM_EPROCESS>+0x4b8
Remplaçons le token du processus CMD par celui du system :
eq <CMD_EPROCESS>+0x4b8 <SYSTEM_Token>Et vérifions le changement :
dt _EX_FAST_REF <CMD_EPROCESS>+0x4b8
Continuons l’exécution du noyau :

Moteur de Base de Données du Registre


Le Moteur de Base de Données du Registre sert de dépôt de configuration hiérarchique centralisé pour Windows, stockant les paramètres pour le système d’exploitation, les applications, les utilisateurs et le matériel. Il organise les données dans une structure arborescente avec des clés racines majeures incluant HKEY_LOCAL_MACHINE (HKLM), qui stocke les paramètres à l’échelle du système dans des ruches telles que SYSTEM (configurations de démarrage et pilotes), SOFTWARE (paramètres d’application), et HARDWARE (informations de périphériques détectés). Les paramètres spécifiques aux utilisateurs résident dans HKEY_USERS, organisés par Identifiant de Sécurité (SID), tandis que HKEY_CURRENT_CONFIG fournit une vue dans le profil matériel actuel, référençant principalement les paramètres système du jeu de contrôle CurrentControlSet.
Physiquement, le Registre est stocké sur plusieurs fichiers de ruche, chacun correspondant à une section majeure de la hiérarchie du Registre. Ces fichiers résident principalement dans %SystemRoot%\System32\Config et dans les répertoires de profils utilisateur. Les fichiers de ruche emploient une structure sophistiquée de type base de données avec support de transactions atomiques pour maintenir l’intégrité des données. Lorsque des modifications du Registre se produisent, les changements sont d’abord écrits dans des fichiers journaux de transactions (log1/log2) plutôt que directement dans la ruche, créant un système de journalisation. Cette approche protège contre la corruption lors de plantages système ou pannes de courant, car les modifications incomplètes restent dans les journaux jusqu’à ce qu’elles puissent être validées ou annulées en toute sécurité lors du prochain démarrage système.
Internement, le Registre utilise un modèle de stockage basé sur les cellules où les Cellules de Clés contiennent des métadonnées sur les clés du Registre, incluant les horodatages, descripteurs de sécurité et références aux sous-clés et valeurs. Pour optimiser les performances, le Registre implémente l’Optimisation Fast Leaf utilisant des structures de données d’arbre B+ qui permettent des recherches de clés efficaces avec une complexité O(log n). Cette indexation est cruciale pour l’accès rapide aux données du Registre, surtout dans les ruches contenant des milliers d’entrées, comme la ruche SOFTWARE sur une installation typique.
Pour les développeurs et les produits de sécurité, Windows fournit un mécanisme de Filtrage du Registre via les API CmRegisterCallback et CmRegisterCallbackEx. Ces fonctions permettent aux pilotes en mode noyau d’intercepter les opérations du Registre avant leur exécution, permettant la surveillance, modification ou blocage de l’accès au Registre. Cette capacité forme la fondation de nombreux produits antivirus, solutions de contrôle d’application et outils de surveillance système qui doivent protéger ou auditer les opérations sensibles du Registre.
Le Mécanisme de Récupération du Registre s’active au démarrage du système lorsque Windows détecte des ruches “sales”, celles qui n’ont pas été fermées proprement lors de la session précédente. Le système applique ou annule automatiquement les transactions en attente depuis les fichiers journaux pour restaurer la cohérence. En cas de corruption sévère, Windows peut également récupérer depuis les ruches de sauvegarde (fichiers *.bak) ou les points de restauration.
Primitives de Synchronisation du Noyau


Les Primitives de Synchronisation du Noyau dans Windows établissent un cadre hiérarchique de gestion des interruptions et de coordination des threads essentiel pour la stabilité et les performances du système. Au cœur de cette architecture se trouve le mécanisme IRQL (Interrupt Request Level), qui priorise l’exécution du code en fonction de l’urgence et de la criticité. Le diagramme illustre comment les IRQL forment une progression des niveaux inférieurs aux supérieurs, chaque transition représentant une priorité d’exécution croissante et un contexte d’exécution plus restrictif.
À PASSIVE_LEVEL (IRQL 0), la priorité la plus basse, le code en mode utilisateur et la plupart des opérations en mode noyau s’exécutent. Ce niveau permet les commutations de contexte de threads et les défauts de page, permettant aux opérations d’accès mémoire de se terminer de manière transparente. Lorsque le système doit délivrer des Appels de Procédure Asynchrones (APC) à un thread, il élève temporairement l’IRQL à APC_LEVEL (IRQL 1), empêchant d’autres APC d’interrompre pendant le traitement des APC actuels. Pour les opérations de planification et de traitement différé, le système s’élève à DISPATCH_LEVEL (IRQL 2), où le planificateur de threads s’exécute et les Appels de Procédure Différés (DPC) s’exécutent. À ce niveau, les commutations de contexte de threads et les défauts de page sont interdits, contraignant quelles opérations peuvent se produire en toute sécurité.
Les interruptions matérielles se produisent aux niveaux Device IRQL (DIRQL) au-dessus de DISPATCH_LEVEL, chaque périphérique se voyant attribuer un IRQL spécifique en fonction de sa priorité. Les cartes réseau, contrôleurs de disque et autres périphériques déclenchent des interruptions qui préemptent le code s’exécutant à des IRQL inférieurs. Au niveau le plus élevé, HIGH_LEVEL (IRQL 31), les interruptions critiques comme les Interruptions Non-Masquables (NMI) et les dépassements de Compteur de Surveillance de Performance s’exécutent, préemptant toutes les autres activités système.
Windows fournit des primitives de synchronisation spécialisées optimisées pour différents scénarios à travers ces niveaux IRQL. Les Spinlocks, acquis via des fonctions comme KeAcquireSpinLockAtDpcLevel, fournissent une protection d’accès exclusif dans les environnements multiprocesseur en interrogeant continuellement (spinning) jusqu’à ce que le verrou devienne disponible. Contrairement aux objets de synchronisation en attente, les spinlocks ne renoncent pas au temps CPU, les rendant adaptés pour des sections critiques brèves à DISPATCH_LEVEL ou au-dessus. Pour des modèles de synchronisation plus complexes, les Ressources Executive implémentent une sémantique lecteur-écrivain via ExAcquireResourceSharedLite et ExAcquireResourceExclusiveLite, permettant plusieurs lecteurs concurrents mais un accès exclusif pour les écrivains.