Aller au contenu principal
Xsec

Composants internes de Windows

Publié le 12 min de lecture

Mis à jour le

Sérieevasion
Partie 1 sur 3
Dans cette série32 min de lecture au total
  1. Composants internes de Windows
  2. Composants Internes des EDR
  3. Neutralisation d'EDR

Suivre une opération Windows de l’API user-mode jusqu’aux objets, gestionnaires et contraintes du noyau.

Windows Internals devient vite rébarbatif lorsqu’il est présenté comme une liste de structures. Le fil directeur de cet article est donc une opération : un thread d’application demande l’accès à une ressource, le système traduit cette demande, vérifie son contexte, fait circuler une requête et conserve l’état nécessaire à son exécution.

Ce parcours permet de répondre à trois questions à chaque couche :

  • quel composant possède le contrat ;
  • quelles données traversent la frontière ;
  • quelles conclusions sont stables, et lesquelles dépendent du build observé.
Schéma technique
ARCHITECTURE EN COUCHES: Les API user-mode rejoignent des services kernel par une transition contrôlée.WINDOWS INTERNALS · FRONTIÈRES DE PRIVILÈGEARCHITECTURE EN COUCHESLes API user-mode rejoignent des services kernel par une transition contrôlée.USER MODEKERNEL MODEsyscallPROCESSUSApplicationCode et bibliothèquesNATIVE APIntdll.dllStubs systèmeNOYAU WINDOWSntoskrnl.exeExecutive · kernelEXECUTIVEGestionnairesObjets · E/S · mémoireMODULESDriversPiles de devicesABSTRACTIONHAL · matérielInterruptions · DMAFRONTIÈRE DE PRIVILÈGE · CONTRAT SYSTÈME · EXECUTIVE · DRIVERS · MATÉRIEL
Vue conceptuelle des domaines user-mode et kernel-mode. Les composants exacts traversés dépendent de l'opération et de la pile de drivers.Lecture du schémaSuivez la demande de gauche à droite. Une application appelle d'abord une API de son processus. Une routine Native API de `ntdll.dll` peut préparer la transition système. Dans le noyau, `ntoskrnl.exe` et les drivers appliquent le contrat de l'opération, tandis que la HAL isole une partie des détails matériels.

Traverser la frontière user-mode et kernel-mode

Une application s’exécute en user-mode, dans un espace d’adressage isolé. Elle utilise des bibliothèques qui exposent des interfaces Win32 ou plus spécialisées. Ces interfaces peuvent valider des paramètres, adapter des formats et, lorsque l’opération requiert un service du noyau, rejoindre une routine Native API exportée par ntdll.dll.

La transition système change le niveau de privilège, mais ne transforme pas l’application en code kernel. ntoskrnl.exe reprend l’exécution dans un point d’entrée contrôlé, valide les arguments selon le service demandé puis mobilise le gestionnaire concerné : objets, processus, mémoire, entrées/sorties ou configuration.

Le Hardware Abstraction Layer (HAL), ou couche d’abstraction matérielle, isole certains détails de plateforme, notamment autour des interruptions et de l’accès au matériel. Les drivers s’intègrent quant à eux dans des piles de devices ou appellent des interfaces supportées du noyau. Leur présence en kernel-mode leur donne un impact élevé, mais pas le droit de contourner les contrats d’Interrupt Request Level (IRQL), de mémoire ou d’objets.

Cette architecture établit où s’effectue la transition de privilège. Elle ne décrit pas encore l’état durable sur lequel le noyau agit. Pour suivre une opération dans le temps, il faut distinguer les objets processus et thread des structures user-mode qui les accompagnent.

Processus et threads : séparer les rôles

