読者です 読者をやめる 読者になる 読者になる

PE ファイルについて (5) - IMAGE_DATA_DIRECTORY

第 5 回。
今回は NT ヘッダーの末尾にある IMAGE_DATA_DIRECTORY についての概要編です。

IMAGE_DATA_DIRECTORY

typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;
    DWORD   Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

単純な構造だと侮るなかれ。
ここまではヘッダーの解説でしたが、このデータ ディレクトリはデータ本体編への入口になるのです。

VirtualAddress

メモリ上にロードされた時に、このデータが置かれる位置を示します。
ロードされたイメージの先頭からの相対アドレスです。

Size

このデータのサイズです。

各データディレクトリの意味

IMAGE_OPTIONAL_HEADER の構造を抜粋して再掲します。

typedef struct _IMAGE_OPTIONAL_HEADER {
  // ...
  DWORD                NumberOfRvaAndSizes;
  IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;

DataDirectory は IMAGE_DATA_DIRECTORY 構造体の配列です。
その要素数は IMAGE_NUMBEROF_DIRECTORY_ENTRIES で定義されます。この値は 16 です。
また、NumberOfRvaAndSizes も同じ値になります。

この配列は、その何番目の要素であるかによって、指す先の意味が決まっています。
名前は winnt.h 中で添字につけられた定数名です。

添字 名前 意味
0 IMAGE_DIRECTORY_ENTRY_EXPORT エクスポート情報
1 IMAGE_DIRECTORY_ENTRY_IMPORT インポート情報
2 IMAGE_DIRECTORY_ENTRY_RESOURCE リソース
3 IMAGE_DIRECTORY_ENTRY_EXCEPTION 例外情報
4 IMAGE_DIRECTORY_ENTRY_SECURITY セキュリティ情報
5 IMAGE_DIRECTORY_ENTRY_BASERELOC ベース再配置情報
6 IMAGE_DIRECTORY_ENTRY_DEBUG デバッグ情報
7 IMAGE_DIRECTORY_ENTRY_ARCHITECTURE アーキテクチャ固有の情報
8 IMAGE_DIRECTORY_ENTRY_GLOBALPTR グローバル ポインター
9 IMAGE_DIRECTORY_ENTRY_TLS TLS(Thread Local Storage)
10 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG ロード構成情報
11 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT バインドされたインポート情報
12 IMAGE_DIRECTORY_ENTRY_IAT インポート アドレス テーブル
13 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 遅延インポート情報
14 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR .NET メタデータ
15 (なし) 予約

ImageDirectoryEntryToDataEx

ImageDirectoryEntryToDataEx 関数を使うと、PE ファイル中のデータ ディレクトリが指すデータの場所を取得することができます。

PVOID WINAPI ImageDirectoryEntryToDataEx(
  _In_      PVOID                 Base,
  _In_      BOOLEAN               MappedAsImage,
  _In_      USHORT                DirectoryEntry,
  _Out_     PULONG                Size,
  _Out_opt_ PIMAGE_SECTION_HEADER *FoundHeader
);

Base

対象の PE ファイルのメモリ上のアドレスです。

MappedAsImage

この PE ファイルが LoadLibrary 関数等でロードされている場合は TRUE、単にメモリマップドファイルとしてマップしただけだったり、ReadFile 関数等で読み込んでいる場合は FALSE を指定します。

DirectoryEntry

ディレクトリエントリの添字です。
上記の表の IMAGE_DIRECTORY_ENTRY_XXX を指定します。

Size

指定した領域のサイズが返されます。
IMAGE_DATA_DIRECTORY::Size の値です。

FoundHeader

指定した領域が含まれるセクションを指す IMAGE_SECTION_HEADER の情報が返されます。

戻り値

指定した領域のアドレスが返されます。