【図解】DLLとは?Windowsの共有部品の仕組みと、DLLハイジャックが起きる理由

障害の調査やセキュリティのアラートを見ていると、「.dll」という拡張子のファイルがよく出てきます。「このDLLが読み込めない」「怪しいDLLが読み込まれた」「DLLハイジャック」といった具合です。

ただ、そもそもDLLが何で、OSの中でいつ使われているのかを、順序立てて説明できる人は意外と多くありません。この記事では、DLLの基本的な仕組みを図で整理し、そのうえで、DLLハイジャックがなぜ起きるのかを説明します。

先に仕組みを理解しておくと、DLLハイジャックは「特別な攻撃」ではなく、DLLの探し方の性質を突いたものだと分かります。

ご利用にあたって
  • 本記事は2026年10月12日時点で公開されている情報をもとにした、個人の見解を含む解説です。内容の正確性や完全性を保証するものではありません。
  • OSのバージョンや設定によって、挙動が異なる場合があります。実際の設定や設計の際は、必ずマイクロソフトの最新の資料を確認してください。
  • 図は理解のためのイメージです。攻撃の手順の詳細を示すものではなく、防御の理解を目的としています。

関連する記事:【図解】EDRとは?ウイルス対策ソフト(EPP)との違いと、不審な動きを見つける仕組み

この記事でわかること
  1. DLLとは何か。EXEとの関係と、「共有の部品」と呼ばれる理由
  2. メモリ上でDLLがどう共有されるか
  3. DLLが読み込まれる2つの方式と、読み込みの流れ
  4. OSの中で、どんなDLLが、どんなときに使われているか
  5. DLLの探索順序と、DLLハイジャックが起きる理由、対策

DLLとは何か

DLL(Dynamic-Link Library)は、複数のプログラムで共通して使うコードやデータをまとめたファイルです。Windowsのプログラムは、必要な機能をDLLから「借りて」動いています。

共有の工具箱と考える

工具に例えると分かりやすくなります。ドライバーやレンチを、作業のたびに自分の道具箱へ買い揃えるのが「静的リンク」です。同じ工具が、作業の数だけ増えます。

共有の作業場に工具箱を1つ置いておき、必要なときに借りて使うのが「動的リンク」で、この共有の工具箱がDLLです。

静的リンク:部品を各アプリに入れるアプリA部品アプリB部品アプリC部品同じ部品がアプリの数だけ入る部品を直すと、アプリごとに作り直し動的リンク:部品を共有するアプリAアプリBアプリC共有のDLL(1つだけ)部品は1つ。使うアプリが必要なときに借りる部品を直せば、使うアプリ全部に効く
図1 静的リンクと動的リンクの違い
項目静的リンク動的リンク(DLL)
部品の置き場所各アプリの中にコピーされる別のファイル(DLL)に置かれ、共有される
部品を直したとき使うアプリを、それぞれ作り直す関数の引数や戻り値が変わらなければ、アプリの作り直しは不要
メモリアプリごとに部品が載る同じDLLのコードは、物理メモリ上で共有される
弱点ファイルが大きくなるDLLが見つからないと、アプリが動かない

動的リンクには、メモリの節約と更新のしやすさに加えて、異なるプログラミング言語で書かれたプログラムが同じ関数を使える、という利点もあります。呼び出しの約束事(呼び出し規約)が合っていればよいためです。

一方で、アプリが自分だけで完結しない、という弱点もあります。必要なDLLがなければ、アプリは起動に失敗します。この「必要なものが見つからない/別のものが見つかる」という性質が、あとで出てくるDLLハイジャックの背景になります。

DLLの中身:エクスポートとインポート

DLLは、EXEと同じ「PE形式」のファイルです。EXEが「実行を始める入口」を持つのに対し、DLLは「他のプログラムが呼べる関数の一覧(エクスポート)」を持ちます。

一方、EXEや別のDLLは、「どのDLLのどの関数を使うか」の一覧(インポート)を持っています。OSが、この2つを突き合わせて、アプリがDLLの関数を呼べるようにします。

実行ファイル(exe)インポート(使う関数の一覧)kernel32.dll のCreateFileW を使うDLL(kernel32.dll)エクスポート(提供する関数の一覧)CreateFileW、ReadFile などを提供する起動時に結びつけるexeの「使う関数の一覧」と、DLLの「提供する関数の一覧」を、OSが突き合わせます
図2 EXEのインポートと、DLLのエクスポートを結びつける

DLLの中身は、関数だけではありません。データやアイコン、文字列などのリソースを入れたDLLもあります。