Schéma technique
DEUX DOMAINES, PLUSIEURS OBJETS: Les structures executive, dispatcher et user-mode ont des rôles distincts.PROCESSUS ET THREADS · STRUCTURES ASSOCIÉESDEUX DOMAINES, PLUSIEURS OBJETSLes structures executive, dispatcher et user-mode ont des rôles distincts.KERNEL MODEUSER MODEcontientassociecontientréférence user-modeTEB du threadEXECUTIVEEPROCESSToken · handlesespace d'adressageEMBARQUÉKPROCESSÉtat dispatcherplanificationTHREAD EXECUTIVEETHREADContexte threadEMBARQUÉKTHREADÉtat ordonnanceurPROCESSUSPEBModulesparamètresTHREADTEBÉtat user-modeRELATION STABLE · RÔLES CONCEPTUELS · CHAMPS ET OFFSETS PROPRES AU BUILD
Relations conceptuelles entre EPROCESS, KPROCESS, ETHREAD, KTHREAD, PEB et TEB. Les champs et offsets internes varient selon le build.Lecture du schémaUn objet `EPROCESS` représente le processus au niveau executive et embarque un `KPROCESS` pour son état de planification. Chaque `ETHREAD` associé embarque un `KTHREAD`. Le Process Environment Block (PEB) et le Thread Environment Block (TEB) résident dans l'espace user-mode et exposent un autre type d'état.

EPROCESS est l’objet processus opaque utilisé par le noyau. Microsoft documente son rôle et les routines supportées qui acceptent un pointeur vers cet objet, mais pas un contrat permettant aux drivers d’en modifier librement les champs. Les offsets affichés par un débogueur sont donc des observations propres aux symboles et au build chargés.

Conceptuellement, EPROCESS porte l’état executive du processus et embarque un KPROCESS associé au dispatcher et à l’ordonnancement. Un thread est représenté par un objet ETHREAD, qui embarque un KTHREAD pour son état d’exécution kernel. Ces relations sont utiles pour comprendre le modèle ; leurs layouts ne constituent pas une ABI stable pour un driver.

Le Process Environment Block (PEB) et le Thread Environment Block (TEB) résident en user-mode. Le PEB expose notamment des informations relatives au processus et à son chargeur ; le TEB porte de l’état propre au thread. Un outil de sécurité peut les lire dans certains contextes, mais leur emplacement en user-mode implique qu’ils ne remplacent pas l’autorité des objets kernel.

Les handles relient le processus à des objets tels que fichiers, événements, sections ou clés de registre. Un handle n’est pas l’objet lui-même : c’est une entrée dans un espace de handles, associée à des droits accordés. Le jeton primaire du processus fournit par ailleurs le contexte de sécurité utilisé lors de nombreux contrôles d’accès.

Ces structures décrivent qui exécute et quels objets lui sont accessibles. Elles ne disent pas quand un thread obtient effectivement un processeur. L’étape suivante est donc le cycle d’ordonnancement.

Ordonnancement : du thread prêt au thread en attente

Schéma technique
TRANSITIONS D'ÉTAT: Le planificateur choisit un thread prêt ; les attentes le retirent du CPU.ORDONNANCEMENT · CYCLE D'UN THREADTRANSITIONS D'ÉTATLe planificateur choisit un thread prêt ; les attentes le retirent du CPU.dispatchpréemptionattentesortiesatisfaitretour prêtÉLIGIBLEPrêtFile de prioritéCPUEn coursThread exécutéBLOQUÉEn attenteE/S · objet · délaiSORTIETerminéNettoyage différéORDONNANCEURDispatcherPriorité · affinitéSIGNALRéveilDevient prêtPRÊT · DISTRIBUTION · EXÉCUTION · ATTENTE · RÉVEIL · TERMINAISON
Cycle simplifié d'un thread. Windows possède des états et transitions supplémentaires qui dépendent du chemin d'exécution.Lecture du schémaUn thread prêt peut être distribué sur un processeur. Une préemption le remet dans un état planifiable. Une attente d'E/S ou d'objet le bloque jusqu'à satisfaction, puis il redevient prêt. La terminaison sort ce thread du cycle d'ordonnancement.

Windows utilise un ordonnanceur préemptif fondé sur les priorités. Un thread prêt est éligible à l’exécution. Lorsqu’il est distribué sur un processeur, il passe en cours d’exécution ; une préemption peut le rendre à nouveau prêt. Une attente sur une E/S, un objet dispatcher ou un délai le retire du processeur jusqu’à ce que la condition soit satisfaite.

La priorité d’un thread et l’IRQL courant sont deux notions différentes. La priorité aide l’ordonnanceur à choisir entre des threads prêts. L’IRQL décrit un niveau d’exécution par processeur qui masque certaines interruptions et contraint les opérations kernel autorisées. Un thread ordinaire s’exécute à PASSIVE_LEVEL, même si sa priorité d’ordonnancement est élevée.

