Comment fonctionne la résolution des noms de DLL sous Windows - Ordre de recherche et SxS

· Mis à jour le: · · Windows, DLL, Chargeur, Sécurité, Développement Windows

Dès que l’on parle des DLL natives sous Windows, une confusion du type suivant survient avec une fréquence remarquable.

  • Quand on écrit LoadLibrary("foo.dll"), où cela va-t-il réellement chercher ?
  • La DLL a été placée dans le même dossier que l’exécutable, alors pourquoi une DLL différente est-elle chargée ?
  • Est-ce System32 qui l’emporte, ou le dossier de l’application ?
  • À quelle étape les manifestes, les API sets et les Known DLLs entrent-ils en jeu ?
  • Que change l’utilisation de SetDllDirectory ou AddDllDirectory ?
  • Qu’est-ce qui rend probables les attaques par implantation de DLL et le DLL hijacking ?

Mémoriser l’ordre de recherche en une seule ligne ne suffit pas pour un usage professionnel réel. En réalité, le chargeur Windows évalue plusieurs règles spéciales avant même de commencer à parcourir le système de fichiers dans l’ordre.

Dans cet article, nous organisons de façon pratique la résolution des noms de DLL sous Windows, en couvrant les différences entre applications non packagées et packagées, les Known DLLs, la liste des modules déjà chargés, les API sets, les manifestes side-by-side, et les effets de la famille d’API LoadLibraryEx. Le contenu s’appuie sur les informations publiques de Microsoft Learn à la date de mars 2026.123456789

1. La conclusion d’abord

Voici d’emblée les conclusions pratiques.

  • La résolution des noms de DLL sous Windows n’est pas « d’abord une recherche sur le système de fichiers ». Des éléments comme la redirection de DLL, les API sets, les manifestes SxS, la liste des modules déjà chargés et les Known DLLs interviennent avant l’ordre de recherche proprement dit.1
  • Dans la configuration standard d’une application non packagée avec le safe DLL search mode activé, le dossier de l’application se classe haut, mais les règles spéciales ci-dessus sont évaluées avant lui.1
  • Même si l’on charge une DLL par chemin complet, ses DLL dépendantes ne sont pas automatiquement fixées au même chemin complet. Les DLL dépendantes sont recherchées uniquement par nom de module, et peuvent donc être résolues ailleurs.1
  • Known DLLs est un mécanisme par lequel l’OS associe certaines DLL bien connues à leurs copies côté système ; ce n’est pas quelque chose qu’un déploiement applicatif ordinaire peut écraser.1
  • Un API set n’est pas « le nom de la DLL réelle elle-même » mais un alias virtuel qui masque la DLL d’implémentation. Si l’on voit un nom comme api-ms-win-... et qu’on le traite comme une recherche de DLL classique, on se méprend facilement.3
  • SetDllDirectory ne fait pas que changer l’ordre de recherche — il a pour effet de désactiver de fait le safe DLL search mode, si bien qu’une utilisation trop légère peut se retourner contre la sécurité.1
  • En pratique, l’approche sûre consiste à combiner le chargement par chemin complet, SetDefaultDllDirectories, AddDllDirectory, et les indicateurs LOAD_LIBRARY_SEARCH_* de LoadLibraryEx pour restreindre explicitement le périmètre de recherche.4562

En résumé, la vision pratique est que la résolution des noms de DLL sous Windows n’est pas déterminée uniquement par « quel dossier vient dans quel ordre », mais par « quelles règles préalables résolvent le nom en premier » et « comment les API ont modifié l’espace de recherche ».

2. La résolution des noms de DLL comporte des règles préalables avant la « recherche de dossier »

Selon la documentation de Microsoft Learn sur l’ordre de recherche des DLL, lorsqu’une DLL est chargée, les éléments suivants sont traités comme faisant partie de l’ordre de recherche en premier lieu.1

  1. La redirection de DLL
  2. Les API sets
  3. La redirection par manifeste SxS
  4. La liste des modules déjà chargés
  5. Les Known DLLs

Ce n’est qu’ensuite que le chargeur procède à la recherche sur le système de fichiers à travers le dossier de l’application, System32, le dossier Windows, PATH, et ainsi de suite.1

Si l’on manque ce point, il peut sembler « anormal » que quelque chose soit décidé avant le dossier de l’application — mais en tant que description du chargeur Windows, c’est en fait la voie principale.

Le nom de la DLL doit être résoluRedirection de DLLAPI setRedirection par manifeste SxSListe des modules déjà chargésKnown DLLsOrdre de recherche sur le système de fichiersLa DLL réellement chargée est déterminée