メモリの中でDLLはどう共有されるのか

プロセスがDLLを読み込むと、DLLはそのプロセスの仮想アドレス空間に配置されます。そのうえで、同じDLLを同じアドレスで読み込んだ複数のプロセスは、物理メモリ上の1つのコピーを共有します。

プロセスAの仮想メモリアプリ本体DLLのデータ(自分用)DLLのコードプロセスBの仮想メモリDLLのコードDLLのデータ(自分用)アプリ本体物理メモリAの本体AのデータDLLのコード(1つだけ)BのデータBの本体コードは共有。データは、プロセスごとに自分用のコピー
図3 メモリ上でのDLLの共有(コードは共有、データは別々)

共有されるのは、実行するコードの部分です。DLLの中にある変数(グローバル変数など)は、既定ではプロセスごとに別のコピーを持ちます。あるプロセスが書き換えた値が、別のプロセスに見えてしまうことはありません。

また、DLLの関数は、それを呼んだスレッドの中で動きます。DLLのコードが確保するメモリは、呼んだプロセスのメモリです。DLLは、呼び出したアプリの一部として動く、と考えてください。この点は、DLLハイジャックの影響を理解するうえで重要です。

OSは、DLLごとにプロセス単位の参照カウントを持っています。読み込むたびに1増え、プロセスが終了するか、カウントが0になると、そのプロセスの空間からDLLが外されます。

DLLが読み込まれる流れ

DLLを読み込む方法には、2つあります。

ロードタイム:起動時にまとめて読み込む

アプリのEXEに、「使うDLLの一覧(インポート)」を持たせておく方式です。アプリを起動するとき、OSのローダーが、必要なDLLを探して読み込みます。

利用者OSローダーDLLアプリ本体① アプリを起動② 必要なDLLを探して読み込む③ DllMain が呼ばれる見つからなければ、起動に失敗する④ アプリの処理を開始
図4 ロードタイム:アプリ起動時のDLLの読み込み(シーケンス図)

この方式では、必要なDLLが1つでも見つからないと、アプリは起動に失敗します。「DLLが見つからない」という内容のエラーで起動に失敗するのは、この状況です。

DLLが読み込まれると、OSは、そのDLLに用意されている入口の関数(DllMain)を呼びます。初期化のための仕組みですが、裏を返すと、DLLが読み込まれた時点で、DLLの中のコードが実行されるということです。覚えておいてください。

ランタイム:必要になったときに読み込む

プログラムが、実行中に、必要になった時点でDLLを読み込む方式です。LoadLibrary という関数でDLLを読み込み、GetProcAddress で関数の場所を取得して呼びます。プラグインの仕組みや、機能を後から追加する場合に使われます。

アプリOSローダーDLL① LoadLibrary で読み込みを依頼② 探して読み込む(DllMain)③ モジュールを返す④ GetProcAddress で関数を取得し、呼ぶ⑤ FreeLibrary(参照カウント −1)
図5 ランタイム:必要なときにDLLを読み込む(シーケンス図)

この方式では、DLLがなくても、アプリはすぐには終了しません。そのDLLの関数が使えないだけで、アプリ側でエラー処理ができます。

項目ロードタイムランタイム
読み込みの時期アプリの起動時必要になったとき
使うDLLの情報EXEのインポートの一覧プログラムが、DLL名を指定して読み込む
DLLがないと起動に失敗するその機能が使えないだけ。アプリ側で対処できる
よく使われる場面OSの標準機能、通常のライブラリプラグイン、機能の後付け

OSの中で使われているDLL

Windowsの標準機能の多くは、DLLを通して提供されています。アプリが画面を描く、ファイルを開く、ネットワークにつなぐといった場面では、裏でDLLが呼ばれています。

アプリケーション(exe)Windows APIのDLL群kernel32 / user32 / gdi32advapi32 / ws2_32 などntdll.dll(カーネルへの入口)Windowsカーネル(OS本体)主なDLLと、担当する仕事kernel32:ファイル・プロセス・メモリuser32:ウィンドウ・メッセージgdi32:画面への描画advapi32:レジストリ・サービス・権限ws2_32:ネットワーク(Winsock)
図6 アプリからOSまで:DLLが担う窓口

アプリは、直接カーネルを呼ぶのではなく、Windows APIのDLL群(kernel32.dll など)を呼びます。その先の処理は、ntdll.dll を経て、OSのカーネルへ渡ります。DLLは、アプリとOSの間にある、標準の窓口の役割を持っています。