L’ordonnanceur explique quand le code s’exécute, mais pas où résident ses instructions et ses données. Pour cela, Windows interpose un espace d’adressage virtuel et un gestionnaire de mémoire.

Mémoire virtuelle : traduire une adresse, retrouver son contenu

Schéma technique
DE L'ADRESSE À SON CONTENU: Une page virtuelle peut être résidente, récupérable ou matérialisée à la demande.MÉMOIRE VIRTUELLE · RÉSIDENCE DES PAGESDE L'ADRESSE À SON CONTENUUne page virtuelle peut être résidente, récupérable ou matérialisée à la demande.validenon validePROCESSUSAdressevirtuelleLecture · écritureTRADUCTIONTables de pagesEntrée PTERÉSIDENTECadre physiqueBase PFNDÉFAUT DE PAGEGestionnairede mémoireRésout la sourceMÉMOIREStandby · zéroDéfaut logicielSTOCKAGEPagefileDonnées privéesSECTIONFichier mappéOctets du fichierADRESSE VIRTUELLE · PTE · ENSEMBLE DE TRAVAIL · PFN · PAGEFILE · FICHIER MAPPÉ
Vue conceptuelle de la traduction d'adresse et des sources possibles d'une page. Les formats de tables dépendent de l'architecture et de la configuration.Lecture du schémaL'adresse virtuelle est traduite par des tables de pages. Si la page est valide, elle référence un cadre physique suivi dans la base PFN. Sinon, le gestionnaire de mémoire peut satisfaire le défaut depuis une liste mémoire, le fichier d'échange ou les octets d'un fichier mappé.

Chaque processus manipule des adresses virtuelles. Les tables de pages de l’architecture traduisent ces adresses vers des cadres de mémoire physique lorsque la page est résidente. La base de données Page Frame Number (PFN) suit l’état des cadres physiques ; l’ensemble de travail d’un processus décrit les pages qui lui sont actuellement résidentes selon les politiques du gestionnaire de mémoire.

Une entrée non valide ne signifie pas nécessairement que les données sont absentes. Un défaut de page peut être satisfait depuis une liste mémoire, par une page privée enregistrée dans le fichier d’échange ou par les octets d’un fichier mappé. La source exacte dépend du type de mappage et de l’état courant.

DéfinitionQue signifie « les pages d'un fichier » ?

Un fichier est conceptuellement une suite d’octets, pas un conteneur qui stocke déjà des « pages mémoire ». L’expression désigne des plages de taille fixe dans ces octets lorsqu’une section les mappe dans un espace virtuel. Chaque page virtuelle correspond alors à un offset du fichier. Si son contenu n’est pas résident, le gestionnaire de mémoire peut relire la plage correspondante depuis le fichier.

Le gestionnaire de mémoire établit donc comment un buffer devient accessible au CPU. Il ne transporte pas à lui seul une demande jusqu’au système de fichiers ou au matériel. Ce transport appartient au modèle d’entrées/sorties.

Entrées/sorties : la requête descend, la complétion remonte

Schéma technique
PARCOURS D'UNE OPÉRATION FICHIER: La requête descend la pile ; son statut remonte vers l'appelant.ENTRÉES/SORTIES · REQUÊTE ET COMPLÉTIONPARCOURS D'UNE OPÉRATION FICHIERLa requête descend la pile ; son statut remonte vers l'appelant.syscallstatut et donnéesAPPLICATIONCreateFileWKernel32.dllKernelBase.dllNATIVE APINtCreateFilentdll.dllNOYAUI/O ManagerIRP_MJ_CREATEPILE FICHIERMinifilters+ NTFSMétadonnéesPILE VOLUMEVolume+ stockageRequête devicePÉRIPHÉRIQUEMatérielDMA · interruptionWIN32 · NATIVE API · IRP · SYSTÈME DE FICHIERS · VOLUME · STOCKAGE · COMPLÉTION
Chemin simplifié d'une opération fichier. Les minifilters, drivers de volume et drivers de stockage présents varient selon la configuration.Lecture du schéma`CreateFileW` est une API Win32 exposée par `Kernel32.dll` et généralement relayée par `KernelBase.dll`. `NtCreateFile` est le point Native API de `ntdll.dll`. Après la transition système, le gestionnaire d'E/S construit la requête, puis la pile de drivers la traite vers le bas avant une complétion vers le haut.

