DLL hijacking攻撃を受けないアプリケーションを開発するために
(1) LoadLibrary() の引数はフルパスで指定せよ
Windowsにおいて、ライブラリを動的にロードするために用意されているAPIはLoadLibrary()です。その引数として DLL ファイル名だけが指定されていた場合には、前編でも説明したように、あらかじめ定められているディレクトリから順番に探し出そうとします。攻撃者はその挙動を悪用して、攻撃コードを含むDLLを読み込ませようとするのでした。
そのような攻撃を受けないようにするには、完全修飾パスでDLLファイルを指定することが推奨されます。アプリケーションのユーザ側としても、決まったディレクトリにあるDLLが使われると分かっていれば、管理しやすいはずです。
(2) DLL探索リストからカレントディレクトリを削除せよ
LoadLibrary()呼び出しにおいて、カレントディレクトリを検索させないように設定する、という手段も有効です。これは、空文字列を引数に SetDllDirectory()を呼び出すことで実現できます。
ドキュメントファイルをダブルクリックすることでアプリケーションを起動するとき、カレントディレクトリはそのドキュメントファイルが置いてあるディレクトリになっています。そのため、一緒に置いてあるDLLが読み込まれてしまう危険があるのです。アプリケーションでLoadLibrary()を使っている場合には、アプリケーションの初期化処理のなかで、SetDllDirectory("")を呼び出しておきましょう。
(3) DLL探索にSearchPath()は使うな
Windowsでは、SearchPath()という関数を使ってドキュメントファイル(あるいはデータファイル)を探索することができます。この関数は LoadLibrary()とは別の探索ディレクトリリストを持っていることに注意が必要です。
MSDN(英語)のSearchPath()の説明にも、DLLファイルの探索に使うことは推奨しないとの注意書きが記載されています。
The SearchPath function is not recommended as a method of locating a .dll file if the intended use of the output is in a call to the LoadLibrary function. This can result in locating the wrong .dll file because the search order of the SearchPath function differs from the search order used by the LoadLibrary function. If you need to locate and load a .dll file, use the LoadLibrary function.
(http://msdn.microsoft.com/en-us/library/aa365527%28VS.85%29.aspx)
SearchPath()を使ってDLLファイルを探索し、見つけたDLLファイルをLoadLibrary()で読み込む、というような組み合わせになっているコードは危険です。SearchPath()を使わない形に修正する必要があります。
(4) Windows のバージョンチェックに LoadLibrary() を流用するな
アプリケーションによっては、Windowsのバージョンを確認するために LoadLibrary()を使用している場合があります。しかし、この目的のためには専用の関数があるので適切なものを使うべきです。しかも、Windowsのバージョン確認の目的が、特定の機能を使えるかどうかを調べるためであるならば、Windows バージョンをチェックするのではなく、その機能の存在を調べる正しいAPIを使うべきである、と述べられています。
実際、Firefoxなどはこの方法を使っていたようで、Mozillaセキュリティアドバイザリ MFSA2010-52には以下のような記述があります:
Firefoxはプラットフォーム判別の一環として起動時にdwmapi.dllを読み込もうとしますが、Windows XPなどこのライブラリが存在しないシステムでは、Firefoxは引き続き現在のワーキングディレクトリからライブラリを読み込もうとします。攻撃者はこの脆弱性を悪用して、HTMLファイルと悪質なdwmapi.dllのコピーをコンピュータ上の同じディレクトリにダウンロードし、そのHTMLファイルをFirefoxで開くようユーザを仕向け、その結果悪質なコードを実行させることが可能でした。攻撃者が被害者と同じネットワーク上にいた場合、UNCパスを通じて悪質なDLLを読み込ませることも可能でした。
(http://www.mozilla-japan.org/security/announce/2010/mfsa2010-52.html)
(5) 実行可能ファイルの読み込みにも注意
DLL読み込みと同様の注意が必要な場面がもう一つあります。アプリケーションから別のアプリケーションを実行する場合です。このような機能のためにCreateProcess()やShellExecute()などの関数が用意されていますが、DLL読み込みと同様の注意が必要であるとされています。