3. L’ordre de recherche standard pour les applications non packagées

Pour une application de bureau ordinaire qui charge une DLL sans chemin complet, Microsoft Learn décrit l’ordre de recherche standard pour les applications non packagées. Dans l’état par défaut avec le safe DLL search mode activé, le déroulement est essentiellement le suivant.1

  1. La redirection de DLL
  2. Les API sets
  3. La redirection par manifeste SxS
  4. La liste des modules déjà chargés
  5. Les Known DLLs
  6. À partir de Windows 11 21H2, le package dependency graph
  7. Le dossier depuis lequel l’application a été chargée
  8. System32
  9. Le dossier système 16 bits
  10. Le dossier Windows
  11. Le dossier courant
  12. PATH

Trois points comptent particulièrement en pratique.

  • Le dossier courant est assez loin dans la liste par défaut. Le safe DLL search mode rend difficile de le faire remonter.1
  • Cependant, être loin dans la liste ne signifie pas sûr. Tant qu’un répertoire contrôlable par l’attaquant reste dans le périmètre de recherche, une marge pour le DLL preloading subsiste.2
  • À partir de Windows 11 21H2, le package dependency graph apparaît aussi dans la description de recherche des applications non packagées. C’est un écart facile à manquer si l’on ne retient que l’ancienne description.1

4. Applications packagées et applications non packagées ne sont pas la même chose

Microsoft Learn définit un ordre de recherche distinct pour les applications packagées. Dans les applications packagées, le package dependency graph agit à un stade plus précoce, et le modèle de recherche lui-même diffère quelque peu.1

Manquer cette différence entraîne, après un passage à MSIX ou l’adoption du Windows App SDK, une confusion de ce type :

  • Une DLL trouvée en exécution non packagée pendant le développement n’est pas trouvée dans le package de production
  • Les dépendances via le manifeste de package se mélangent à une dépendance à l’ancienne via PATH, et les conditions de reproduction changent
  • Expliquer « l’ordre de recherche des DLL sous Windows est tel » avec un tableau unique, en laissant de côté les différences de comportement des applications packagées

Dans les articles et les revues de conception, il est plus sûr de séparer d’abord « s’agit-il d’une application packagée ou non packagée ? »1

5. Ce que font les Known DLLs et la liste des modules déjà chargés

Les aspects de la résolution de DLL les plus susceptibles de défier l’intuition sont la liste des modules déjà chargés et les Known DLLs.

5.1 La liste des modules déjà chargés

Microsoft Learn explique que le système peut vérifier si une DLL portant le même nom de module est déjà chargée en mémoire.1

Autrement dit, avant la recherche sur le système de fichiers, il y a une vérification portant sur :

  • ce nom de DLL est-il déjà chargé, et
  • par conséquent, y a-t-il seulement besoin d’aller le chercher.

Ainsi, si, lors d’une investigation, on omet le fait que « dans ce processus, une DLL de même nom provenant d’un autre dossier était déjà chargée en premier », on interprète mal les conditions de reproduction.

5.2 Les Known DLLs

Known DLLs est la liste des DLL que Windows considère comme bien connues pour cette version, et elle peut être consultée à HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\KnownDLLs. Pour une DLL figurant sur cette liste, le système utilise sa propre copie de cette DLL connue.1

Ce qui compte ici, c’est que les Known DLLs ne sont pas le genre de chose qu’une application ordinaire peut « gagner » en plaçant une DLL de même nom dans son dossier d’application. Le comprendre comme une simple course au premier arrivé contre System32 conduit à mal interpréter le comportement.

6. Un API set est un nom de contrat, pas un « nom de DLL réel »

Quand on voit un nom comme api-ms-win-core-..., on est tenté de se demander « où trouver ce fichier DLL ? ». Mais Microsoft Learn explique qu’un API set est un alias virtuel pour une DLL physique — un mécanisme qui sépare le contrat de l’implémentation.3

Autrement dit, un raisonnement du type

  • nom de l’API set = le nom du fichier DLL physique tel quel
  • résolution de l’API set = la même recherche de fichier qu’une DLL normale

est inexact.

En gardant le modèle des API sets à l’esprit, il devient plus facile d’expliquer que

  • les choses restent cohérentes même lorsque le nom de la DLL d’implémentation diffère selon les versions de Windows et les types d’appareil, et
  • l’appelant n’a pas besoin de savoir, de façon figée, « quelle DLL hôte implémente ceci ».3

7. Les manifestes et le side-by-side (SxS) sont une réponse alternative au problème du versionnage des DLL

