IMAGE_OPTIONAL_HEADER32構造体
次は、同じくIMAGE_NT_HEADERS32に定義されている、IMAGE_OPTIONAL_HEADER32構造体について解説します。IMAGE_OPTIONAL_HEADER32構造体の定義内容は次のとおりです。
typedef struct _IMAGE_OPTIONAL_HEADER { // // Standard fields. // WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; // // NT additional fields. // DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
IMAGE_OPTIONAL_HEADER32構造体の各メンバについて
- Magic
- MajorLinkerVersion、MinorLinkerVersion
- SizeOfCode
- SizeOfInitializedData
- SizeOfUninitializedData
- AddressOfEntryPoint
- BaseOfCode
- BaseOfData
- ImageBase
- 0x00400000 …… 一般的なWindowsのEXEファイル
- 0x10000000 …… DLLファイル
- 0x00010000 …… Windows CEのEXEファイル
- SectionAlignment
- FileAlignment
- MajorOperatingSystemVersion、MinorOperatingSystemVersion
- MajorImageVersion、MinorImageVersion
- MajorSubsystemVersion、MinorSubsystemVersion
- SizeOfImage
- SizeOfHeaders
- CheckSum
- Subsystem
- DllCharacteristics
- SizeOfStackReserve、SizeOfStackCommit
- SizeOfHeapReserve、SizeOfHeapCommit
- LoaderFlags
- NumberOfRvaAndSizes
- DataDirectory
Magicにはマジックナンバーとなる値を指定します。何度も繰り返しますが、EXE内部には、シグネチャやマジックナンバーなどを始めとした「お決まりのルール」が多くあります。ここには、0x10Bを指定しておけば間違いありません(MSDNには0x107を指定するとROMイメージになると記載されています)。MajorLinkerVersion、MinorLinkerVersionはリンカのバージョンです。例えば、Visual C++ 6.0などでコンパイルされたEXEファイルは、MajorLinkerVersion=6、MinorLinkerVersion=0などとなっています。SizeOfCodeにはコードセクションのサイズを格納します。コードセクションとは、すなわち、ネイティブコードを保持するセクションのことを言います。SizeOfInitializedDataは初期化されたデータセクションのサイズです。一般的には、int a=10;など、初期値があらかじめ格納されているグローバル変数領域の割り当て用のバッファを「初期化されたデータセクション」とします。SizeOfUninitializedDataは、SizeOfInitializedDataとは逆に、初期化されていないデータセクションのサイズです。多くの場合、0が指定されています。AddressOfEntryPoint、このメンバはかなり重要です。コードセクションのどの位置からプログラムを開始するのかのエントリーポイントを格納します。エントリーポイントは、イメージベースからの相対オフセット値となります。イメージベースについてはImageBaseメンバで解説します。BaseOfCodeはメモリにロードされたときのコードセクションの位置です。ファイル位置ではないので、注意が必要です。BaseOfDataはメモリにロードされたときのデータセクションの位置です。こちらもファイル位置ではないので、注意が必要です。ImageBaseにはイメージベースの値を指定します。イメージベースとは、プロセスメモリ(0x00000000~0xFFFFFFFF)のどの位置にEXEファイルのイメージをロードするのかを取り決めた値です。64KBの倍数でなければならないのですが、一般的なEXEファイルでは0x00400000を指定します。その他、次のような値が指定されることがあります。SectionAlignmentには、各セクションがメモリにロードされるときの境界をバイト単位で指定します。大きすぎるとアライメントを行うためのNULL空間が大きくなってしまうので、0x1000などの適度の値を指定しておきます。SectionAlignmentメンバがメモリ内におけるアライメントを指定したのに対し、FileAlignmentではファイル上のアライメントを指定します。この値も0x1000などとしておくのが一般的ではあるのですが、2KBなどの極小EXEファイルを作りたい場合は、0x100などとすると効果的です。MajorOperatingSystemVersion、MinorOperatingSystemVersionは、必要なOSのバージョンです。OSのバージョンといっても、Windows 2000やWindows XPのみを指定するわけにはいかないので、時代をさかのぼってバージョンを指定しましょう。そもそも、Windows 95で動くアプリケーションはWindows XPで動作しても良いはずです。MajorOperatingSystemVersion=4、MinorOperatingSystemVersion=0となっています。MajorImageVersion、MinorImageVersionはEXEファイルのバージョンです。アプリケーションのバージョンを指定しておけば問題ないでしょう。この値はアプリケーションの動作に支障をきたすことがないため、面倒臭がりなコンパイラを利用すると、デフォルトで0が格納されることがあります。MajorSubsystemVersion、MinorSubsystemVersionはサブシステムのバージョンです。先ほどのOSのバージョンとほとんど同じ意味なので、4.0を指定しておけば間違いありません。ちなみに、Windows XPのサブシステムのバージョンは5.1なので、これよりも大きな値(5.2など)を指定すると、「有効なWin32イメージではありません」というエラーが出て、アプリケーションが起動できなくなります。Visual C++では、「/SUBSYSTEM リンカオプション」で、この値を指定できます。Win32VersionValueはReserveという「将来のために予約されたメンバ」でした。このメンバに関する詳しい資料が見つからないため、定かなことは言えませんが、Win32のバージョン番号を指定するようです。0を指定おいても問題ありません。SizeOfImageはメモリ上にロードされたときのEXEイメージの総バイト数です。Windows 9xではこの値を評価することはあまり無いようなのですが、Windows 2000/XPなどではこの値を元にメモリ確保を行うので、正確な値を指定する必要があります。SizeOfHeadersにはヘッダ情報の総バイト数を指定します。CheckSumにはチェックサムを指定します。一般的なEXEファイルではチェックが行われないので0を指定しておいても問題ありません。ブート時にロードされるものがDLL、DLLサーバーの場合には、正確なチェックサムを指定する必要があるようです。Subsystemには表3で示す値のいずれかを指定します。この値一つでCUI、GUI、またはその他アプリであるのかが決まります。| 名前 | 値 | 説明 |
IMAGE_SUBSYSTEM_UNKNOWN | 0 | 未知のサブシステムです。 |
IMAGE_SUBSYSTEM_NATIVE | 1 | デバイスドライバ、およびWindows NTネイティブのプロセスのために使用されます。 |
IMAGE_SUBSYSTEM_WINDOWS_GUI | 2 | Windowsグラフィカルユーザーインタフェース(GUI)サブシステム内で実行されるイメージです。 |
IMAGE_SUBSYSTEM_WINDOWS_CUI | 3 | Windowsの文字サブシステム内で実行されるイメージです。 |
IMAGE_SUBSYSTEM_POSIX_CUI | 7 | Posix文字サブシステム内で実行されるイメージです。 |
IMAGE_SUBSYSTEM_WINDOWS_CE_GUI | 9 | Windows CE上で実行されるイメージです。 |
DllCharacteristicsはDLL特性に関する値を指定するものですが、一般的には0で問題ないようです。SizeOfStackReserve、SizeOfStackCommitには、それぞれスタックサイズ、コミットするスタックサイズを指定します。ローカル変数などで大きな値を指定するとプログラムが落ちてしまうという現象は、SizeOfStackReserveメンバやSizeOfStackCommitメンバが関係しています。SizeOfHeapReserve、SizeOfHeapCommitには、それぞれローカルヒープスペースのサイズ、コミットするローカルヒープスペースのサイズを指定します。LoaderFlagsは現在は使われていないメンバです。0を指定して問題ありません。NumberOfRvaAndSizesにはIMAGE_OPTIONAL_HEADER32構造体の直下に配置されるデータ ディクショナリエントリの数を指定します。一般的には16です。DataDirectoryにはデータディクショナリを指定します。詳細は次項の「データディクショナリ」で解説しています。