Windows DLL名前解決の仕組み - 検索順序とSxS

· · Windows, DLL, ローダー, セキュリティ, Windows開発

Windows でネイティブ DLL を扱う話になると、かなりの頻度で次のような混乱が起きます。

  • LoadLibrary("foo.dll") と書いたら、実際にはどこを見に行くのか
  • 実行ファイルと同じフォルダに置いたのに、なぜ別の DLL が読み込まれるのか
  • System32 が優先されるのか、アプリフォルダが優先されるのか
  • manifest や API set や Known DLLs は、どの段階で効くのか
  • SetDllDirectoryAddDllDirectory を使うと、何が変わるのか
  • DLL 植え込み攻撃や DLL hijacking は、何をすると起きやすいのか

この話は、単に「検索順序を 1 行で覚える」だけでは実務で役に立ちません。 実際には、Windows のローダーは、ファイルシステムを順番に舐める前に、いくつかの特別ルールを先に評価します。

この記事では、Windows での DLL の名前解決を、unpackaged app と packaged app の違い、Known DLLs、loaded-module list、API set、side-by-side manifest、LoadLibraryEx 系 API の影響 まで含めて、実務向けに整理します。 内容は 2026 年 3 月時点 で Microsoft Learn の公開情報を前提にしています。123456789

1. まず結論

先に実務向けの結論だけ並べておきます。

  • Windows の DLL 名前解決は、「まずファイルシステム検索」ではありません。DLL redirection、API set、SxS manifest、loaded-module list、Known DLLs といった要素が、検索順序の前段に入ります。1
  • unpackaged app で safe DLL search mode が有効な標準形では、アプリケーションフォルダは上位 にありますが、その前に上記の特別ルールが評価されます。1
  • DLL をフルパス指定でロードしても、その DLL の依存 DLL までは自動で同じフルパス固定になるわけではありません。依存 DLL はモジュール名だけで検索される扱いになるため、別の場所から解決されることがあります。1
  • Known DLLs は、OS が既知の特定 DLL をシステム側のコピーへ結び付ける仕組みで、通常のアプリ側配置で上書きする話ではありません。1
  • API set は「実体 DLL 名そのもの」ではなく、実装 DLL を隠蔽する仮想エイリアス です。api-ms-win-... のような名前を見て、通常の DLL 検索と同じ感覚で考えると誤解しやすいです。3
  • SetDllDirectory は検索順序を変えるだけでなく、safe DLL search mode を実質的に無効化する 振る舞いを持つため、安易に使うとセキュリティ面で逆効果になることがあります。1
  • 実務では、フルパス指定、SetDefaultDllDirectoriesAddDllDirectoryLoadLibraryExLOAD_LIBRARY_SEARCH_* フラグ を組み合わせて、検索範囲を明示的に狭めるのが安全です。4562

要するに、Windows の DLL 名前解決は「どのフォルダが何番目か」だけではなく、「名前を何に解決する前段ルールがあるか」と「API で検索空間をどう変えたか」で決まる と考えるのが実務的です。

2. DLL の名前解決は「フォルダ探索」の前に前段ルールがある

Microsoft Learn の DLL search order の説明では、DLL のロード時にはまず次のような要素が検索順序の一部として扱われます。1

  1. DLL redirection
  2. API sets
  3. SxS manifest redirection
  4. loaded-module list
  5. Known DLLs

その後で、app folder、System32、Windows フォルダ、PATH などのファイルシステム上の探索に入ります。1

ここを見落とすと、たとえば「アプリフォルダより先に何かが決まるのはおかしい」と感じますが、Windows ローダーの説明としてはむしろそちらが本筋です。

DLL 名を解決したいDLL redirectionAPI setSxS manifest redirectionloaded-module listKnown DLLsファイルシステム上の検索順序実際にロードされる DLL が決まる

3. unpackaged app の標準検索順序

いわゆる普通のデスクトップアプリで、DLL をフルパス指定せずにロードする場合、Microsoft Learn では unpackaged app の標準検索順序が説明されています。safe DLL search mode が有効な既定状態では、主に次の流れです。1

  1. DLL redirection
  2. API sets
  3. SxS manifest redirection
  4. loaded-module list
  5. Known DLLs
  6. Windows 11 21H2 以降では package dependency graph
  7. アプリケーションがロードされたフォルダ
  8. System32
  9. 16-bit system folder
  10. Windows folder
  11. current folder
  12. PATH

実務で特に効いてくるのはこの 3 点です。

  • current folder は既定ではかなり後ろ です。safe DLL search mode により、current folder を前に出しにくくしています。1
  • ただし 後ろにあるから安全という意味ではありません。攻撃者が支配できるディレクトリが検索対象に残っている時点で、DLL preloading の余地は残ります。2
  • Windows 11 21H2 以降では、unpackaged app の検索説明にも package dependency graph が入っています。古い説明だけを覚えていると見落としやすい差分です。1

