Порядок поиска динамической библиотеки

Как правило, несколько версий одной библиотеки динамической компоновки (DLL) существуют в разных расположениях файловой системы в операционной системе. Вы можете управлять конкретным расположением, из которого загружается любая библиотека DLL, указав полный путь. Но если вы не используете этот метод, система выполняет поиск библиотеки DLL во время загрузки, как описано в этом разделе. Загрузчик DLL — это часть операционной системы (ОС), которая загружает библиотеки DLL и (или) разрешает ссылки на библиотеки DLL.

Совет

Определения упакованных и неупакованных приложений см. в статье Преимущества и недостатки упаковки приложения.

Факторы, влияющие на поиск

Ниже приведены некоторые особые факторы поиска, которые рассматриваются в этом разделе. Их можно считать частью порядка поиска в библиотеках DLL. В последующих разделах этого раздела эти факторы перечислены в соответствующем порядке поиска для определенных типов приложений, а также в других расположениях поиска. В этом разделе описаны основные понятия и приведены имена, которые мы будем использовать для ссылки на них далее в этом разделе.

  • Перенаправление DLL. Дополнительные сведения см. в разделе Перенаправление библиотек динамической компоновки.
  • Наборы API. Дополнительные сведения см. в разделе Наборы API Windows.
  • Параллельное перенаправление манифеста (SxS) — только классические приложения (не приложения UWP). Вы можете перенаправлять с помощью манифеста приложения (также известного как параллельный манифест приложения или манифест fusion). Дополнительные сведения см. в разделе Манифесты.
  • Список загруженных модулей. Система может проверить, загружена ли библиотека DLL с тем же именем модуля в память (независимо от того, из какой папки она была загружена).
  • Известные библиотеки DLL. Если библиотека DLL входит в список известных библиотек DLL для версии Windows, в которой выполняется приложение, система использует свою копию известной библиотеки DLL (и зависимые библиотеки DLL, если таковые есть). Список известных библиотек DLL в текущей системе см. в разделе HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLsреестра .

Если библиотека DLL имеет зависимости, система ищет зависимые библиотеки DLL, как если бы они были загружены, используя только имена модулей. Это верно, даже если первая библиотека DLL была загружена путем указания полного пути.

Порядок поиска упакованных приложений

Когда упаковаемое приложение загружает упакованный модуль (в частности, модуль библиотеки — .dll файл) путем вызова функции LoadPackagedLibrary , библиотека DLL должна находиться в графе зависимостей пакета процесса. Дополнительные сведения см. в разделе LoadPackagedLibrary. Когда упаковаемое приложение загружает модуль другими способами и не указывает полный путь, система выполняет поиск библиотеки DLL и ее зависимостей во время загрузки, как описано в этом разделе.

Когда система ищет модуль или его зависимости, она всегда использует порядок поиска для упакованных приложений; даже если зависимость не является упакованным кодом приложения.

Стандартный порядок поиска для упакованных приложений

Система выполняет поиск в следующем порядке:

  1. Перенаправление DLL.
  2. Наборы API.
  3. Только классические приложения (не приложения UWP). Перенаправление манифеста SxS.
  4. Список загруженных модулей.
  5. Известные библиотеки DLL.
  6. Граф зависимостей пакета процесса. Это пакет приложения и все зависимости, указанные в <PackageDependency><Dependencies> разделе манифеста пакета приложения. Поиск зависимостей выполняется в порядке их отображения в манифесте.
  7. Папка, из которую был загружен вызывающий процесс (папка исполняемого файла).
  8. Системная папка (%SystemRoot%\system32).

Если библиотека DLL имеет зависимости, система ищет зависимые библиотеки DLL так, как если бы они были загружены только с именами модулей (даже если первая библиотека DLL была загружена путем указания полного пути).

Альтернативный порядок поиска для упакованных приложений

Если модуль изменяет стандартный порядок поиска путем вызова функции LoadLibraryEx с LOAD_WITH_ALTERED_SEARCH_PATH, то порядок поиска совпадает со стандартным порядком поиска, за исключением того, что на шаге 7 система выполняет поиск в папке, из которую был загружен указанный модуль (папка модуля с верхней загрузкой), а не в папке исполняемого файла.

Порядок поиска неупакованных приложений

Когда неупакованное приложение загружает модуль и не указывает полный путь, система выполняет поиск библиотеки DLL во время загрузки, как описано в этом разделе.

Важно!

Если злоумышленник получает контроль над одним из каталогов, в которые выполняется поиск, он может поместить вредоносную копию библиотеки DLL в этой папке. Способы предотвращения таких атак см. в статье Безопасность библиотеки динамической компоновки.

Стандартный порядок поиска для неупакованных приложений

Стандартный порядок поиска DLL, используемый системой, зависит от того, включен ли безопасный режим поиска DLL .

Безопасный режим поиска DLL (который включен по умолчанию) перемещает текущую папку пользователя позже в порядке поиска. Чтобы отключить безопасный режим поиска DLL, создайте HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode значение реестра и задайте для него значение 0. Вызов функции SetDllDirectory фактически отключает безопасный режим поиска DLL (в то время как указанная папка находится в пути поиска) и изменяет порядок поиска, как описано в этом разделе.

