第 3 回。
今回は IMAGE_OPTIONAL_HEADER をやっつけます。
- IMAGE_OPTIONAL_HEADER
- Magic
- MajorLinkerVersion
- MinorLinkerVersion
- SizeOfCode
- SizeOfInitializedData
- SizeOfUninitializedData
- AddressOfEntryPoint
- BaseOfCode
- BaseOfData
- ImageBase
- SectionAlignment
- FileAlignment
- MajorOperatingSystemVersion
- MinorOperatingSystemVersion
- MajorImageVersion
- MinorImageVersion
- MajorSubsystemVersion
- MinorSubsystemVersion
- Win32VersionValue
- SizeOfImage
- SizeOfHeaders
- CheckSum
- Subsystem
- DllCharacteristics
- SizeOfStackReserve
- SizeOfStackCommit
- SizeOfHeapReserve
- SizeOfHeapCommit
- LoaderFlags
- NumberOfRvaAndSizes
- DataDirectory
- おわり
IMAGE_OPTIONAL_HEADER
typedef struct _IMAGE_OPTIONAL_HEADER { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; 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_HEADER, *PIMAGE_OPTIONAL_HEADER;
長い!
気を取り直してメンバー逐次解説行きます。
Magic
このファイルが 32bit 用か 64bit 用かを表します。
- IMAGE_NT_OPTIONAL_HDR32_MAGIC (0x10b)
- 32bit 用
- IMAGE_NT_OPTIONAL_HDR64_MAGIC (0x20b)
- 64bit 用
dumpbin で見ると、32bit 用の場合は "PE32"、64bit 用の場合は "PE32+" と表示されます。
MajorLinkerVersion
MinorLinkerVersion
このファイルを作成したリンカーのバージョンです。
VC++ 2015 の場合、14.0 とかになります。
SizeOfCode
実行可能なコード セクションのサイズです。
コード セクションが複数ある場合は合計のサイズになります。
SizeOfInitializedData
初期化済みデータ セクションのサイズです。
初期化済みデータ セクションが複数ある場合は合計のサイズになります。
SizeOfUninitializedData
未初期化データ セクションのサイズです。
未初期化データ セクションが複数ある場合は合計のサイズになります。
コード セクションや初期化済みデータ セクションは PE ファイル内にデータがありますが、未初期化データ セクションはファイルに含まれません。
この値は、PE ファイルがロードされるときにメモリ上に確保されるべきサイズ(の合計)を表します。
AddressOfEntryPoint
実行を開始するエントリーポイントのアドレスです。
VC++ ではリンカーオプション /ENTRY で制御できます。
また、/NOENTRY オプションをつけるとこの値は 0 になります。
/ENTRY を指定した場合はその関数のアドレスになりますが、指定しない場合は、通常、main 関数のアドレスにはなりません。
main 関数を実行する前にランタイム ライブラリの初期化などをするコードが埋め込まれるので、エントリーポイントのアドレスは、その初期化ルーチンの開始位置を指します。
逆に言えば、/ENTRY:main などと指定してはいけません。
/ENTRY オプションを指定する場合は、ランタイム ライブラリの初期化などを自分でやる必要があります。
BaseOfCode
実行可能なコードセクションの開始位置を表します。
BaseOfData
初期化済みデータセクションの開始位置を表します。
ImageBase
このファイルがロードされるべき望ましいメモリ上のアドレスを表します。
リンカーオプション /BASE で指定できます。
リンカーオプション /FIXED を指定している場合、このアドレスにロードできないと実行に失敗します。
SectionAlignment
この PE ファイルがメモリ上にロードされた時、各セクションは、SectionAlignment の値の倍数になるアドレスに配置されます。
リンカーオプション /ALIGN で変更できます。
FileAlignment
この PE ファイル中で、各セクションは FileAlignment の値の倍数になるアドレスに配置されています。
現在、単に PE ファイルをメモリマップドファイルとして見ているだけなので、各セクションは FileAlignment に従って配置されています。
これが、EXE ファイルを実行したり、LoadLibrary 関数などを使ってメモリ上にロードされると、各セクションは SectionAlignment の値に従って配置されます。
実行のためにロードする時も、メモリマップドファイルとして読み込まれるのですが、単にバイナリファイルとして読み込む場合と、実行のためにロードする場合では、内容が変化するのも PE ファイルの特徴です。
MajorOperatingSystemVersion
MinorOperatingSystemVersion
この PE ファイルを実行するのに必要となる OS のバージョンです。
が、どうやらこの値は使われていないようです。
MajorImageVersion
MinorImageVersion
この PE ファイルのバージョンです。
リンカーオプション /VERSION で設定することができます。
MajorSubsystemVersion
MinorSubsystemVersion
この PE ファイルを実行するのに必要となるサブシステムのバージョンです。
リンカーオプション /SUBSYSTEM で設定できます。
この値が、Windows の現在のバージョン(Windows 10 であれば 10.0)を上回る場合、この PE ファイルを実行することはできません。
Win32VersionValue
使用されていません。常に 0 です。
SizeOfImage
この PE ファイルをロードしたときにメモリ上に占めるサイズです。
SectionAlignment の値の倍数に丸められます。
ファイルサイズとは異なります。
SizeOfHeaders
この PE ファイル中の全てのヘッダーサイズの合計です。
FileAlignment の値の倍数に丸められます。
CheckSum
この PE ファイルのチェックサムです。
リンカーオプション /RELEASE を指定すると書き込まれます。
また、PE ファイルを書き換えて、チェックサムを再計算する必要がある場合は、MapFileAndCheckSum 関数や CheckSumMappedFile 関数を利用できます。
Subsystem
この PE ファイルが動作するサブシステムです。
リンカーオプション /SUBSYSTEM で設定できます。
以下のような値が定義されています。
- IMAGE_SUBSYSTEM_UNKNOWN (0)
- 不明
- IMAGE_SUBSYSTEM_NATIVE (1)
- サブシステム無し
- IMAGE_SUBSYSTEM_WINDOWS_GUI (2)
- Windows GUI アプリケーション
- IMAGE_SUBSYSTEM_WINDOWS_CUI (3)
- Windows CUI(コンソール)アプリケーション
- IMAGE_SUBSYSTEM_OS2_CUI (5)
- OS/2
- IMAGE_SUBSYSTEM_POSIX_CUI (7)
- POSIX
- IMAGE_SUBSYSTEM_WINDOWS_CE_GUI (9)
- Windows CE
- IMAGE_SUBSYSTEM_EFI_APPLICATION (10)
- EFI アプリケーション
- IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER (11)
- EFI ブート サービス ドライバー
- IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER (12)
- EFI ランタイム ドライバー
- IMAGE_SUBSYSTEM_EFI_ROM (13)
- EFI ROM
- IMAGE_SUBSYSTEM_XBOX (14)
- XBox
- IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION (16)
- Windows ブート アプリケーション
- IMAGE_SUBSYSTEM_XBOX_CODE_CATALOG (17)
- XBox コード カタログ?
DllCharacteristics
いろいろなフラグです。
- IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA (0x0020)
- 64bit のアドレス空間で ASLR が有効であることを意味します。
- リンカーオプション /HIGHENTROPYVA で有効にできます。
- IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE (0x0040)
- ASLR が有効であることを意味します。
- リンカーオプション /DYNAMICBASE で有効にできます。
- ASLR (Address Space Load Randomization) とは、PE ファイルを毎回ランダムなアドレスにロードすることで、攻撃をしにくくする技術です。Windows Vista から導入されています。
- ASLR が有効な場合、ImageBase は無視されます。
- IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY (0x0080)
- コードのデジタル署名の検査が強制されることを意味します。
- リンカーオプション /INTEGRITYCHECK で有効にできます。
- IMAGE_DLLCHARACTERISTICS_NX_COMPAT (0x0100)
- データ実行防止(DEP)が有効であることを意味します。
- リンカーオプション /NXCOMPAT で制御できます。
- IMAGE_DLLCHARACTERISTICS_NO_ISOLATION (0x0200)
- このファイルがアプリケーション マニフェストを持たないことを意味します。
- リンカーオプション /ALLOWISOLATION で制御できます。
- IMAGE_DLLCHARACTERISTICS_NO_SEH (0x0400)
- この PE ファイルが構造化例外ハンドラーを持たないことを意味します。
- IMAGE_DLLCHARACTERISTICS_NO_BIND (0x0800)
- この PE ファイルがバインドできないことを意味します。
- リンカーオプション /ALLOWBIND で制御できます。
- バインドについてはそのうち取り上げます。
- IMAGE_DLLCHARACTERISTICS_APPCONTAINER (0x1000)
- この PE ファイルが AppContainer 上で実行される必要があることを意味します。
- Windows ストアアプリでは、このフラグが有効になっています。
- リンカーオプション /APPCONTAINER で制御できます。
- IMAGE_DLLCHARACTERISTICS_WDM_DRIVER (0x2000)
- このファイルが WDM ドライバーであることを意味します。
- リンカーオプション /DRIVER:WDM で有効にできます。
- IMAGE_DLLCHARACTERISTICS_GUARD_CF (0x4000)
- 制御フロー ガードが有効であることを意味します。
- リンカー オプション /GUARD で有効にできます。
- IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE (0x8000)
- アプリケーションがターミナル サーバーとの互換性があることを意味します。
- リンカーオプション /TSAWARE で制御できます。
- ターミナル サーバーとは、要するにリモート デスクトップのことですが、一台のマシンに複数ユーザーの同時ログオンを許可する「ユーザーの切り替え」にも、ターミナル サーバーの技術が利用されています。
- このフラグがオフの場合、ターミナル サーバーとの互換性がないこと、つまり、一台のマシンに複数ユーザーが同時にログオンする環境を考慮していないことを意味します。そのため、このようなアプリケーションが動作する際には、ある種の仮想化が行われるようです。
SizeOfStackReserve
この PE ファイルがロードされるときにスタック領域として予約されるサイズです。
リンカーオプション /STACK で指定できます。
SizeOfStackCommit
この PE ファイルがロードされるときにスタック領域として確保されるサイズです。
リンカーオプション /STACK で指定できます。
SizeOfHeapReserve
この PE ファイルがロードされるときにヒープ領域として予約されるサイズです。
リンカーオプション /HEAP で指定できます。
SizeOfHeapCommit
この PE ファイルがロードされるときにヒープ領域として確保されるサイズです。
リンカーオプション /HEAP で指定できます。
LoaderFlags
使用されていません。
NumberOfRvaAndSizes
データ ディレクトリの数です。
通常は 16 です。
DataDirectory
データ ディレクトリです。
IMAGE_DATA_DIRECTORY 構造体の配列になっており、要素数は NumberOfRvaAndSizes で示されます。
データ ディレクトリについては後で詳細に取り上げます。
おわり
アドベント カレンダーの方は埋まったようで何よりです。
この連載はもうちょっと続きます。