今回はIMAGE_NT_HEADERSのIMAGE_OPTIONAL_HEADERにあるDataDirectoryメンバの役割です。
これだけでも意外とすごいことができるメンバなのでみると楽しいです。
このメンバの定義は
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 typedef struct _IMAGE_OPIONAL_HEADER32 { ・・・ IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; ・・・ } IMAGE_OPTIONAL_HEADER32;
となっています。IMAGE_DATA_DIRECTORYの構造はとても簡単で
typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY;
です。ただの仮想アドレス(ロードされたデータからのオフセット)とその領域のサイズのペアです。
問題は配列の各要素にどんな意味があるか、ですね。よく使う意味のものだけですが。
- IMAGE_DIRECTORY_ENTRY_EXPORT(0)
DLLなどが外部に公開しているモジュールの情報位置になります。公開していない場合は使用しません。
公開しているときには、序数情報、名前(GetProcAddressのロード処理で使用する)、そのモジュールのエントリアドレスを示します。
- IMAGE_DIRECTORY_ENTRY_IMPORT(1)
自分が使用する外部DLLのロード情報位置になります。
このアドレスの先に自分が使用しているモジュール情報(kernel32.dllのLoadLibraryといったもの)があります。
プログラムのロード時にここを参照して必要なモジュールをロードし、DLLの呼び出し先アドレスを確定させておきます。
この先のデータをちょっといじると対象のモジュールの動きを乗っ取れるわけです。
DLLをカスタムでロードしたときに特定のモジュールの動作を変えないとまずいというときにもロード作業を行ったときに自身のモジュールを指定して・・・ということもできます。
自分自身で自分の・・・というなんか不思議なこともできますが・・・。
- IMAGE_DIRECTORY_ENTRY_RESOURCE(2)
プログラムのリソース情報位置になります。
実行ファイルがアイコンやマニフェストなどを表示できるのは、この先に必要な情報があってそこからWindowsが直接アイコンデータなどを読み出しているからです。
LoadResource系の命令もHINSTANCEからこの領域を参照して必要なリソースのアドレスを見つけ出すという作業をやっています。
- IMAGE_DIRECTORY_ENTRY_BASERELOC(5)
DLLなどで再配置が行われる可能性があるモジュールに対してImageBaseを使った仮想絶対アドレスがある場所を書き換えるための
情報がある場所です。DLLが予想された場所にロードできなかったときはこの情報を使ってロード後にコードアドレスを書き換えることで
正しく動作できるようにします。
使用しないそれぞれのデータはメンバのSizeを0にすることで「データがない」という意味を示します。
さて、次回はいよいよプログラムのメモリ単位である「セクション」のお話です。長かったような短かったような・・・