Pour ouvrir un fichier, une application peut appeler CreateFileW. Cette API est exportée par Kernel32.dll, déclarée dans fileapi.h et liée avec Kernel32.lib; selon le build, l’export peut relayer son implémentation vers KernelBase.dll. La Native API correspondante, NtCreateFile, est exportée par ntdll.dll et déclarée dans winternl.h.

Après la transition système, le gestionnaire d’entrées/sorties de ntoskrnl.exe construit une requête. Dans le modèle Windows Driver Model (WDM), elle est généralement représentée par un I/O Request Packet (IRP). Une opération d’ouverture porte le code majeur IRP_MJ_CREATE. Chaque driver de la pile reçoit une vue de paramètres adaptée à son niveau, peut traiter la demande ou la transmettre vers le bas.

Un chemin fichier peut traverser des minifilters, le système de fichiers, des drivers de volume puis de stockage. Cette liste est conceptuelle : les composants réellement présents dépendent de la configuration, du type de device et de l’opération. La requête descend vers le device ; le statut, le nombre d’octets et les éventuelles données remontent par les routines de complétion.

Le Direct Memory Access (DMA), ou accès direct à la mémoire, permet à certains devices de transférer des données sans faire copier chaque octet par le CPU. Des Memory Descriptor Lists (MDL) et mécanismes de mappage décrivent les buffers selon le contrat du driver et de la plateforme.

Le modèle E/S explique comment une demande atteint son fournisseur. Il ne suffit pas à décider si l’appelant possède les droits requis. Avant de remettre un handle exploitable, Windows doit comparer le contexte de sécurité de l’appelant à la politique de l’objet.

Contrôle d’accès : calculer les droits du handle

Schéma technique
DÉCIDER DES DROITS ACCORDÉS: Le contexte de l'appelant est comparé à la politique de l'objet.SÉCURITÉ · CONTRÔLE D'ACCÈSDÉCIDER DES DROITS ACCORDÉSLe contexte de l'appelant est comparé à la politique de l'objet.ouinonDEMANDEObjet + droitsAccès souhaitéAPPELANTJeton d'accèsSID · groupesprivilègesOBJETDescripteurde sécuritéDACL · SACLNOYAUAccess checkCalcule le masqueAUTORISÉHandle accordéDroits effectifsREFUSÉAccès refuséStatut d'échecAUDITSACLSi configuréeJETON · SID · PRIVILÈGES · DESCRIPTEUR · DACL · SACL · MASQUE D'ACCÈS
Modèle conceptuel d'un contrôle d'accès. Les privilèges, Mandatory Integrity Control et règles propres au type d'objet peuvent ajouter des conditions.Lecture du schémaLe jeton porte notamment les Security Identifiers (SID), groupes et privilèges de l'appelant. Le descripteur de sécurité porte la Discretionary Access Control List (DACL) et éventuellement une System Access Control List (SACL) pour l'audit. Le contrôle calcule les droits accordés avant la création du handle.

Un jeton d’accès contient notamment les Security Identifiers (SID) de l’utilisateur et de ses groupes, ainsi que des privilèges. Un descripteur de sécurité identifie le propriétaire d’un objet sécurisable et peut contenir une Discretionary Access Control List (DACL), qui autorise ou refuse des droits, ainsi qu’une System Access Control List (SACL), qui configure l’audit.

Le contrôle compare le masque d’accès demandé au contexte de l’appelant et aux règles de l’objet. D’autres mécanismes peuvent intervenir, notamment les privilèges, le Mandatory Integrity Control et les vérifications propres au type d’objet. En cas de succès, le handle reçu porte les droits effectivement accordés ; il ne confère pas automatiquement tous les droits possibles sur l’objet.

Observation dans WinDbg : un champ interne n’est pas un contrat

AvertissementLab isolé uniquement

Les captures suivantes proviennent d’une session de débogage kernel à haute intégrité. Modifier directement un EPROCESS contourne les interfaces supportées, peut rompre les comptages de références et déstabiliser la machine cible. L’intérêt ici est de montrer la frontière entre objet documenté et layout propre au build, pas de proposer une méthode d’administration.

La première vue établit le contexte général de la session WinDbg.

Session WinDbg connectée à une cible Windows
Observation de lab : session de débogage kernel utilisée pour inspecter les objets processus.