La redirection de DLL et les manifestes SxS ne sont pas décrits comme de simples astuces d’ordre de recherche, mais comme des mécanismes visant à éviter les conflits de versionnage de DLL.789

La formulation de Microsoft Learn est la suivante :

  • Un manifeste est du XML décrivant un assembly side-by-side ou une application isolée
  • Un assembly side-by-side est l’unité de nommage, de liaison (binding), de versionnage et de déploiement
  • Le chargeur décide à quelle version se lier en fonction des dépendances enregistrées dans le manifeste

89

Il faut donc, en pratique, distinguer ces trois cas :

  • Simplement placer une DLL privée dans le dossier de l’application
  • Utiliser une redirection de DLL telle que .local
  • Utiliser une liaison side-by-side via des manifestes

Ces trois approches se ressemblent en ce qu’elles « affectent la résolution des DLL », mais leur intention de conception n’est pas la même.

8. Ce que changent LoadLibraryEx, SetDllDirectory et AddDllDirectory

8.1 SetDllDirectory

SetDllDirectory modifie l’ordre de recherche, mais Microsoft Learn indique explicitement qu’elle désactive de fait le safe DLL search mode.1

Autrement dit, même si l’on n’avait l’intention que d’« ajouter un dossier propre à l’application », l’espace de recherche change en conséquence, y compris la façon dont le dossier courant est traité.

De plus, appeler SetDllDirectory dans un processus parent peut aussi affecter l’ordre de recherche standard des processus enfants.1

Pour cette raison, plutôt que d’utiliser SetDllDirectory de façon habituelle et négligente, il est plus sûr en pratique de s’appuyer sur

  • SetDefaultDllDirectories
  • AddDllDirectory
  • les indicateurs LOAD_LIBRARY_SEARCH_* de LoadLibraryEx

456

8.2 AddDllDirectory

Les chemins ajoutés avec AddDllDirectory s’utilisent en combinaison avec LOAD_LIBRARY_SEARCH_USER_DIRS. Sur Microsoft Learn, l’ordre de recherche parmi plusieurs répertoires ajoutés est non spécifié.15

Il vaut donc mieux éviter une conception qui

  • ajoute plusieurs répertoires, et
  • s’attend strictement à un ordre de recherche précis entre eux.

8.3 SetDefaultDllDirectories

SetDefaultDllDirectories est décrite comme une API permettant de retirer du chemin de recherche standard des DLL les répertoires les plus sujets aux vulnérabilités, afin de restreindre le périmètre de recherche.4

Trois propriétés méritent particulièrement d’être retenues.

  • Elle prend effet par processus
  • Une fois appelée, elle persiste pendant toute la durée de vie du processus
  • Un chemin de recherche standard, une fois défini, ne peut pas simplement être restauré à son état par défaut d’origine

Du point de vue de la sécurité, cette API se prête bien à une conception consistant à « basculer vers un espace de recherche plus sûr juste après le démarrage ».4

8.4 LoadLibraryEx

LoadLibraryEx permet de modifier le comportement de recherche avec LOAD_WITH_ALTERED_SEARCH_PATH et les indicateurs LOAD_LIBRARY_SEARCH_*.61

En pratique, c’est une API bien adaptée à des besoins tels que

  • inclure dans le périmètre de recherche le dossier de la DLL chargée, dépendances comprises, ou
  • restreindre la recherche au dossier de l’application, à System32, et aux répertoires utilisateur explicitement ajoutés uniquement.

9. Un chemin complet ne fixe pas les DLL dépendantes

C’est le point de ce sujet qui compte énormément en pratique tout en étant facilement négligé. Microsoft Learn explique que même lorsque la première DLL est chargée par chemin complet, ses DLL dépendantes sont recherchées uniquement par nom de module.14

Autrement dit, ce n’est pas parce que

  • l’on a explicitement chargé C:\\MyApp\\plugins\\foo.dll

qu’il s’ensuit que

  • bar.dll, dont dépend foo.dll, sera toujours prise dans le même dossier.

Avec cette idée fausse en tête, on obtient le mode d’échec plutôt désagréable où

  • cela fonctionne en environnement de développement,
  • une bar.dll différente est résolue chez le client, et
  • les conflits de DLL dépendantes deviennent difficiles à reproduire car dépendants de l’environnement.

10. Éviter le DLL preloading / hijacking

La documentation de Microsoft Learn sur la sécurité des DLL explique que la combinaison d’un chargement dynamique sans chemin complet et de répertoires contrôlables par l’attaquant dans le périmètre de recherche conduit à des attaques par préchargement de DLL (DLL preloading) et par implantation de binaire (binary planting).2

