Présentation du noyau de Windows NT

Transcription

Présentation du noyau de Windows NT
Présentation du noyau
de Windows NT
Version 1.0
06 février 2014
Présentation du noyau de Windows NT
Figure 1 – Capture d’écran de Windows NT 3.51
1
Présentation
Windows NT est un système d’exploitation à destination des stations de travail et des serveurs. Son
développement a commencé en 1989 et la première version est sortie en 1993. C’est un système d’exploitation portable et qui existe selon les versions pour des plate-formes 32-bits et 64-bits (Intel x86,
PowerPC, MIPS, DEC Alpha, AMD64, Itanium et ARM). Il a été inspiré par DOS et Windows pour
l’interface utilisateur et par VMS pour certains composants du noyau.
Depuis sa sortie, 4 versions majeures de Windows NT se sont succédées :
— NT 3.x avec NT 3.1 (1993), NT 3.50 et NT 3.51 (1995) ; voir fig. 1.
— NT 4.0 (1996) et NT 4.0 Terminal Server (1998).
— NT 5.x avec Windows 2000 (NT 5.0, 2000), Windows XP (NT 5.1, 2001), Windows 2003 (NT 5.2,
2003).
— NT 6.x avec Windows Vista et Server 2008 (NT 6.0, 2007), Windows 7 et Server 2008R2 (NT 6.1,
2009), Windows 8 et Server 2012 (NT 6.2, 2012) et Windows 8.1 et Server 2012R2 (NT 6.3, 2013).
Jusqu’en 2002 avec l’arrivée de Windows XP, les systèmes Windows NT cohabitaient avec les systèmes
Windows “classiques” tels que Windows 98. Ces systèmes non-NT, bien que partageant la même interface
graphique et la même API pour les programmes, fonctionnent très différemment ; ils sont basés sur MSDOS, n’ont aucune notion de sécurité et sont peu fiables. Windows Millenium Edition sorti en 2000 a
été le dernier système de cette lignée, principalement destinée à une utilisation familiale.
2
2.1
Architecture générale
Vue d’ensemble
La figure 2 présente une vue générale de l’architecture de Windows 7 (NT 6.1). Sur ce schéma les
composants à fond gris font partie du système d’exploitation alors que les composants à fond blanc
proviennent de l’extérieur. Tous ces composants seront détaillés dans les sections suivantes. Les noms en
italique correspondent aux noms des fichiers qui contiennent le code relatif au composant.
2 / 17
Présentation du noyau de Windows NT
Applications Win32
Applis DOS
Applis POSIX
VDM
ntvdm.exe
advapi32.dll
kernel32.dll
psxdll.dll
user32.dll gdi32.dll
API native
ntdll.dll
Ring 3
Appel système (int 2Eh/sysenter/syscall)
Ring 0
Power man Plug’n’Play
I/O manager
Object manager
Cache
SRM (sécurité)
ALPC (com inter-proc)
Config man (registre)
Virtual memory man
Process manager
Executive
Driver 1
Syst de
fichiers
fastfat.sys
ntfs.sys
Driver 3
Driver 2
Driver 4
Kernel
ntoskrnl.exe
hal.dll
Couche d’abstraction matérielle (HAL)
Matériel
Figure 2 – Architecture de Windows NT 6.x
3 / 17
Sockets
afd.sys
TCP/IP
tcpip.sys
NDIS
USER
GDI
ndis.sys
win32k.sys
Drv réseau
Driver vidéo
Présentation du noyau de Windows NT
Préfixe
Composant
Description
Nt et Zw
Rtl
Runtime Library
Ex
Executive
Ke et Ki
Kernel
Io
Input / Output Manager
Se
Security Reference Monitor
Mm
Memory Manager
Cm
Configuration Manager
Cc
Cache Manager
Ob
Object Manager
Ps
Alpc
Process Manager
Advanced Local Procedure Call
Appels systèmes (fonctions de haut niveau)
Fonctions auxiliaires telles qu’une implémentation spécifique de la bibliothèque standard C
Fonctions de haut niveau agissant sur des structures du
système ou faisant appel à une couche inférieure
Fonctions du noyau bas niveau, souvent spécifiques au type
de processeur (gestion des interruptions, scheduler. . .)
Gestionnaire des entrées/sorties, gérant les lectures/écritures en communiquant avec les pilotes de périphériques
Gestionnaire de sécurité gérant les listes de contrôle d’accès, les jetons d’accès, vérifiant que l’accès à un objet est
autorisé et enregistrant les tentatives d’accès
Gestionnaire de mémoire virtuelle affectant des pages au
système et aux processus
Gestionnaire de la base de registre (base de donnée contenant de nombreux paramètres liés aussi bien au système ou
aux périphériques qu’aux applications)
À la frontière de Io et Mm, gère la mise en cache des fichiers
des disques
Gestionnaire d’objets gérant l’arborescence des objets (dont
les fichiers) et les handles
Gestionnaire des processus
Ports de communication inter-processus utilisés par le système
Table 1 – Principaux composants du noyau NT
Le fichier ntoskrnl.exe contient le noyau de Windows NT. On trouvera dans le tableau 1 la liste des
principaux composants du noyau avec leur description et le préfixe de nom de fonction correspondant.
Le fichier win32k.sys contient le “noyau graphique”, c’est-à-dire le gestionnaire de fenêtrage.
Dans le mode utilisateur, le fichier ntdll.dll est une librairie (DLL pour Dynamic Link Library)
qui contient tous les appels systèmes non graphiques ; l’ensemble de ces appels systèmes s’appelle l’API
native ; les rares programmes fonctionnant uniquement avec la librarie ntdll.dll sont dits natifs. Il
existe plusieurs sous-systèmes qui fonctionnent par-dessus ntdll :
— Le sous-système Win32 constitué de nombreuses DLL (kernel32.dll, user32.dll, gdi32.dll,
advapi32.dll en sont les principales) dont les fonctions constituent l’API Win32. Il permet
l’exécution des applications Windows, fenêtrées ou console. La VDM (Virtual Dos Machine),
uniquement présente dans les versions 32-bits de Windows, permet d’émuler une machine 16-bits
et d’exécuter des applications MS-DOS et Windows 16-bits.
— Le sous-système POSIX, non installé par défaut, offre une émulation des appels systèmes Unix
(librairie psxdll.dll) et permet d’utiliser des applications provenant du monde Unix en facilitant
leur portage pour Windows.
— Le sous-système OS/2, qui a disparu après Windows 2000, permettait d’exécuter des applications
en mode texte prévues pour IBM OS/2.
2.2
Segmentation et pagination
Les systèmes d’exploitation modernes utilisent des fonctionnalités offertes par les processeurs pour
assurer la fiabilité de l’ordinateur en empêchant les programmes de “faire n’importe quoi”. Nous nous
concentrerons sur les processeurs Intel x86. Dans ces processeurs, deux principaux mécanismes existent
et sont souvent utilisés conjointement :
— la segmentation, apparue avec la famille de processeurs 286 ;
— la pagination, ou “mémoire virtuelle”, apparue avec la famille 386.
4 / 17
Présentation du noyau de Windows NT
2.2.1
La segmentation, les niveaux de privilèges et les appels systèmes
À l’origine la segmentation était un mécanisme qui permettait de découper la mémoire vive en “segments” de taille variable et d’affecter ces segments aux différentes tâches (programmes) pour empêcher
une tâche d’accéder à la mémoire affectée à une autre tâche. Les systèmes modernes dont NT utilisent
plutôt la pagination pour cela. Par contre la segmentation reste utilisée pour ses niveaux de privilèges.
Un niveau de privilège, dans les processeurs x86, est une valeur nommée Ring comprise entre 0 et 3
affectée à chaque segment et indiquant quelles instructions le code s’exécutant dans ce segment aura le
droit d’effectuer. La plupart des systèmes comme NT ou Linux utilisent seulement deux niveaux (IBM
OS/2 en utilise 3). On a alors :
— Le Ring 0, aussi appelé mode noyau (kernel) ou superviseur (supervisor) est utilisé par le noyau
du système d’exploitation et les pilotes de périphériques. Un programme s’exécutant en ring 0
peut utiliser toutes les instructions fournies par le processeur.
— Le Ring 3, aussi appelé mode utilisateur (user) est utilisé pour exécuter les applications. Un
programme s’exécutant en ring 3 ne peut accéder à certains registres du processeur, ne peut
exécuter certaines instructions et ne peut accéder aux ports d’entrée/sortie.
Comme on peut le voir sur la figure 2, les applications fonctionnant en Ring 3 ne peuvent accéder au
matériel. Elles doivent donc faire appel au noyau du système pour toute opération impliquant le matériel
(lire un fichier, accéder au réseau, afficher quelque chose à l’écran. . .). Pour cela elles effectuent des appels
systèmes au moyen de l’interruption 0x2E, ou dans les systèmes plus modernes le couple d’instructions
sysenter/sysexit ou syscall/sysret. L’utilisation de ces instructions provoque l’exécution d’une fonction
du noyau appelée KiSystemService qui se chargera d’appeler la fonction demandée dans le noyau.
Il existe une liste faisant correspondre chaque appel système à un numéro, numéro qui est chargé dans
un registre avant l’appel. Sous Windows NT, les noms des appels systèmes commencent tous par le préfixe
Nt. Il existe dans Windows 7 environ 400 appels systèmes généralistes (par exemple NtReadFile pour
lire dans un fichier ou encore NtQuerySystemInformation pour demander des informations sur l’état du
système) et environ 800 appels systèmes relatifs à l’interface graphique (comme NtUserCreateWindowEx
pour créer une fenêtre ou NtGdiLineTo pour tracer une ligne droite à l’écran ou sur une imprimante).
En effet sous Windows toute la gestion de l’interface graphique (système de fenêtrage) a lieu en mode
noyau.
Si on observe la liste des fonctions appelées lors de la lecture d’un fichier par le programme cmd
(figure 3), on observe que la fonction ReadFile de KernelBase.dll utilise l’appel système NtReadFile
et que l’on passe du mode utilisateur (icône U bleue) au mode noyau (icône K rose).
2.2.2
La pagination
Dans cette section, on se concentrera sur les processeurs x86 ; les principes présentés restent valables
pour les processeurs AMD64, seules les valeurs diffèrent.
La pagination, ou mémoire virtuelle, permet de faire abstraction de la mémoire vive réelle et de
présenter à chaque processus un espace d’adressage de 4 Go. Chaque processus “croit” être le seul à
s’exécuter ; dans ses 4 Go de mémoire virtuelle, il ne voit que ses données et son code. Le processeur se
charge automatiquement de traduire les adresses mémoire virtuelles en adresses physiques.
Sous Windows, les 4 Go sont coupés en deux. Les deux giga-octets inférieurs (adresses de 0x0 à
0x7FFFFFFF) sont spécifiques au processus et librement accessibles par lui et le noyau. Les deux gigaoctets supérieurs (adresses de 0x80000000 à 0xFFFFFFFF) pointent vers les mêmes données quelque-soit
le processus ; ils s’agit de données uniquement accessibles depuis le mode noyau et contenant tout le code
et les données du noyau et des drivers.
Les deux giga-octets réservés au noyau et aux drivers sont composés entre autres de deux zones dans
lesquelles il est possible d’allouer de la mémoire :
— le paged pool est une zone dont certaines pages peuvent être déchargées de la mémoire (stockées
dans le fichier swap) ; cette zone est donc à privilégier si possible ;
— le nonpaged pool dont les pages restent toujours résidentes en mémoire ; à utiliser si on doit accéder
aux données à un IRQL élevé (voir plus bas).
5 / 17
Présentation du noyau de Windows NT
Figure 3 – Pile des appels de fonctions lors d’une lecture de fichier
3
Gestionnaire d’objets
Dans Windows NT, les objets sont des structures du système qui, pour la plupart, ont un nom et
sont placés dans une arborescence. Ils sont alors accessibles par des fonctions spécialisées (selon le type
de l’objet) pour effectuer des opérations avec. Lorsqu’un objet a un nom, il possède la plupart du temps
aussi une liste de contrôle d’accès, de manière à restreindre ce que chaque utilisateur du système peut
faire avec cet objet.
Il existe une quarantaine de types d’objet dans Windows 7. Parmi eux on trouve :
— des objets utilisés pour la synchronisation et communication inter-processus comme : l’évènement
(event), le mutex (mutant), le sémaphore (semaphore), le timer, le port ALPC ou la section
de mémoire partagée ;
— le fichier (file) qui peut être un fichier réel sur un disque ou bien un fichier virtuel comme un
canal nommé (pipe) ;
— le périphérique (device) qui représente un périphérique physique ou virtuel ;
— le pilote (driver) qui représente un pilote de périphérique ;
— le jeton (token) qui représente l’identité d’un utilisateur, utilisé pour les contrôles d’accès ;
— le processus (process), la thread et le job ;
— la clef de registre (key), c’est-à-dire un “dossier” dans la base de registre ;
— des objets utilisés par le gestionnaire de fenêtrage : la WindowStation et le bureau (desktop).
L’arborescence est quasiment la même d’un système à l’autre. On trouve entre autres les dossiers
suivants :
6 / 17
Présentation du noyau de Windows NT
— \BaseNamedObjects contient tous les objets de synchronisation
(évènements, mutex, sémaphores, etc.) des processus utilisateurs ;
— \Device contient tous les périphériques. On trouve par exemple
\Device\HarddiskVolume1 représentant la première partition
du disque-dur, \Device\Afd représentant les sockets, etc. On
trouve aussi de nombreux périphériques avec un nom hexadécimal
comme \Device\0000006a ; ils correspondent aux périphériques
Plug&Play ;
— \Driver contient la liste des drivers chargés en mémoire ;
— \GLOBAL?? aussi appelé \?? ou encore \DosDevices contient
des liens symboliques vers les périphériques du dossier
\Device. Par exemple \??\C: pointe sur mon PC vers
\Device\HarddiskVolume2 (il s’agit du C:\ habituel utilisé par
les applications). On trouve aussi par exemple \??\DISPLAY1 qui
pointe vers \Device\Video0 ou encore \??\LPT1 qui pointe vers
\Device\Parallel0. Les éléments présents dans ce dossier sont
accessibles depuis le mode utilisateur, ce qui n’est pas le cas pour
le dossier \Device ;
— \Sessions contient un sous-dossier par session ouverte sur
le poste, qui contient une instance privée des dossiers
\BaseNamedObjects et \??.
Certains objets possèdent un état pouvant être signalé ou non signalé. La signification de l’état signalé dépend du type d’objet. Par exemple, un processus est signalé lorsqu’il est terminé ; un évènement
est signalé lorsqu’une thread l’a activé ; un timer est signalé lorsqu’il arrive à expiration. Les appels
systèmes NtWaitForSingleObject et NtWaitForMultipleObjects permettent de mettre en pause une
thread tant que le ou les objets passés en paramètres ne sont pas dans l’état signalé ; c’est ainsi que
fonctionne la programmation évènementielle sous Windows NT.
Sous Windows les lecteurs sont la plupart du temps identifiés par une lettre (on appelle cela le nom
DOS car cette notation provient du système DOS). Avant d’utiliser un appel système, il faut convertir
le nom DOS en nom NT ; c’est la couche Win32 (kernel32.dll) qui s’en occupe. Par exemple le nom
C:\Windows\explorer.exe sera converti en \??\C:\Windows\explorer.exe avant d’être transmis au
noyau. Le lien symbolique \??\C: sera ensuite remplacé par \Device\HarddiskVolume2 et le chemin
sera alors \Device\HarddiskVolume2\Windows\explorer.exe.
Un principe veut que tout objet reste existant tant qu’il est au moins ouvert une fois. Chaque objet
possède un compteur de nombre de références qui est incrémenté à son ouverture et décrémenté à sa
fermeture ; lorsque ce compteur atteint zéro, l’objet est détruit. Imaginons qu’un processus A crée un
évènement E (avec NtCreateEvent) ; le compteur de référence vaut 1. Le processus B ouvre lui aussi E
(avec NtOpenEvent) ; le compteur vaut 2. Le processus A ferme E (avec NtClose) ; le compteur vaut 1.
Le processus B ferme à son tour E ; le compteur vaut 0 et E est détruit. Ainsi le seul moyen de détruire
un objet est que toutes ses références soient fermées.
4
Kernel
Le kernel est la couche la plus bas-niveau du noyau. Il gère le démarrage de Windows, les commutations de contexte, la gestion des interruptions et des exceptions ainsi que des objets de synchronisation.
Contrairement au reste du noyau qui est exclusivement programmé en C, une partie du kernel est écrite
en assembleur ; de nombreuses fonctions du kernel sont en effet dépendantes du type de processeur.
7 / 17
Présentation du noyau de Windows NT
Valeur x86
Valeur AMD64
Nom
Description
31
15
HIGH_LEVEL
28
3 – 26
2
13
3 – 11
2
CLOCK_LEVEL
(DIRQL)
DISPATCH_LEVEL
1
1
APC_LEVEL
0
0
PASSIVE_LEVEL
Niveau le plus haut. Toutes les interruptions sont
masquées (normalement jamais utilisé)
Interruption d’horloge
Interruptions matérielles
C’est à ce niveau que s’exécutent les DPC (Deferred
Procedure Calls)
C’est à ce niveau que s’exécutent les APC (Asynchronous Procedure Calls)
C’est à ce niveau que s’exécutent les threads en mode
utilisateur et la plupart des threads en mode noyau
Table 2 – Valeurs d’IRQL
4.1
Interruptions, DPC, APC et IRQL
L’IRQL (Interrupt ReQuest Level) est une valeur (entre 0 et 31 pour les processeurs x86 et entre 0
et 15 pour les processeurs AMD64) que possède chaque processeur à un instant donné. Selon le type
de code exécuté par le processeur un IRQL plus ou moins élevé est assigné au processeur. La règle
est qu’une tâche ne peut interrompre une autre tâche s’exécutant à un IRQL plus élevé. Le tableau 2
présente certains niveaux IRQL. Les threads s’exécutent au niveau PASSIVE_LEVEL ; elles peuvent être
interrompues par une interruption matérielle (clavier, etc.), par le scheduler ou par un APC. Un APC
(Asynchronous Procedure Call) est une procédure initiée par le noyau qui s’exécute en interrompant une
thread ; lorsqu’un APC s’exécute, l’IRQL est élevé à APC_LEVEL. Lorsque l’IRQL est supérieur ou égal à
DISPATCH_LEVEL, le scheduler ne fonctionne plus ; il ne peut donc plus y avoir de commution de tâche.
Lorsqu’une interruption en provenance de l’horloge a lieu, le système exécute la routine KeUpdateSystemTime,
qui met à jour la date et l’heure, vérifie si un timer a expiré et décrémente le quantum de la thread actuelle.
Lorsqu’une interruption matérielle a lieu, l’IRQL est élevé à la valeur attribuée à cette interruption
puis le contrôle est passé au driver responsable du traitement de cette interruption (pilote du clavier,
de la souris, etc.). La routine de traitement de l’interruption s’appelle ISR (Interrupt Service Routine).
Pendant que cette routine s’exécute, l’IRQL est très élevé ; d’autres interruption d’IRQL inférieur ne
peuvent donc pas l’interrompre. Le temps passé dans une ISR doit donc être le plus court possible. Pour
pallier cet inconvénient il existe les DPC (Deferred Procedure Calls) : ce sont des routines qui s’exécutent
à l’IRQL DISPATCH_LEVEL, ce qui permet à d’autres interruptions d’être traitées.
Typiquement lorsqu’une interruption survient, l’ISR est exécutée : elle fait le minimum nécessaire et
met un DPC en file d’attente. L’IRQL redescent et le DPC est exécuté : il finit alors plus tranquilement
le travail commencé par l’ISR. Les recommandations de Microsoft sont qu’un ISR ne devrait pas durer
plus de 25 micro-secondes et qu’un DPC ne devrait pas durer plus de 100 micro-secondes.
4.2
Les exceptions, fautes de pages et bugchecks
Lorsqu’une opération invalide est effectuée (division par zéro, accès à une page non présente en
mémoire, exécution d’une instruction invalide, etc.) le processeur déclenche une exception (voir tableau 3),
c’est-à-dire un type d’interruption. C’est le kernel qui se charge de traiter les exceptions. Si une thread
en mode utilisateur provoque une exception, deux cas de figure peuvent se produire :
— si la thread a enregistré une routine SEH (Structured Exception Handling), ce qui est accessible en
C par la structure __try / __except, le noyau redonne la main à la thread en lui faisant exécuter
sa routine d’exception ;
— sinon le processus fautif est terminé et un message indique que le programme a généré une exception et a été terminé.
Si le code qui génère l’exception se situe en mode noyau, le principe est le même. Par contre si
l’exception n’est pas gérée, le kernel provoque l’arrêt du système en affichant un bugcheck (voir figure 4)
aussi appelé BSOD (Blue Screen Of Death). Le BSOD contient un code et 4 paramètres ; à chaque code
est associé un alias comme KMODE_EXCEPTION_NOT_HANDLED par exemple. Il existe environ 300 codes
d’erreurs. Le tableau 4 présente les codes d’erreurs les plus courants. L’immense majorité des BSOD
8 / 17
Présentation du noyau de Windows NT
Numéro
Nom
Description
0
3
6
8
#DE
#BP
#UD
#DF
11
12
13
#NP
#SS
#GP
14
#PF
Division par zéro
Breakpoint (exécution de l’instruction INT3)
Opcode invalide (exécution d’une instruction inexistante)
Double faute (exception pendant la gestion d’une première exception)
Faute de segmentation (erreur liée aux registres de segments)
Faute de pile (débordement de la pile par exemple)
Faute de protection générale (toutes les fautes qui ne génèrent pas
une autre exception)
Faute de page (tentative d’accès à une page non présente en mémoire)
Table 3 – Exceptions les plus courantes
sont dus à des drivers mal programmés ou à des erreurs matérielles et non à une prétendue instabilité
de Windows.
Un cas particulier d’exception est la faute de page. Windows NT peut utiliser un fichier swap sur le
disque-dur pour étendre la mémoire disponible au système. Si une thread accède à une page mémoire
qui n’est pas présente en mémoire physique, le processeur déclenche une exception. Le kernel se rend
compte qu’il s’agit d’une page qui est dans le fichier swap ; elle recharge alors cette page en mémoire et
redonne le contrôle à la thread qui a déclenché l’exception. À noter que le kernel ne peut pas gérer une
faute de page lorsque l’IRQL est supérieur ou égal à DISPATCH_LEVEL ; ceci est à l’origine de nombreux
bugchecks de type IRQL_NOT_LESS_OR_EQUAL qui peuvent survenir à cause de drivers mal programmés
qui tentent d’accéder à une adresse mémoire invalide.
5
Sécurité
Le modèle de sécurité de Windows NT repose sur deux éléments, permettant de contrôler ce que tel
ou tel utilisateur (et donc tel ou tel processus) peut ou ne peut pas faire :
— les privilèges ;
— les listes de contrôle d’accès (ACL)
5.1
Les privilèges
Un privilège est une autorisation pour utiliser certaines fonctions du système. Il existe 35 privilèges
sous Windows 7. Le tableau 5 présente les plus importants. L’administrateur de l’ordinateur ou du
domaine choisit quels privilèges attribuer à quels utilisateurs (à l’aide du composant Stratégie de sécurité
locale, secpol.msc ou du contrôleur de domaine). Par exemple un utilisateur qui possède le privilège
SeSystemtimePrivilege pourra modifier la date et l’heure de l’ordinateur alors que la même opération
échouera pour un utilisateur n’ayant pas ce privilège.
5.2
Les listes de contrôle d’accès
Un SID (Security IDentifier) est un identifiant commençant par S-1- et suivi de plusieurs groupes
de nombres. Un SID peut représenter un utilisateur (réel ou virtuel), un groupe d’utilisateurs ou un
ordinateur. Certains SID sont identiques d’un ordinateur à l’autre (par exemple S-1-1-0 représente
le groupe virtuel Tout le monde qui, comme son nom l’indique, désigne n’importe quel utilisateur),
d’autres sont uniques (par exemple S-1-5-21-1430825754-3039618593-2372326455-1000 représente
mon compte utilisateur sur mon PC).
Une liste de contrôle d’accès (ACL) est composée de deux parties :
— Une liste de contrôle d’accès discrétionnaire (DACL) : il s’agit d’une liste associant des SID
à des opérations (par exemple lecture, écriture, exécution, lecture des attributs, etc. pour un
fichier ; démarrage, arrêt, modification de la configuration, etc. pour un service) auquel le SID
aura explicitement accès ou pas accès ;
9 / 17
Présentation du noyau de Windows NT
Figure 4 – BugCheck (BSOD) dû à un driver mal programmé
Code
Alias
Description
0x0A
0x1A
IRQL_NOT_LESS_OR_EQUAL
MEMORY_MANAGEMENT
0x1E
KMODE_EXCEPTION_NOT_HANDLED
0x50
0x7B
PAGE_FAULT_IN_NONPAGED_AREA
INACCESSIBLE_BOOT_DEVICE
0x7F
UNEXPECTED_KERNEL_MODE_TRAP
0x8E
0x9F
KERNEL_MODE_EXCEPTION_NOT_HANDLED
DRIVER_POWER_STATE_FAILURE
0xD1
0xEA
DRIVER_IRQL_NOT_LESS_OR_EQUAL
THREAD_STUCK_IN_DEVICE_DRIVER
0xC000021A
STATUS_SYSTEM_PROCESS_TERMINATED
0xDEADDEAD
MANUALLY_INITIATED_CRASH1
Faute de page à un IRQL ≥ DISPATCH_LEVEL
Grave erreur liée à la mémoire (souvent problème
matériel)
Exception non gérée. Le paramètre 1 indique le code
de l’exception (0xC0000005 indique par exemple une
violation d’accès à la mémoire)
Tentative d’accès à une adresse mémoire invalide
Impossible de trouver la partition système lors du
démarrage
Exception non gérée. Le paramètre 1 indique le numéro de l’exception (voir tableau 3)
Équivalent à KMODE_EXCEPTION_NOT_HANDLED
Un driver n’a pas traité correctement une demande
d’arrêt ou de mise en veille
Équivalent à IRQL_NOT_LESS_OR_EQUAL
Une routine dans un driver a duré trop longtemps
(souvent le driver de la carte graphique)
Un processus ou une thread critique (WinLogon /
CSRSS) a été terminée
BugCheck déclenché volontairement pour faire un vidage de la mémoire
Table 4 – BugChecks les plus courants
10 / 17
Présentation du noyau de Windows NT
Nom du privilège
Description
SeAssignPrimaryTokenPrivilege
SeBackupPrivilege
SeCreateTokenPrivilege
SeDebugPrivilege
SeIncreaseBasePriorityPrivilege
SeIncreaseQuotaPrivilege
SeLoadDriverPrivilege
SeRestorePrivilege
SeShutdownPrivilege
SeSystemtimePrivilege
SeTakeOwnershipPrivilege
SeTcbPrivilege
SeTimeZonePrivilege
Assigner un jeton d’accès à un processus
Accéder à tous les fichiers en lecture même sans en avoir l’autorisation
Créer un jeton d’accès
Déboguer n’importe quel processus et le noyau
Augmenter la priorité d’exécution d’un processus ou d’une thread
Ajuster les quotas d’un processus ou du registre
Charger (ou décharger) un driver en mémoire
Accéder à tous les fichiers en écriture même sans en avoir l’autorisation
Éteindre ou redémarrer l’ordinateur
Modifier la date et l’heure
Prendre possession de n’importe quel objet (fichier ou dossier par
exemple)
Effectuer des opérations très particulières normalement réservées
au système
Modifier le fuseau horaire de l’ordinateur
Table 5 – Quelques privilèges de Windows 7
— Une liste de contrôle d’accès système (SACL) : il s’agit essentiellement d’une liste associant des
SID à des opérations (les mêmes que ci-dessus) qui déclencheront un enregistrement dans le journal
des audits.
Presque tous les objets du noyau (fichier ou dossier sur une partition NTFS, clef de registre, évènement, mutex, processus, thread, bureau, etc.) possédant un nom (ainsi que d’autres éléments comme les
services ou les imprimantes) possèdent une ACL associée, réglementant ainsi leur accès. Un fichier peut
optionnellement hériter des entrées ACL de son dossier parent.
Lorsque l’ACL d’un objet est vide, personne (même le ou les administrateurs) ne peut accéder à
l’objet. Il existe deux types d’entrées : celles autorisant l’accès à l’objet et celles refusant l’accès. Les
entrées de refus sont prioritaires sur celles d’autorisation.
Une ACL peut être modifiée par le propriétaire de l’objet ou toute personne justement autorisée
par une entrée à cet effet dans cette ACL. Soulignons donc que quelqu’un qui possède le privilège
SeTakeOwnershipPrivilege (normalement seulement l’administrateur) peut prendre possession de n’importe quel objet, puis ensuite éditer l’ACL pour se donner tous les droits sur cet objet.
La figure 5 montre l’exemple d’une ACL pour un fichier nommé C:\Users\_\test. Si on analyse la
sortie de la commande, on observe que :
— Ce fichier hérite des DACL et SACL du dossier parent.
— Le propriétaire du fichier est l’utilisateur _ de l’ordinateur IBMT61.
— La SACL contient 2 entrées (ACE pour Access Control Entry) d’audit spécifiques à ce fichier :
toute tentative d’écriture dans le fichier sans en avoir accès sera consignée dans le journal des
audits et toute tentative de lecture, autorisée ou non, sera aussi consignée.
— La DACL contient 2 ACE spécifiques à ce fichier : personne n’aura le droit d’exécuter le fichier
et l’utilisateur NETUSR aura le droit de lire et d’ajouter des données (append) au fichier.
— La DACL contient 3 ACE héritées du dossier C:\Users\_ : l’utilisateur virtuel Système (représentant les processus du système ayant le plus de droits), le groupe des administrateurs ainsi que
l’utilisateur _ ont un droit d’accès total (sauf exécution puisque refusé par une autre ACE).
Les ACL sont présentes partout dans le système et permettent un contrôle très fin de l’accès aux objets.
Mais ce sont des structures complexes et les fonctions permettant de les manipuler ne sont pas faciles
à utiliser. C’est pourquoi Windows 2000 a introduit une notation sous forme de chaîne permettant de
représenter de manière plus simple les ACL. Cette notation est appelée SDDL (pour Security Descriptor
Definition Language). Pour exemple l’ACL représentée figure 5 donne en SDDL (des sauts de lignes ont
été ajoutés pour faciliter la lecture ; la première ligne représente le propriétaire, la troisième la DACL et
la dernière la SACL ; chaque paire de parenthèses représente une ACE) :
11 / 17
Présentation du noyau de Windows NT
======================
+File C:\Users\_\test
======================
/control=0xc00 SE_DACL_AUTO_INHERITED-0x0400 SE_SACL_AUTO_INHERITED-0x0800
/owner
=ibmt61\_
/primary group
=ibmt61\none
/audit ace count
=2
/aace =tout le monde
SYSTEM_AUDIT_ACE_TYPE-0x2
SUCCESSFUL_ACCESS_ACE_FLAG-0x40
Type of access:
Special acccess :
Detailed Access Flags :
FILE_WRITE_DATA-0x2
/aace =tout le monde
SYSTEM_AUDIT_ACE_TYPE-0x2
FAILED_ACCESS_ACE_FLAG-0x80
SUCCESSFUL_ACCESS_ACE_FLAG-0x40FAILED_ACCESS_ACE_FLAG-0x0x80
Type of access:
Special acccess :
Detailed Access Flags :
FILE_READ_DATA-0x1
/perm. ace count
=5
/pace =tout le monde
ACCESS_DENIED_ACE_TYPE-0x1
Type of access:
Special acccess :
Detailed Access Flags :
FILE_EXECUTE-0x20
/pace =ibmt61\netusr
ACCESS_ALLOWED_ACE_TYPE-0x0
Type of access:
Special acccess : -Read
Detailed Access Flags :
FILE_READ_DATA-0x1
FILE_APPEND_DATA-0x4
FILE_READ_EA-0x8
FILE_READ_ATTRIBUTES-0x80
READ_CONTROL-0x20000
SYNCHRONIZE-0x100000
/pace =système ACCESS_ALLOWED_ACE_TYPE-0x0
INHERITED_ACE-0x10
Type of access:
Full Control
Detailed Access Flags :
FILE_READ_DATA-0x1
FILE_WRITE_DATA-0x2
FILE_APPEND_DATA-0x4
FILE_READ_EA-0x8
FILE_WRITE_EA-0x10
FILE_EXECUTE-0x20
FILE_DELETE_CHILD-0x40
FILE_READ_ATTRIBUTES-0x80
FILE_WRITE_ATTRIBUTES-0x100 DELETE-0x10000
READ_CONTROL-0x20000
WRITE_DAC-0x40000
WRITE_OWNER-0x80000
SYNCHRONIZE-0x100000
/pace =builtin\administrateurs ACCESS_ALLOWED_ACE_TYPE-0x0
INHERITED_ACE-0x10
Type of access:
Full Control
Detailed Access Flags :
FILE_READ_DATA-0x1
FILE_WRITE_DATA-0x2
FILE_APPEND_DATA-0x4
FILE_READ_EA-0x8
FILE_WRITE_EA-0x10
FILE_EXECUTE-0x20
FILE_DELETE_CHILD-0x40
FILE_READ_ATTRIBUTES-0x80
FILE_WRITE_ATTRIBUTES-0x100 DELETE-0x10000
READ_CONTROL-0x20000
WRITE_DAC-0x40000
WRITE_OWNER-0x80000
SYNCHRONIZE-0x100000
/pace =ibmt61\_
ACCESS_ALLOWED_ACE_TYPE-0x0
INHERITED_ACE-0x10
Type of access:
Full Control
Detailed Access Flags :
FILE_READ_DATA-0x1
FILE_WRITE_DATA-0x2
FILE_APPEND_DATA-0x4
FILE_READ_EA-0x8
FILE_WRITE_EA-0x10
FILE_EXECUTE-0x20
FILE_DELETE_CHILD-0x40
FILE_READ_ATTRIBUTES-0x80
FILE_WRITE_ATTRIBUTES-0x100 DELETE-0x10000
READ_CONTROL-0x20000
WRITE_DAC-0x40000
WRITE_OWNER-0x80000
SYNCHRONIZE-0x100000
Figure 5 – Exemple d’ACL d’un fichier
12 / 17
Présentation du noyau de Windows NT
O:S-1-5-21-1430825754-3039618593-2372326455-1000
G:S-1-5-21-1430825754-3039618593-2372326455-513
D:ARAI(D;;WP;;;WD)(A;;0x12008d;;;S-1-5-21-1430825754-3039618593-2372326455-1004)
(A;ID;FA;;;SY)(A;ID;FA;;;BA)(A;ID;FA;;;S-1-5-21-1430825754-3039618593-2372326455-1000)
S:ARAI(AU;SA;DC;;;WD)(AU;SAFA;CC;;;WD)
Le contrôle d’accès est effectué par le noyau à l’ouverture de l’objet. Par exemple pour ouvrir un
fichier en écriture on utilise l’appel système NtCreateFile avec l’accès désiré FILE_WRITE_DATA. Si
l’accès est refusé la fonction échoue, sinon elle renvoie un handle qui pourra être utilisé avec l’appel
système NtWriteFile pour écrire dans le fichier.
5.3
Jeton d’accès
Un jeton d’accès (access token) est un objet attribué à chaque processus. Il comprend une liste de
privilèges que le processus est autorisé à utiliser ainsi qu’une liste de SID qui serviront lors des contrôles
d’accès.
À l’ouverture d’une session, le processus lsass.exe (Local Security Authority Subsystem Service) crée
un jeton d’accès correspondant à l’utilisateur qui ouvre la session, puis l’affecte au premier processus de
l’utilisateur. Les processus enfants hériteront de ce jeton d’accès. Une fois créé il sera possible de créer
une version plus restreinte du jeton en enlevant des privilèges et en désactivant des SID. Par contre pour
une question de sécurité il est impossible de rajouter des privilèges.
À partir de Windows Vista et pour les comptes utilisateurs privilégiés, si le mécanisme UAC (User
Account Control) est activé, chaque processus possède deux jetons liés : un jeton avec le moins de
privilèges possibles et ne comprenant pas le SID du groupe des adminstrateurs par exemple, pour les
applications normales et un jeton avec tous les privilèges et SID pour les programmes administratifs.
Souvent les privilèges présents dans les jetons sont désactivés. Pour en faire usage, le programme doit
d’abord les activer. Cela permet de minimiser les dégâts que pourrait faire du shellcode si une faille est
découverte dans une application.
6
Processus, threads et jobs
6.1
Processus et threads
Sous Windows NT, processus et threads sont deux objets bien distincts.
Un processus contient principalement :
— un PID (Process IDentifier) : numéro identifiant le processus, multiple de 4 ;
— un working set, c’est-à-dire toute la mémoire occupée par le processus : il s’agit de code exécutable
et de données (tas (heaps) ou pages directement réservées) ;
— un ou plusieurs threads ;
— une table de handles, c’est-à-dire des descripteurs pointant vers les objets ouverts par le processus ;
— un jeton d’accès (access token) pour le contrôle d’accès ;
— un ensemble de variables d’environnement héritées du processus parent ;
— une classe de priorité d’exécution et une classe de priorité d’entrées/sorties ;
— une ACL comme tout objet.
Un processus est représenté dans le système par les structures EPROCESS (Executive Process) et
KPROCESS (Kernel Process) dans le noyau et par une structure PEB (Process Environment Block) en
mode utilisateur.
Une thread contient principalement :
— un TID (Thread IDentifier), similaire au PID ;
— un contexte processeur, c’est-à-dire l’ensemble des registres du processeur à un instant donné et
en particulier le pointeur d’instruction (EIP/RIP) ;
— une pile (stack) ;
— une classe de priorité d’exécution et une classe de priorité d’entrées/sorties ;
— un compteur indiquant si la thread est suspendue ;
— une ACL comme tout objet ;
13 / 17
Présentation du noyau de Windows NT
— parfois aussi un jeton d’accès (lors des opérations d’impersonation : un serveur peut emprunter
l’identité d’un client et ainsi restreindre ses droits à ceux du client).
Une thread est représentée dans le système par les structures ETHREAD (Executive Thread) et KTHREAD
(Kernel Thread) dans le noyau et par une structure TEB (Thread Environment Block) en mode utilisateur.
Autrement dit la thread est l’unité d’exécution de base (il existe aussi les fibers qui sont une sorte de
thread contrôlés en mode utilisateur mais c’est relativement rare) dont la création et la destruction est
rapide tandis que le processus contient tout le code et la mémoire de l’application et est relativement
long à créer et détruire. Toute thread fait forcément partie d’un processus et inversement un processus
possède au moins une thread.
Un job est un objet pouvant contenir un ou plusieurs processus. Le job est utile pour regrouper
plusieurs processus d’une même application et leur imposer des quotas (de mémoire ou d’utilisation processeur) ou pouvoir tous les terminer d’un coup.
La figure 6 montre le gestionnaire des tâches Process Hacker (bien plus convivial et détaillé que celui
fourni avec Windows) sur mon PC. On y observe les processus en cours avec le nombre de threads et de
handles ouverts par chacun. À ce moment, il y avait 69 processus en exécution, totalisant 731 threads.
Il y avait en tout 47 340 handles ouverts.
6.2
La commutation de tâche
À tout moment, une thread possède l’un des états suivants :
— en exécution (running) : la thread est en train de s’exécuter sur le processeur ; il ne peut y avoir
au maximum qu’une seule thread qui s’exécute par processeur ;
— prête (ready) : la thread a du code à exécuter mais ne s’exécute pas car elle attend son tour ;
— sur liste d’attente (standby) : la thread va normalement s’exécuter au prochain tour ; il ne peut y
avoir au maximum qu’une seule thread dans cet état par processeur ;
— en attente (waiting) : la thread n’a pas de code à exécuter ; elle attend qu’un objet soit signalé
(par la fonction NtWaitForSingleObject par exemple) ou alors elle a été mise en pause ;
— terminée (terminated) : la thread a été terminée ; l’objet n’est pas détruit car il est encore ouvert
par d’autres processus.
Le scheduler effectue les commutations de contexte d’une thread à une autre. Un quantum désigne l’unité de temps pendant lequel une thread peut s’exécuter. Le quantum varie en fonction de
la fréquence de l’horloge système et de la configuration de Windows. Il peut donc varier de 2 ms à
150 ms ; dans la plupart des configurations il est d’environ 20 ms. Une commutation de contexte (changement de thread) a donc lieu dans les cas suivants : lorsqu’une thread passe en attente (si elle appelle
NtWaitForSingleObject par exemple), lorsque le quantum est épuisé ou bien lorsqu’une thread de
priorité plus haute passe dans l’état ready.
Le scheduler choisit la prochaine thread à exécuter en fonction de deux paramètres :
— la priorité de la thread : c’est une valeur entre 0 et 31 ; les valeurs entre 0 et 15 sont des priorités
normales et celles entre 16 et 31 sont des priorités temps-réel ; cette priorité est calculée en fonction
de la classe de priorité du processus et de celle de la thread ;
— un éventuel boost : lorsqu’une thread possède une fenêtre au premier plan, à la complétion d’opération d’entrée/sortie ou encore lorsqu’un objet devient signalé ; cela permet d’assurer une meilleure
réactivité.
Il existe aussi un mécanisme de boost permettant d’éviter que des threads ne s’exécutent jamais et d’éviter les problèmes d’inversion de priorité.
Lorsqu’aucune thread n’est prête à s’exécuter, le système exécute une pseudo-thread exécutant la
fonction KiIdleLoop, qui se charge de mettre le processeur dans un mode de basse consommation et en
pause en attendant qu’il y ait une thread à exécuter.
14 / 17
Présentation du noyau de Windows NT
Figure 6 – Gestionnaire des tâches Process Hacker sous Windows 7
15 / 17
Présentation du noyau de Windows NT
7
Entrées / Sorties
Sous Windows NT, les objets périphérique (devices) forment des piles. Le device en bas de la pile
s’appelle un PDO (Physical Device Object). On trouve en haut de la pile un FDO (Functional Device
Object). À n’importe quel endroit de la pile on peut trouver des filtres (filters).
Lorsqu’on lance une opération d’entrée/sortie, c’est-à-dire une lecture, une écriture ou un IOCTL
(Input/Output ConTroL : un mécanisme permettant un échange spécial avec un périphérique comme
pour changer un paramètre par exemple), le système crée une structure appelée IRP (I/O Request Packet). Cette structure contient toutes les données relatives à l’opération d’entrée/sortie. L’I/O Manager
passe alors cet IRP au premier périphérique de la pile en appelant une fonction du driver qui y est attaché. Cette fonction va éventuellement faire un traitement sur l’IRP puis va passer celui-ci au prochain
élément dans la pile, et ainsi de suite jusqu’à arriver en bas de la pile. Le driver le plus bas dans la pile
communique avec le matériel.
Un exemple est la lecture d’un fichier. Un programme appelle NtReadFile sur un fichier du disque-dur.
Un IRP avec les données nécessaires est créé. L’IRP est passé au driver du système de fichier (ntfs.sys).
Celui-ci effectue un premier traitement puis appelle le driver de gestion des partitions (partmgr.sys), qui
appelle le driver du disque (disk.sys), qui appelle le driver du bus ATA (atapi.sys) qui communique
enfin avec le disque-dur. Il est courant que l’IRP passe par divers filtres qui peuvent être présents dans
la pile.
Un autre exemple est celui d’une communication réseau à l’aide d’une socket. L’application appelle
send. Un IRP de type IOCTL est envoyé au driver gérant les sockets (afd.sys), qui appelle la pile
TCP/IP (tcpip.sys), qui appelle le driver de gestion des cartes réseau (ndis.sys), qui appelle enfin le
driver de la carte réseau qui communique alors avec celle-ci (voir fig. 2).
La création d’un IRP est une opération coûteuse. C’est pourquoi lorsque l’opération d’entrée/sortie
porte sur un fichier présent dans le cache du système, un mécanisme appelé FastIO permet de s’affranchir
de la notion d’IRP et ainsi d’obtenir de meilleures performances.
8
Interface graphique
L’interface graphique de Windows fait partie intégrante du système. Auparavant sa gestion était
effectuée en mode utilisateur, mais pour des raisons de performances, elle est gérée en mode noyau
depuis Windows NT 4.0, par le fichier win32k.sys, dans le processus csrss.exe (Client/Server Runtime
SubSystem). Elle est constituée de deux composants :
— USER (USER interface) est le système de fenêtrage. Il gère les fenêtres, les contrôles (boutons,
cases à cocher, etc.), les périphériques d’entrée (clavier, souris) et les files de messages ;
— GDI (Graphics Device Interface) correspond à la gestion du graphisme. Elle gère l’affichage à
l’écran et l’impression : polices de caractères, formes, courbes, lignes, palettes, etc.
8.1
Les messages et le RIT
Un message est constitué d’un identifiant de message et de deux paramètres (de 32 bits pour un
processeur x86 et de 64 bits pour un processeur AMD64). Les messages permettent au système de
communiquer avec les applications pour leur signaler des évènements. Par exemple une fenêtre reçoit
le message WM_COMMAND lorsque l’utilisateur a cliqué sur un bouton. Elle reçoit le message WM_KEYDOWN
lorsqu’une touche du clavier est enfoncée. Certains évènements particuliers sont aussi signalés par des
messages ; par exemple lorsque l’ordinateur est débranché du secteur ou lorsqu’il se prépare à passer en
veille, tous les programmes reçoivent le message WM_POWERBROADCAST et peuvent réagir en conséquence
si nécessaire. Il existe environ 1200 messages définis par Windows. C’est la couche USER qui se charge
de transmettre les messages.
Chaque thread qui utilise l’interface graphique possède une file de message. Il s’agit d’une queue permettant d’accumuler des messages en vue de leur traitement. Un programme peut envoyer un message
à une autre fenêtre à l’aide des fonctions SendMessage ou PostMessage. Presque tous les programmes
graphiques exécutent une boucle constituée des fonctions GetMessage (cette fonction met la thread en
état d’attente et retourne uniquement lorsqu’un message est présent) et DispatchMessage pour récupérer et traiter les messages de sa file. Il possède une fonction souvent nommée WindowProc ou WndProc
qui reçoit les messages, traite ceux qui l’intéressent et renvoie les autre à la fonction de traitement par
16 / 17
Présentation du noyau de Windows NT
défaut du système, DefWindowProc.
Il existe une thread du processus csrss.exe qui exécute la fonction RawInputThread (RIT). Cette
fonction s’occupe de récupérer les évènements en provenance du clavier et de la souris, de les transformer
en messages et d’envoyer ces messages aux fenêtres concernées. Une deuxième thread de csrss.exe
exécute la fonction xxxDesktopThread ; cette fonction s’occupe de déplacer le curseur de la souris à
l’écran et de traiter les messages envoyés à la desktop window, qui est une fenêtre invisible et qui est la
mère de toutes les autres fenêtres du bureau.
8.2
Les sessions, WindowStations et bureaux
Un bureau (desktop) est un conteneur pouvant contenir des fenêtres. L’intérêt d’avoir plusieurs bureaux réside dans le fait que deux fenêtres situées dans deux bureaux différents ne peuvent pas s’envoyer
de message. C’est pour cela que l’UAC affiche la demande d’élévation sur un bureau distinct (Windows
prend une capture d’écran, la grise et l’affiche en arrière plan du nouveau bureau pour donner l’illusion
qu’il s’agit du même bureau) pour éviter qu’un programme malveillant réponde oui à la place de l’utilisateur en envoyant un message WM_COMMAND à la fenêtre de l’UAC. Le bureau est un objet protégé par
une ACL ce qui permet de protéger ainsi ses fenêtres.
Dans une configuration standard, toutes les applications s’exécutent dans un bureau nommé Default.
Il existe un deuxième bureau appelé Winlogon qui apparaît quand on presse Ctrl-Alt-Suppr. Là encore
il s’agit de sécurité : dans ce bureau on entre son mot de passe. Si ces fenêtres s’affichaient dans le bureau
Default, un programme malveillant pourrait envoyer WM_GETTEXT à la zone de texte contenant le mot
de passe pour le récupérer.
Une WindowStation est un conteneur pouvant contenir plusieurs bureaux. En pratique il n’y a qu’une
seule WindowStation par session, d’autant que seuls les bureaux contenus dans la WindowStation nommée WinSta0 peuvent être affichés à l’écran.
À partir de Windows NT 4.0 Terminal Server (et Windows XP pour les versions client), plusieurs
sessions peuvent être ouvertes en même temps sur le même système. Chaque session possède sa propre
copie en mémoire de win32k.sys, de csrss.exe, du pilote de carte graphique et de WinSta0. Sous
Windows Vista et suivants, la session 0 héberge les services (équivalents des dæmons sous Unix), tandis
que les sessions suivantes sont disponibles pour les utilisateurs. On peut voir figure 6 que les services
tournent dans la session 0 et les applications dans la session 2 (colonne Session ID).
Il est possible d’avoir plusieurs sessions ouvertes en même temps ; on peut passer d’une session à
l’autre à l’aide de l’option Changer d’utilisateur du bouton Démarrer. Par contre, une seule session peut
être connectée au terminal local (écran, clavier et souris) à la fois. Les autres sessions peuvent toutefois
être ouvertes à distance (sur un autre PC) à l’aide du bureau à distance (protocole RDP : Remote Desktop Protocol).
Attention, dans l’environnement Windows, le terme session peut désigner deux concepts différents,
à ne pas confondre :
— la session au sens Win32, celle que nous traitons dans cette partie ;
— la session au sens LSA (Local Security Authority) qui correspond à la délivrance d’un jeton d’accès.
17 / 17