La commande !process 0 0 cmd.exe retrouve l’adresse de l’objet processus associé à cmd.exe.

Résultat WinDbg de la commande process pour cmd.exe
Observation de lab : l'extension `!process` retourne l'adresse EPROCESS du processus ciblé pour ce démarrage.

dt nt!_EPROCESS Token interroge les symboles du build courant. L’offset visible dans la capture ne doit jamais être réutilisé comme constante universelle.

Structure EPROCESS et champ Token affichés dans WinDbg
Observation propre au build : type et offset du champ `Token` résolus depuis les symboles chargés.

La même énumération retrouve l’objet du processus System, utilisé ici uniquement pour comparer deux champs.

Résultat WinDbg de la commande process pour System
Observation de lab : adresse EPROCESS du processus System dans la session courante.

Le champ est de type _EX_FAST_REF, c’est-à-dire une référence d’objet qui combine un pointeur aligné et des bits de comptage. Lire seulement l’adresse sans comprendre ces bits conduit à une interprétation incorrecte.

Valeur EX_FAST_REF du token System affichée dans WinDbg
Observation de lab : représentation `_EX_FAST_REF` du token. Le pointeur et les bits de référence doivent être distingués.

La capture suivante montre l’état après une écriture expérimentale. Elle démontre qu’un débogueur kernel peut modifier le layout observé, pas que ce layout est une interface supportée.

Champ Token de cmd.exe relu après une modification dans WinDbg
Observation de lab : relecture du champ modifié. Une égalité de valeur ne garantit ni la cohérence des références ni la stabilité de la cible.

La reprise de l’exécution mesure ensuite les conséquences sur la cible.

Reprise de l'exécution de la cible dans WinDbg
Observation de lab : reprise de la machine virtuelle après l'expérience. Toute validation doit inclure la stabilité et les effets secondaires.

Ce cas montre pourquoi un offset interne ne doit pas être confondu avec une API. Il manque encore un type de ressource central pour la configuration : le registre, dont les noms logiques sont reliés à des ruches et à des callbacks spécialisés.

Registre : des vues logiques aux ruches

Schéma technique
DU NOM DE CLÉ AU STOCKAGE: Le Configuration Manager relie les vues du registre aux ruches chargées.REGISTRE · VUES LOGIQUES ET RUCHESDU NOM DE CLÉ AU STOCKAGELe Configuration Manager relie les vues du registre aux ruches chargées.statutUSER MODEReg* APIAdvapi32.dllNATIVE APINt/Zw*ntdll · ntoskrnlNOYAUConfigurationManagerObjets cléNOTIFICATIONCallback préAvant l'opérationNOTIFICATIONCallback postStatut résultantSTOCKAGERuches+ cellulesSYSTEM · SOFTWAREREPRISELogsÉtatAPI REG* · NATIVE API · CONFIGURATION MANAGER · OBJETS CLÉ · RUCHES · JOURNAUX
Vue conceptuelle du registre. Certaines clés racines sont des vues ou des liens vers des emplacements gérés par le Configuration Manager.Lecture du schémaLes API user-mode de `Advapi32.dll` rejoignent les services Native API de `ntdll.dll`, puis le Configuration Manager dans `ntoskrnl.exe`. Celui-ci résout les noms, objets clé et cellules des ruches. Les callbacks enregistrés avec `CmRegisterCallbackEx` observent des classes de notifications pré et post distinctes.

Le registre organise clés et valeurs dans des vues hiérarchiques. Une ruche est un groupe logique de clés, sous-clés et valeurs associé à un ensemble de fichiers de support chargé en mémoire. Les ruches système principales utilisent notamment des fichiers sous %SystemRoot%\System32\Config; les profils utilisateurs possèdent leurs propres fichiers.

Les fichiers de journalisation participent à la cohérence et à la récupération. Les cellules, index et autres structures internes expliquent l’implémentation d’un build, mais une application doit utiliser les API documentées plutôt que dépendre de leur layout.

Les fonctions RegOpenKeyExW et RegSetValueExW sont exposées par Advapi32.dll, déclarées dans winreg.h et liées avec Advapi32.lib. Elles rejoignent les services Native API de ntdll.dll, puis le Configuration Manager de ntoskrnl.exe.