4. packaged app と unpackaged app は同じではない

Microsoft Learn では、packaged app については別の検索順序が定義されています。packaged app では package dependency graph がより前段で効き、検索の考え方自体が少し違います。1

この差を見落とすと、MSIX 化や Windows App SDK 導入後にこんな混乱が起きます。

  • 開発中の unpackaged 実行では見つかる DLL が、本番 package では見つからない
  • package manifest による依存関係と、昔ながらの PATH 依存が混ざって再現条件が変わる
  • 「Windows の DLL 検索順序はこう」と単一の表だけで説明してしまい、packaged app の挙動差を落とす

記事や設計レビューでは、「packaged app の話か、unpackaged app の話か」 を最初に分けるのが安全です。1

5. Known DLLs と loaded-module list は何をしているのか

DLL の解決で直感に反しやすいのが、loaded-module listKnown DLLs です。

5.1 loaded-module list

Microsoft Learn では、同じモジュール名の DLL がすでにメモリにロードされているか をシステムが確認できると説明されています。1

つまり、ファイルシステム検索の前に、

  • その DLL 名は、すでにロード済みではないか
  • その結果として、今から探しに行く必要自体があるのか

という判定が入ります。

そのため、調査中に「このプロセスでは別フォルダの同名 DLL が先にロード済みだった」という事実を落とすと、再現条件を読み違えます。

5.2 Known DLLs

Known DLLs は、Windows がそのバージョンで既知とみなす DLL の一覧で、HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\KnownDLLs で確認できます。該当する DLL なら、システムはその既知 DLL のコピーを使います。1

ここで大事なのは、Known DLLs は「一般アプリが同名 DLL をアプリフォルダへ置けば勝てる」種類の話ではない という点です。 System32 との単純な先着争いとして理解すると、挙動を誤解します。

6. API set は「実体 DLL 名」ではなく契約名

api-ms-win-core-... のような名前を見ると、つい「その DLL ファイルをどこから探すのか」と考えがちです。ですが Microsoft Learn では、API set は物理 DLL への仮想エイリアスであり、実装と契約を分離する仕組みだと説明されています。3

つまり、

  • API set 名 = そのまま物理 DLL ファイル名
  • API set の解決 = 通常 DLL と同じファイル探索

と考えるのは不正確です。

API set の考え方を入れておくと、

  • Windows のバージョンやデバイス種別で実装 DLL 名が違っても整合する
  • 呼び出し側は「どのホスト DLL が実装しているか」を固定で知らなくてよい

という説明がしやすくなります。3

7. manifest と side-by-side (SxS) は DLL versioning 問題への別解

DLL redirection や SxS manifest は、単なる検索順序の小技ではなく、DLL versioning の衝突を避けるための仕組み として説明されています。789

Microsoft Learn では、

  • manifest は side-by-side assembly や isolated application を記述する XML
  • side-by-side assembly は命名、binding、versioning、deployment の単位
  • manifest に記された依存関係で、どのバージョンへ bind するかをローダーが判断する

という整理です。89

そのため、実務ではこの 3 つを分けて考える必要があります。

  • 単に private DLL を app folder に置く話
  • .local などの DLL redirection を使う話
  • manifest による side-by-side binding を使う話

どれも「DLL の解決に影響する」点では近いですが、設計意図は同じではありません。

8. LoadLibraryExSetDllDirectoryAddDllDirectory で何が変わるか

8.1 SetDllDirectory

SetDllDirectory は検索順序を変えますが、Microsoft Learn では safe DLL search mode を実質的に無効化する と明記されています。1

つまり、「アプリ専用フォルダを 1 つ足したいだけ」のつもりで使っても、結果として current folder の扱いなどを含めた検索空間が変わります。

さらに、親プロセスで SetDllDirectory を呼ぶと、その影響が子プロセス側の標準検索順序にも及ぶことがあります。1

このため、実務では SetDllDirectory を雑に常用するより、

  • SetDefaultDllDirectories
  • AddDllDirectory
  • LoadLibraryExLOAD_LIBRARY_SEARCH_*

に寄せる方が安全です。456

8.2 AddDllDirectory

AddDllDirectory で追加したパスは、LOAD_LIBRARY_SEARCH_USER_DIRS と組み合わせて使います。 Microsoft Learn では、複数追加した場合の検索順序は 未規定 です。15

なので、

  • 複数ディレクトリを追加した
  • その探索順まで厳密に期待した

という設計は避けた方がよいです。

8.3 SetDefaultDllDirectories

SetDefaultDllDirectories は、標準の DLL search path から脆弱になりやすいディレクトリを外し、検索対象を限定するための API として説明されています。4

特に押さえておきたい性質はこの 3 つです。

  • プロセス単位で効く
  • 呼び出し後はプロセスの寿命中継続する
  • 一度設定した標準検索パスを、そのまま元の標準形へ戻すことはできない

セキュリティ面を考えるなら、「起動直後に安全寄りの検索空間へ寄せる」設計が取りやすい API です。4