En pratique, il est utile de converger vers cette base.

  • Réduire les chargements par nom nu comme LoadLibrary("foo.dll")
  • Utiliser le chargement par chemin complet lorsque c’est nécessaire
  • Restreindre le chemin de recherche par défaut du processus avec SetDefaultDllDirectories
  • N’ajouter que des répertoires explicitement approuvés avec AddDllDirectory
  • Rendre le périmètre de recherche explicite avec des indicateurs comme LOAD_LIBRARY_SEARCH_SYSTEM32, LOAD_LIBRARY_SEARCH_APPLICATION_DIR et LOAD_LIBRARY_SEARCH_USER_DIRS
  • Éviter le dossier courant et une dépendance négligente à PATH

Une situation où un processus s’exécutant avec des privilèges d’administrateur possède un chemin de recherche ambigu est particulièrement dangereuse. Microsoft Learn note également que, lorsqu’une DLL malveillante est chargée, elle s’exécute avec les privilèges de ce processus.2

11. Une liste de contrôle pratique pour la décision

Lors de la revue de la conception du chargement de DLL sous Windows, vérifier au moins les points suivants réduit les incidents.

  1. L’application est-elle packagée ou non packagée ?
  2. Quelles DLL proviennent d’une liaison statique, et lesquelles sont chargées dynamiquement ?
  3. Chargement par chemin complet, ou par nom de module seul ?
  4. SetDllDirectory est-elle utilisée quelque part ?
  5. La configuration permet-elle d’utiliser SetDefaultDllDirectories et LOAD_LIBRARY_SEARCH_* ?
  6. Plusieurs appels à AddDllDirectory sont-ils utilisés avec une attente implicite d’ordre ?
  7. Les dépendances sont-elles gérées via des manifestes / SxS / DLL privées / redirection — et laquelle ?
  8. Existe-t-il des hypothèses de sécurité faibles autour du dossier courant ou de PATH ?
  9. Des DLL dépendantes pourraient-elles être résolues depuis un emplacement différent dans un environnement différent ?

Vérifier séparément ces neuf points permet d’éliminer, à un stade beaucoup plus précoce, des problèmes tels que « DLL introuvable », « la mauvaise DLL a été chargée », « cela échoue au démarrage uniquement en production », ou « bloqué lors de la revue de vulnérabilité ».

12. Résumé

La résolution des noms de DLL sous Windows n’est pas simplement un « ordre de recherche de dossiers ». En réalité, elle est déterminée par le chevauchement de la redirection de DLL, des API sets, des manifestes SxS, de la liste des modules déjà chargés, des Known DLLs, et de l’espace de recherche tel que modifié par les appels d’API.134

Ce qui compte le plus en pratique se résume à ces cinq points.

  • Ne pas mémoriser l’ordre de recherche comme un tableau unique
  • Distinguer les applications packagées des applications non packagées
  • Comprendre que même avec un chargement par chemin complet, les DLL dépendantes peuvent être traitées différemment
  • Ne pas utiliser SetDllDirectory de façon désinvolte
  • Pour pencher du côté sûr, utiliser SetDefaultDllDirectories et les indicateurs de recherche de LoadLibraryEx

La résolution des noms de DLL est un endroit où les échecs de démarrage, les différences d’environnement et les problèmes de sécurité ont tendance à surgir tous ensemble. C’est précisément pourquoi il vaut la peine de comprendre non seulement « dans quel ordre Windows recherche », mais aussi « ce que Windows considère, en premier lieu, comme les prémisses de la résolution des noms ».

Articles connexes

Références

  1. Microsoft Learn : Dynamic-link library search order
  2. Microsoft Learn : Dynamic-Link Library Security
  3. Microsoft Learn : Windows API sets
  4. Microsoft Learn : SetDefaultDllDirectories function
  5. Microsoft Learn : AddDllDirectory function
  6. Microsoft Learn : LoadLibraryEx function
  7. Microsoft Learn : Dynamic-link library redirection
  8. Microsoft Learn : Manifests
  9. Microsoft Learn : About Side-by-Side Assemblies
  1. Microsoft Learn, Dynamic-link library search order, consulté le 24 mars 2026  2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

  2. Microsoft Learn, Dynamic-Link Library Security, consulté le 24 mars 2026  2 3 4 5

  3. Microsoft Learn, Windows API sets, consulté le 24 mars 2026  2 3 4 5

  4. Microsoft Learn, SetDefaultDllDirectories function, consulté le 24 mars 2026  2 3 4 5 6 7

  5. Microsoft Learn, AddDllDirectory function, consulté le 24 mars 2026  2 3 4

  6. Microsoft Learn, LoadLibraryEx function, consulté le 24 mars 2026  2 3 4

  7. Microsoft Learn, Dynamic-link library redirection, consulté le 24 mars 2026  2

  8. Microsoft Learn, Manifests, consulté le 24 mars 2026  2 3

  9. Microsoft Learn, About Side-by-Side Assemblies, consulté le 24 mars 2026  2 3

