詳細はTechNet Magazineを参照。
Address Space Load Randomizationとは、要するに、DLLのロードアドレスをある程度ランダムにすることで、悪意のあるソフトウェアを抑えるという、Vistaから導入された新技術である。
この機能は、PEヘッダ(IMAGE_OPTIONAL_HEADER::DllCharacteristics)に、ビット0x0040(winnt.hではIMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)が立っているイメージについて有効になるものと思われる。
さて、前述のTechNet Magazineには、こうある。
「動的再配置フラグは Windows Vista のすべての DLL と実行可能ファイルに含まれていますが、このフラグを含むイメージのみが再配置されます。これは、レガシ イメージを移動すると、開発者がイメージの読み込み場所に関して行っている内部的な想定に反する可能性があるためです。
」
ところで、皆さんは「DLLのバインド」という機能をご存知だろうか。
ここで紹介したASLRとは対極をなす、「DLLのロードアドレスを事前に決定する」というものだ(正しくは、ロードアドレスの事前決定は「リベース」という作業。バインドは、DLLが特定のアドレスにロードされていると仮定して、DLL内の関数のアドレスを事前決定するもの)。ASLRが行われると、リベースもバインドも意味がなくなってしまう。
リベースは、ロードされるDLLに対して行う作業だが、バインドは、そのDLLをロードする側に対して行う。ロードしたDLLが、期待したアドレスに配置されていなかったり、ロードアドレスは期待した通りでも、DLLのバージョンが違って、関数のオフセットが違ったりすると、バインドはできない。
そこで、ロードしたDLLがバインドしたものかどうかを判断するために、そのDLLのビルド時刻が使われる。
このビルド時刻は、PEファイルのIMAGE_FILE_HEADER::TimeDateStampに、32bitで格納される。故に、ここには2038年問題が存在する。
Microsoftは、64bit Windows用にPEファイル形式を拡張する際に、このフィールドを64bitにすることもできたが、そうしなかった。
それは少なくとも、Microsoftが、2038年までにはDLLのバインドを使わなくなることを意味していた。結果としてそれは、2007年の時点で現実となり、バインドを使っているファイルは「レガシ イメージ」と呼ばれるようになってしまった。
話は唐突に変わるが、.NET Framework上で動く実行ファイルも、EXEやDLLといった形をとる。
.NETにある程度詳しい方であれば、.NET Frameworkにとって重要なのはILとメタデータであるということをご存知だろう。
.NET用ではない、Win32用のネイティブな実行ファイルには、ネイティブコードと、それに関するメタデータが豊富に含まれている(バインドもビルド時刻もその一種だ)。しかし、.NET Frameworkはそれらを使わない。
要するに、.NET用の実行ファイルがEXEやDLLという形態をとる必然性はなく、また、ILによるマルチプラットフォームを謳う上では、Win32用のPEという形式は有害でしかないと言っていい。Unix用の.NETコンパイラであるMonoまでがPEを出力し、実行することに、一体何の意味があるというのか。
また、.NET用のPEファイルは、PEファイルという視点で見る限り、外部のモジュールに、たった1つの関数しかリンクしていない。この点において、.NET PEは、リベースとバインドの恩恵をまったくと言っていいほど受けることができない。
きっと、バインドが決定的に死ぬ2038年ごろには、ネイティブなPEファイルなど存在していないのだろう。Microsoftはそこまで見据えて、タイムスタンプフィールドの拡張をしなかったのかもしれない。
ASLRは、PEファイルに新しい機能をもたらす半面、別の機能の死を加速させた。
.NETにおいては完全に形骸化し切っているPEというフォーマットに、Microsoftがいつまでしがみつくのか、ずいぶん前からひそかに注目している。