8.4 LoadLibraryEx

LoadLibraryEx は、LOAD_WITH_ALTERED_SEARCH_PATHLOAD_LIBRARY_SEARCH_* フラグで検索挙動を変えられます。61

実務的には、

  • 依存 DLL を含めて、ロード元 DLL のフォルダも探索対象にしたい
  • アプリフォルダ、System32、明示追加したユーザーディレクトリだけに絞りたい

といった要求に対応しやすい API です。

9. フルパス指定しても依存 DLL までは固定されない

このテーマで実務上かなり重要なのに見落とされやすいのがここです。 Microsoft Learn では、最初の DLL をフルパス指定でロードしても、その DLL の依存 DLL はモジュール名だけで検索される と説明されています。14

つまり、

  • C:\\MyApp\\plugins\\foo.dll を明示ロードした
  • だから foo.dll が依存する bar.dll も同じフォルダから必ず取られる

とは限りません。

この誤解があると、

  • 開発環境では動く
  • 配布先では別の bar.dll が解決される
  • 依存 DLL の衝突が再現環境依存になる

という、少し厄介な障害になります。

10. DLL preloading / hijacking を避けるには

Microsoft Learn の DLL security では、フルパスなしの動的ロードと、攻撃者が支配できる検索対象ディレクトリの組み合わせが、DLL preloading attack や binary planting attack につながると説明されています。2

実務では、この基本形に寄せると考えやすいです。

  • LoadLibrary("foo.dll") のような裸の名前ロードを減らす
  • 必要ならフルパス指定を使う
  • プロセス既定の検索パスを SetDefaultDllDirectories で絞る
  • 明示的に許可したディレクトリだけ AddDllDirectory で追加する
  • LOAD_LIBRARY_SEARCH_SYSTEM32LOAD_LIBRARY_SEARCH_APPLICATION_DIRLOAD_LIBRARY_SEARCH_USER_DIRS などを使って探索範囲を明示する
  • current folder や不用意な PATH 依存を避ける

特に、管理者権限で動くプロセスが曖昧な検索パスを持つ 状況は危険です。Microsoft Learn でも、悪意ある DLL がロードされると、その DLL はそのプロセスの権限で実行されると説明されています。2

11. 実務での判断チェックリスト

Windows で DLL ロード設計をレビューする時は、最低限、以下を確認すると事故が減ります。

  1. そのアプリは packaged app か unpackaged app か
  2. どの DLL が静的リンク由来で、どれが動的ロードか
  3. フルパス指定か、モジュール名だけか
  4. SetDllDirectory を使っていないか
  5. SetDefaultDllDirectoriesLOAD_LIBRARY_SEARCH_* を使える構成か
  6. AddDllDirectory を複数使っていて、順序依存を暗黙に期待していないか
  7. manifest / SxS / private DLL / redirection のどれで依存関係を管理しているか
  8. current folder や PATH にセキュリティ上の弱い前提がないか
  9. 依存 DLL が別環境で別の場所から解決されないか

この 9 点を分けて確認すると、「DLL が見つからない」「違う DLL が読まれた」「本番だけ起動しない」「脆弱性レビューで止まる」といった問題を、かなり前段で潰せます。

12. まとめ

Windows での DLL の名前解決は、単なる「フォルダの探索順」ではありません。 実際には、DLL redirection、API set、SxS manifest、loaded-module list、Known DLLs、そして API 呼び出しで変更される検索空間 が重なって決まります。134

実務で一番大事なのは、この 5 つに尽きます。

  • 検索順序を 1 枚の表として暗記しない
  • packaged / unpackaged を分ける
  • フルパス指定でも依存 DLL は別扱いになりうると理解する
  • SetDllDirectory を安易に使わない
  • 安全側へ寄せるなら SetDefaultDllDirectoriesLoadLibraryEx の検索フラグを使う

DLL 名の解決は、起動障害、環境差異、セキュリティ問題がまとめて表面化しやすい場所です。 だからこそ、「Windows がどの順番で探すか」だけでなく、「Windows がそもそも何を名前解決の前提として扱っているか」まで理解しておく価値があります。

References

  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, accessed March 24, 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, accessed March 24, 2026  2 3 4 5

  3. Microsoft Learn, Windows API sets, accessed March 24, 2026  2 3 4 5

  4. Microsoft Learn, SetDefaultDllDirectories function, accessed March 24, 2026  2 3 4 5 6 7

  5. Microsoft Learn, AddDllDirectory function, accessed March 24, 2026  2 3 4

  6. Microsoft Learn, LoadLibraryEx function, accessed March 24, 2026  2 3 4

  7. Microsoft Learn, Dynamic-link library redirection, accessed March 24, 2026  2

  8. Microsoft Learn, Manifests, accessed March 24, 2026  2 3

  9. Microsoft Learn, About Side-by-Side Assemblies, accessed March 24, 2026  2 3

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る