代表的なDLLと、使われる場面

DLL主な役割使われる場面の例
kernel32.dllファイル、プロセス、メモリなどの基本機能ファイルの読み書き、プロセスの作成
user32.dllウィンドウやメッセージの管理画面にウィンドウを出す、ボタン操作を受け取る
gdi32.dll画面への描画文字や図形の描画
advapi32.dllレジストリ、サービス、権限など設定の読み書き、サービスの操作
ws2_32.dllネットワーク通信(Winsock)ソケット通信
ntdll.dllカーネルへの入口上のDLLが、内部で呼び出す

DLLの種類(用途別)

種類どんなもの
OS標準のDLLSystem32 などにある、Windowsの機能そのもの(上の表のもの)
ランタイムライブラリC/C++のランタイムなど、アプリが共通で使う部品。アプリと一緒にインストールされることもある
アプリ固有のDLLアプリのフォルダーに置かれた、そのアプリ専用の部品
プラグイン・拡張エクスプローラーの機能拡張、ブラウザやエディタの拡張など、後から差し込まれるもの
リソースのDLLアイコンや文字列など、コードを含まないデータだけのもの
.NETの部品.NETで作られたアプリの部品も、拡張子は .dll

DLLと同じ仕組みのファイルには、拡張子が .ocx や .cpl(コントロールパネルの項目)、.drv のものもあります。いずれも、読み込まれる仕組みはDLLと共通です。

手元のPCで確かめる

実際にどのDLLが読み込まれているかは、コマンドで確認できます。例として、メモ帳(notepad.exe)を起動した状態で実行します。

コマンドプロンプト:プロセスが読み込んでいるDLLの一覧

tasklist /m /fi "IMAGENAME eq notepad.exe"

PowerShell:同じ内容を、パスつきで確認する

(Get-Process notepad).Modules | Select-Object ModuleName, FileName

Visual Studioの開発者向けコマンドプロンプト:EXEが使うDLLと、DLLが提供する関数

dumpbin /dependents C:\Windows\System32\notepad.exe
dumpbin /exports C:\Windows\System32\kernel32.dll

kernel32.dll や ntdll.dll など、OSの標準のDLLが並ぶのが確認できると思います。

DLLはどこから読み込まれるのか

ここからが、DLLハイジャックを理解するための本題です。アプリがDLLを読み込むとき、DLLの名前だけを指定して、場所(フルパス)を指定しないことがあります。その場合、OSは、決まった順序でDLLを探します。

先に確認されるものDLLリダイレクトAPIセットマニフェスト(SxS)ロード済みのモジュールKnownDLLs(OSの正規コピー)見つからなければ、フォルダーを順に探す① アプリのフォルダー(exeの場所)② System32③ 16ビットのシステムフォルダー④ Windowsフォルダー⑤ カレントフォルダー(作業中の場所)⑥ PATHに書かれたフォルダー①⑤⑥は、一般ユーザーが書き込める場所になりうる点に注意
図7 DLLの探索順序(通常のデスクトップアプリ、セーフDLL検索モード有効)

通常のデスクトップアプリで、セーフDLL検索モード(既定で有効)の場合の順序です。まず、リダイレクトやAPIセット、マニフェストでの指定、すでに読み込み済みのモジュール、KnownDLLsといった「特別扱い」が確認されます。それでも決まらない場合に、フォルダーを①から順に探します。

なお、Windows 11(バージョン21H2以降)では、フォルダーの検索の前に、パッケージの依存関係を探す段階が加わります。

KnownDLLs:OSの正規コピーを使う仕組み

KnownDLLsは、OSが「正規のコピー」を持っているDLLの一覧です。レジストリの HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs で確認できます。一覧に載っているDLLは、フォルダーを探す前に、OSが持つコピーが使われます。

コマンドプロンプト:KnownDLLsの一覧を見る

reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs"

つまり、OSの根幹にかかわるDLLは、フォルダーに偽物を置かれても影響を受けにくくなっています。逆に言うと、KnownDLLsに載っていないDLLは、フォルダーの探索の対象になります。

セーフDLL検索モード:カレントフォルダーを後ろへ

カレントフォルダーは、ユーザーが今作業している場所です。ここが探索の先頭近くにあると、ダウンロードしたフォルダーなどに置かれたDLLが読まれやすくなります。そこで、既定のセーフDLL検索モードでは、カレントフォルダーを⑤に下げています。このモードは、Windows XP SP2から既定で有効です。