Если включен безопасный режим поиска DLL, порядок поиска выглядит следующим образом:

  1. Перенаправление DLL.
  2. API sets.
  3. SxS manifest redirection.
  4. Loaded-module list.
  5. Known DLLs.
  6. Windows 11, версия 21H2 (10.0; Сборка 22000) и более поздних версий. The package dependency graph of the process. This is the application's package plus any dependencies specified as <PackageDependency> in the <Dependencies> section of the application's package manifest. Dependencies are searched in the order they appear in the manifest.
  7. Папка, из которой загружено приложение.
  8. Системная папка. Используйте функцию GetSystemDirectory , чтобы получить путь к этой папке.
  9. 16-разрядная системная папка. Нет функции, которая получает путь к этой папке, но выполняется поиск.
  10. Папка Windows. Используйте функцию GetWindowsDirectory , чтобы получить путь к этой папке.
  11. Текущая папка.
  12. Каталоги, перечисленные в переменной PATH среды. Сюда не входит путь для каждого приложения, указанный в разделе реестра Пути приложений . Ключ пути к приложению не используется при вычислении пути поиска DLL.

Если режим безопасного поиска DLL отключен, порядок поиска будет таким же, за исключением того, что текущая папка перемещается из позиции 11 в позицию 8 последовательности (сразу после шага 7). Папка, из которой загружено приложение).

Альтернативный порядок поиска для неупакованных приложений

Чтобы изменить стандартный порядок поиска, используемый системой, можно вызвать функцию LoadLibraryEx с LOAD_WITH_ALTERED_SEARCH_PATH. Вы также можете изменить стандартный порядок поиска, вызвав функцию SetDllDirectory .

Примечание

На стандартный порядок поиска процесса также влияет вызов функции SetDllDirectory в родительском процессе до начала текущего процесса.

Если вы укажете альтернативную стратегию поиска, ее поведение будет продолжаться до тех пор, пока не будут удалены все связанные исполняемые модули. После того как система начнет обрабатывать подпрограммы инициализации DLL, система возвращается к стандартной стратегии поиска.

Функция LoadLibraryEx поддерживает альтернативный порядок поиска, если вызов задает LOAD_WITH_ALTERED_SEARCH_PATH, а параметр lpFileName задает абсолютный путь.

  • Стандартная стратегия поиска начинается (после начальных шагов) в папке вызывающего приложения.
  • Альтернативная стратегия поиска, указанная в loadLibraryEx с LOAD_WITH_ALTERED_SEARCH_PATH , начинается (после начальных шагов) в папке исполняемого модуля, загружаемого LoadLibraryEx .

Это единственный способ, которым они отличаются.

Если включен безопасный режим поиска DLL, альтернативный порядок поиска выглядит следующим образом:

Шаги 1–6 совпадают со стандартным порядком поиска.

  1. Папка, указанная lpFileName.
  2. The system folder. Use the GetSystemDirectory function to retrieve the path of this folder.
  3. The 16-bit system folder. There's no function that obtains the path of this folder, but it is searched.
  4. The Windows folder. Используйте функцию GetWindowsDirectory , чтобы получить путь к этой папке.
  5. Текущая папка.
  6. Каталоги, перечисленные в переменной PATH среды. Сюда не входит путь для каждого приложения, указанный в разделе реестра Пути приложений . Ключ пути к приложению не используется при вычислении пути поиска DLL.

Если режим безопасного поиска DLL отключен, альтернативный порядок поиска будет таким же, за исключением того, что текущая папка перемещается из позиции 11 в позицию 8 последовательности (сразу после шага 7). Папка, указанная параметром lpFileName).

Функция SetDllDirectory поддерживает альтернативный порядок поиска, если параметр lpPathName указывает путь. Альтернативный порядок поиска выглядит следующим образом:

Шаги 1–6 совпадают со стандартным порядком поиска.

  1. Папка, из которой загружено приложение.
  2. Папка, указанная параметром lpPathNameобъекта SetDllDirectory.
  3. Системная папка.
  4. 16-разрядная системная папка.
  5. Папка Windows.
  6. Каталоги, перечисленные в переменной PATH среды.

Если параметр lpPathName является пустой строкой, вызов удаляет текущую папку из порядка поиска.

SetDllDirectory фактически отключает безопасный режим поиска DLL, пока указанная папка находится в пути поиска. Чтобы восстановить безопасный режим поиска DLL на основе значения реестра SafeDllSearchMode и восстановить текущую папку в порядке поиска, вызовите Метод SetDllDirectory с lpPathName значением NULL.

Порядок поиска с помощью флагов LOAD_LIBRARY_SEARCH

Порядок поиска можно указать с помощью одного или нескольких флагов LOAD_LIBRARY_SEARCH с функцией LoadLibraryEx . Вы также можете использовать флаги LOAD_LIBRARY_SEARCH с функцией SetDefaultDllDirectories , чтобы установить порядок поиска DLL для процесса. Вы можете указать дополнительные каталоги для порядка поиска в библиотеке DLL процесса с помощью функций AddDllDirectory или SetDllDirectory .

Каталоги, в которых выполняется поиск, зависят от флагов, указанных параметром SetDefaultDllDirectories или LoadLibraryEx. Если используется несколько флагов, поиск в соответствующих каталогах выполняется в следующем порядке:

  1. LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR. Выполняется поиск в папке, содержащей библиотеку DLL. В этой папке выполняется поиск только зависимостей загружаемой библиотеки DLL.
  2. LOAD_LIBRARY_SEARCH_APPLICATION_DIR. Выполняется поиск в папке приложения.
  3. LOAD_LIBRARY_SEARCH_USER_DIRS. Выполняется поиск по путям, явно добавленным с помощью функции AddDllDirectory или SetDllDirectory . При добавлении нескольких путей порядок поиска путей не указан.
  4. LOAD_LIBRARY_SEARCH_SYSTEM32. Выполняется поиск в папке System.

Если вы вызываете LoadLibraryEx без флагов LOAD_LIBRARY_SEARCH или устанавливаете порядок поиска DLL для процесса, система выполняет поиск библиотек DLL с помощью стандартного или альтернативного порядка поиска.