Un driver de filtrage peut appeler CmRegisterCallbackEx. Cette routine est exécutée par ntoskrnl.exe, déclarée dans wdm.h et liée avec NtosKrnl.lib. Elle inscrit une fonction fournie par le driver et une altitude. Le Configuration Manager livre ensuite des classes REG_NOTIFY_CLASS distinctes avant ou après les opérations. Les données disponibles et les modifications permises dépendent de la classe exacte.

Le registre ajoute une source de configuration et de télémétrie. Il ne supprime pas les contraintes du contexte kernel qui exécute le callback. Pour savoir quelles fonctions et quelles mémoires restent sûres à cet instant, il faut enfin comprendre l’IRQL.

IRQL et synchronisation : le contexte fait partie du contrat

Schéma technique
PLUS LE NIVEAU MONTE, PLUS LE CONTRAT SE RESSERRE: L'IRQL borne les interruptions autorisées et les opérations sûres.KERNEL · INTERRUPT REQUEST LEVELPLUS LE NIVEAU MONTE, PLUS LE CONTRAT SE RESSERREL'IRQL borne les interruptions autorisées et les opérations sûres.IRQL BASPASSIVE_LEVELAttente possiblemémoire pageableAPCAPC_LEVELLivraison restreinteDISPATCHERDISPATCH_LEVELPas d'attentepas de page faultINTERRUPTIONDIRQLPropre au deviceSOMMETHIGH_LEVELContexte maximalRÈGLEBrefIRQL COURANT · MÉMOIRE NON PAGEABLE · PAS D'ATTENTE À DISPATCH_LEVEL · SECTIONS COURTES
Hiérarchie conceptuelle des IRQL. Les valeurs et Device IRQL (DIRQL) exacts dépendent de l'architecture et de la plateforme.Lecture du schémaÀ `PASSIVE_LEVEL`, le code peut attendre et toucher de la mémoire pageable selon son contrat. À `APC_LEVEL`, certaines livraisons sont masquées. À `DISPATCH_LEVEL`, attendre ou provoquer un défaut de page n'est plus autorisé. Les DIRQL servent aux interruptions de devices ; `HIGH_LEVEL` est le niveau symbolique le plus élevé.

L’Interrupt Request Level (IRQL) est un état par processeur. En élevant l’IRQL, Windows masque certaines interruptions de niveau inférieur ou égal et restreint les opérations sûres. Le niveau ne mesure pas la « puissance » d’un driver ; il exprime un contexte d’exécution.

À PASSIVE_LEVEL, une routine peut attendre et accéder à de la mémoire pageable si son propre contrat l’autorise. À partir de DISPATCH_LEVEL, elle ne doit pas effectuer une attente bloquante ni provoquer de défaut de page. Les Device IRQL (DIRQL) servent aux routines d’interruption de devices. Les valeurs exactes dépendent de l’architecture ; HIGH_LEVEL désigne symboliquement le niveau le plus élevé.

KeAcquireSpinLock est une macro déclarée dans wdm.h et liée selon le WDK avec Hal.lib. Elle élève le processeur à DISPATCH_LEVEL, acquiert le spinlock et rend l’ancien IRQL à l’appelant. La section protégée doit rester non pageable et très courte.

Une ressource executive répond à un autre besoin. ExAcquireResourceSharedLite et ExAcquireResourceExclusiveLite fournissent un verrou lecteur-écrivain susceptible d’attendre. Ces routines sont exécutées par ntoskrnl.exe, déclarées dans wdm.h et liées avec NtosKrnl.lib; leur contrat impose notamment un IRQL compatible et la gestion des APC kernel normaux. Elles ne sont pas interchangeables avec un spinlock à DISPATCH_LEVEL.

Conclusion

Le fonctionnement interne de Windows se lit comme une chaîne de contrats. Une API prépare une demande, la Native API traverse la frontière, un gestionnaire sélectionne des objets et des droits, les requêtes circulent dans des piles, puis l’ordonnanceur, la mémoire et l’IRQL bornent l’exécution.

Cette base rend les deux articles suivants plus lisibles sans répéter les mêmes définitions : l’analyse technique des internals EDR applique ces contrats aux capteurs, tandis que Neutralisation d’EDR étudie l’écart entre confiance de chargement et autorisation dans le protocole d’un driver.

Références

Utiliser avec une IA

Actions