DLLが別のDLLを必要とするときも、同じ探索が行われます。注意したいのは、最初のDLLをフルパスで読み込んでも、そのDLLが必要とする別のDLLは、名前だけで探される点です。

DLLハイジャックとは

DLLハイジャック(DLLプリロード攻撃、バイナリプランティングとも呼ばれます)は、この探索の性質を使った攻撃です。攻撃者が、本物のDLLよりも先に探される場所に偽のDLLを置き、正規のアプリに読み込ませます。

攻撃者書き込める場所利用者アプリOSローダー① 偽のDLLを置く② アプリを起動③ DLL名だけで読み込み④ 順番に探す⑤ 偽DLLが先に見つかる⑥ 偽DLLを読み込む⑦ DllMain が動き、アプリの権限でコードが実行される
図8 DLLハイジャックの流れ(シーケンス図)

流れを整理します。

  1. 攻撃者が、探索の対象になっているフォルダー(書き込める場所)に、偽のDLLを置く。
  2. 利用者が、そのフォルダーにある正規のアプリを起動する(または、関連するファイルを開く)。
  3. アプリが、DLLの名前だけで読み込みを依頼する。
  4. OSが探索して、本物より先に、偽のDLLを見つけて読み込む。
  5. 偽のDLLの DllMain が動き、アプリの権限で攻撃者のコードが実行される。

ここで、先ほどの「DLLが読み込まれた時点で、中のコードが実行される」「DLLは呼び出したアプリの一部として動く」という2点が効いてきます。偽のDLLは、アプリが持つ権限で動きます。そのアプリが管理者権限で動いていれば、権限の昇格につながります。

成立しやすくなる条件

① 書き込める場所探索の対象フォルダーに一般ユーザーでもファイルを置ける② 先に探される本物のDLLより先に見つかる順番になっている③ 権限や信頼が高い読み込むアプリが管理者権限、または信頼されているこの3つがそろうと、DLLハイジャックが成立しやすくなりますどれか1つを崩せば、攻撃は難しくなります
図9 DLLハイジャックが成立しやすくなる3つの条件

攻撃が成立するのは、アプリがDLLをフルパスで指定せず、名前だけで探している場合です。そして、探索の対象のどこかに、攻撃者が書き込める場所があることが必要です。たとえば、ダウンロードフォルダーや、誰でも書き込める共有フォルダー、一般ユーザーが書き込めるように設定されたアプリのインストール先などです。

なお、読み込まれるDLLに署名があるかどうかは、既定では読み込みの条件になっていません。名前などが合えば、署名のないDLLでも読み込まれます。署名を条件にする設定は、後述する対策で触れます。

代表的なパターン

ひとくちにDLLハイジャックと言っても、いくつかの形があります(MITRE ATT&CKでの整理に沿っています)。

パターン何が起きるか
探索順序の乗っ取り本物のDLLより先に探される場所に、同じ名前の偽のDLLを置く。
ファントムDLLアプリが、実際には存在しないDLLの名前を探している。その名前の偽のDLLを置く。
DLLの差し替え本物のDLLを、同じ名前・同じ場所で偽のものに置き換える。本物も読み込んで、正常に動いているように見せる場合がある。
サイドローディング正規の(署名のある)アプリに、偽のDLLを読み込ませる。信頼されたアプリの中で動くため、検知を避ける目的で使われる。
リモートDLLカレントフォルダーがネットワーク共有などになっているときに、そこにあるDLLを読み込ませる。

被害のイメージ

  • 権限昇格:管理者権限などで動くアプリを経由して、高い権限でコードが実行される。
  • 永続化:アプリが起動するたびに、偽のDLLが読み込まれる。
  • 検知回避:正規のアプリの中で動くため、不審なプロセスとして見えにくい。
補足:ファイルを置かないDLLの悪用

DLLの悪用には、ディスクにファイルを置かず、メモリの上でDLLを読み込ませる手法(リフレクティブDLLインジェクションなど)もあります。これは探索順序を使うDLLハイジャックとは別の話で、ファイルの監視だけでは気づきにくい点が違います。対策としては、メモリ上の挙動を見られるEDRのような仕組みが役立ちます。

対策:DLLハイジャックを防ぐには

先ほどの3つの条件のどれかを崩せば、攻撃は難しくなります。立場ごとに、できることを整理します。

作る側DLLをフルパスで読み込む探す場所をSystem32などに絞る運用する側フォルダーの書き込み権限を絞る保護設定やアプリ制御を使う確かめる側Process Monitorで探索の様子を見るNAME NOT FOUNDの場所を確認する
図10 対策を、立場ごとに整理する