Articles récents partageant les mêmes étiquettes, pour approfondir des sujets proches.

Ces pages replacent le sujet dans un contexte plus large de services et de décisions.

Cet article est directement lié aux services suivants.

Développement d'applications Windows

L'emplacement et le mode de chargement des DLL déterminent directement si une application Windows démarre, comment elle est distribuée et à quel point les défaillances sont reproductibles ; c'est donc un sujet qui mérite d'être traité dans le cadre du développement d'applications Windows.

Conseil technique et revue de conception

La résolution des noms de DLL se situe au croisement de l'investigation de bugs, du portage, de l'évitement des vulnérabilités et de la conception de la distribution, ce qui en fait un thème facile à structurer sous forme de revue de conception ou de consultation technique.

Questions fréquentes

Questions souvent posées lors d’une consultation sur le sujet de cet article.

Dans quel ordre Windows recherche-t-il une DLL ?
Pas d'abord par une recherche sur le système de fichiers. Le chargeur évalue plusieurs règles préalables avant de parcourir les dossiers : la redirection de DLL, les API sets, la redirection par manifeste SxS, la liste des modules déjà chargés, puis les Known DLLs. Ce n'est qu'ensuite que la recherche sur le système de fichiers se poursuit — le dossier de l'application, System32, le dossier système 16 bits, le dossier Windows, le dossier courant, puis PATH, avec en plus le package dependency graph à partir de Windows 11 21H2. Les applications packagées suivent un modèle de recherche différent des applications non packagées ; déterminez donc d'abord de quel cas il s'agit.
Pourquoi une DLL différente est-elle chargée alors que j'ai placé la mienne à côté de l'EXE ?
Parce que plusieurs mécanismes résolvent le nom avant même que le dossier de l'application ne soit examiné. Si la DLL figure dans la liste des Known DLLs, le système utilise sa propre copie, et une application ordinaire ne peut pas gagner cette course en plaçant un fichier de même nom à côté de l'EXE. Si un module portant le même nom est déjà chargé dans le processus, la liste des modules déjà chargés court-circuite entièrement la recherche. La redirection par manifeste SxS et les API sets peuvent eux aussi rediriger le nom — un nom comme api-ms-win-... est un alias virtuel, pas un fichier physique à trouver par recherche de dossier.
Si je charge une DLL par chemin complet, ses dépendances sont-elles chargées depuis le même dossier ?
Non, et c'est l'un des points les plus fréquemment mal compris. Même lorsque la première DLL est chargée par chemin complet, ses DLL dépendantes sont recherchées uniquement par nom de module, et peuvent donc être résolues depuis un tout autre emplacement. Cela produit ce mode d'échec désagréable où tout fonctionne en environnement de développement, mais où une DLL dépendante différente est résolue chez le client. Pour fixer les dépendances, utilisez LoadLibraryEx avec des indicateurs tels que LOAD_WITH_ALTERED_SEARCH_PATH ou la famille LOAD_LIBRARY_SEARCH_* afin de rendre le périmètre de recherche explicite.
Comment prévenir le DLL hijacking et les attaques par préchargement ?
L'attaque combine un chargement dynamique sans chemin complet et des répertoires contrôlables par l'attaquant dans le périmètre de recherche. La base : réduire les chargements par nom nu comme LoadLibrary("foo.dll"), utiliser le chargement par chemin complet quand c'est nécessaire, restreindre le chemin de recherche par défaut du processus avec SetDefaultDllDirectories, n'ajouter que des répertoires explicitement approuvés avec AddDllDirectory, et rendre le périmètre de recherche explicite avec les indicateurs LOAD_LIBRARY_SEARCH_*. Évitez SetDllDirectory, qui désactive de fait le safe DLL search mode, et soyez particulièrement prudent avec les processus s'exécutant en tant qu'administrateur, car une DLL malveillante s'exécute avec les privilèges de ce processus.

Profil de l’auteur

Page de présentation de l’auteur de l’article.

Go Komura

Représentant de KomuraSoft LLC

Spécialisé dans le développement de logiciels Windows, le conseil technique et l’analyse de pannes, notamment pour les systèmes existants et les incidents difficiles à reproduire.

Retour au blog