作る側:アプリの設計で防ぐ

  • LoadLibrary などでDLLを読み込むときは、可能な限り、フルパスで指定する。
  • SetDefaultDllDirectories と LOAD_LIBRARY_SEARCH のフラグで、探す場所を、System32やアプリのフォルダーなどに絞る。
  • SetDllDirectory に空の文字列を指定して、カレントフォルダーを探索から外す。プロセスの起動の早い段階で、1回だけ呼ぶ。
  • 通常の探索順序を使う場合は、セーフDLL検索モードが有効なことを確認する。
  • DLLのリダイレクトやマニフェストで、使うDLLを固定する。

運用する側:OSとフォルダーの設定で防ぐ

1つ目は、書き込み権限の見直しです。アプリのインストール先や、アプリが参照する共有フォルダーに、一般ユーザーが書き込める状態になっていないかを確認します。書き込める場所がなければ、偽のDLLを置けません。

2つ目は、プロセスの保護設定(Exploit Protection)の利用です。PowerShellの Set-ProcessMitigation で、アプリごと、またはシステム全体に設定できます。DLLの読み込みに関係する主な項目は、次のとおりです。

設定項目内容
PreferSystem32DLLの探索で、System32を、アプリのフォルダーより先に探す。
MicrosoftSignedOnlyマイクロソフトの署名があるバイナリだけを読み込む。
BlockRemoteImageLoadsネットワーク共有(UNC)など、リモートにあるバイナリの読み込みを拒否する。

これらは、アプリによっては正常な動作を妨げます。いきなり有効にせず、まず監査(Audit)のモードで影響を確認するのが安全です。たとえば PreferSystem32 には、AuditPreferSystem32 が用意されています。

PowerShell:特定のアプリで、監査モードを有効にする

Set-ProcessMitigation -Name example.exe -Enable AuditPreferSystem32

PowerShell:アプリに設定されている保護の状態を確認する

Get-ProcessMitigation -Name example.exe

3つ目は、アプリケーション制御です。許可したバイナリ以外を実行・読み込みさせない仕組みで、偽のDLLが読み込まれること自体を防げます。MITRE ATT&CKでも、緩和策の一つとして挙げられています。

確かめる側:Process Monitorで探索を観察する

自社のアプリが、DLLハイジャックの影響を受けるかどうかは、Sysinternalsの Process Monitor(Procmon)で確かめられます。マイクロソフトの資料に、手順が示されています。

  1. Process Monitor を起動し、フィルターで「Operation is CreateFile」「Operation is LoadImage」と、「Path contains .dll」などを指定する。
  2. プロセス名がprocmon、Operationが IRP_MJ_ や FASTIO_ で始まるもの、Result is SUCCESS などは除外する。
  3. アプリを、特定のフォルダーをカレントにして起動する。たとえば、そのアプリに関連付けられたファイルを開く。
  4. カレントフォルダーなど、怪しい場所からDLLを読もうとしていないかを確認する。
アプリがDLLを探す様子(イメージ・実際の画面ではありません)① アプリのフォルダー\helper.dllNAME NOT FOUND② System32\helper.dllSUCCESS①に偽のhelper.dllを置かれると、本物(②)より先に読み込まれます①が一般ユーザーの書き込める場所かどうかが、見るポイントです
図11 Process Monitorで見るポイント(イメージ)

アプリのフォルダーなど、一般ユーザーが書き込める場所でDLLが見つからず(NAME NOT FOUND)、その後、別の場所で見つかっている場合は、その場所に偽のDLLを置かれると先に読まれる可能性があります。

おわりに

DLLは、アプリで共通して使う部品を、共有するための仕組みです。メモリを節約し、更新をしやすくする一方で、「名前でDLLを探す」という性質を持っています。DLLハイジャックは、この探し方の順序を突いたものです。

DLLの性質そこから生まれる弱点対策の方向
名前でDLLを探す本物より先に、偽のDLLが見つかる。フルパス指定、探索場所の限定
読み込まれると、コードが動く偽のDLLの処理が、アプリの権限で動く。署名や、アプリケーション制御による制限
探索の対象に、書き込めるフォルダーがある攻撃者が、偽のDLLを置ける。書き込み権限の見直し

まずは、自社で使っているアプリのインストール先が、一般ユーザーに書き込める状態になっていないかを確認するところから始めるのが、手軽で効果の大きい一歩です。

参考URL

本記事で参照した公開情報です。内容は、2026年10月12日時点で確認したものです。

DLLの仕組み

セキュリティと対策

コメント