SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Windows実行ファイル「EXE」の謎に迫る

EXEファイルの内部構造(セクション)

Windows実行ファイル「EXE」の謎に迫る 第3回


  • X ポスト
  • このエントリーをはてなブックマークに追加

リソースセクション(.rsrc)

リソースとは

 リソースは、EXEファイルに埋め込まれるアイコンや、ビットマップ画像、音楽など、実行コードに直接的に関係のない特徴的なデータを管理しています。リソースデータとしては、一般的に次のようなデータが書き込まれることがあります。もちろん、この他のデータについては、カスタムリソース(バイナリデータ)という扱いにして、EXEファイル内に埋め込むことができます。

  • ビットマップ
  • アイコン
  • カーソル
  • ダイアログ ボックス デザイン
  • メニュー
  • 文字列

リソースディレクトリテーブル

 リソースセクションは、リソースがどのような構成になっているのかを示すリソースディレクトリテーブル、各リソースの生データが格納されるバイナリ部分の大きく2つに分かれます。

 まずはリソースの全体構造を示すためのリソースディレクトリを説明します。リソースディレクトリは3階層のツリー構造で構成され、各階層には次のようなデータが格納されます。

  • 1階層目 …… データの型
  • 2階層目 …… ID(または名前)
  • 3階層目 …… 言語

 どの階層もディレクトリ表記のフォーマットは同一です。1つの階層のリソースディレクトリは次の構造体で表現できます。

  • IMAGE_RESOURCE_DIRECTORY構造体 …… 各階層の先頭に1つだけ存在します。
  • IMAGE_RESOURCE_DIRECTORY_ENTRY構造体 …… 指定するデータの数だけ存在します。

 これは筆者の感想ですが、リソースセクションにおけるデータ群は、EXEファイル内に存在する各種構造体の中でも、一番理解しにくいものになっています。文章では表現しづらい部分もあるので、大よその構造は以下の図を参考にしてください。

リソースセクションの構造
リソースセクションの構造

 次に、IMAGE_RESOURCE_DIRECTORY構造体の定義内容を示します。

IMAGE_RESOURCE_DIRECTORY構造体
typedef struct _IMAGE_RESOURCE_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    WORD    NumberOfNamedEntries;
    WORD    NumberOfIdEntries;
//  IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;

 Characteristicsは予約されているので0です。TimeDateStampMajorVersionMinorVersionはそれぞれ作成時刻、バージョンになりますが、プログラム的にはほとんど意味を持ちません。多くのアプリケーションでは0を格納しています。

 この構造体で重要なのは、NumberOfNamedEntries、およびNumberOfIdEntriesです。後に続くIMAGE_RESOURCE_DIRECTORY_ENTRY構造体の数を示します。一般的には、各データをIDで識別することが多いため(データの量も少なくて済みます)、NumberOfNamedEntriesに0をセットし、NumberOfIdEntriesに値をセットしているケースを多く見かけます。

 次に、IMAGE_RESOURCE_DIRECTORY_ENTRY構造体の定義内容を示します。

IMAGE_RESOURCE_DIRECTORY_ENTRY構造体
typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
    union {
        struct {
            DWORD NameOffset:31;
            DWORD NameIsString:1;
        };
        DWORD   Name;
        WORD    Id;
    };
    union {
        DWORD   OffsetToData;
        struct {
            DWORD   OffsetToDirectory:31;
            DWORD   DataIsDirectory:1;
        };
    };
} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;

 NameまたはIdには任意のデータを指定できます。任意のデータとは、先ほど解説した階層ごとのデータ型、ID、言語などのことです。

 OffsetToDataには、接続される次の階層のデータの位置をRVAで指定します。上位ビットが1のときは次のデータはリソースディレクトリテーブル内であることが、0のときはリソースデータエントリ(バイナリデータに直結するデータ)であることが示されます。

リソースディレクトリテーブル1階層目(データの型)

 IMAGE_RESOURCE_DIRECTORY_ENTRY構造体のNameメンバには次に挙げる値のいずれかを指定します。

  • RT_CURSOR
  • RT_BITMAP
  • RT_ICON
  • RT_MENU
  • RT_DIALOG
  • RT_STRING
  • RT_FONTDIR
  • RT_FONT
  • RT_ACCELERATOR
  • RT_RCDATA
  • RT_MESSAGETABLE
  • RT_GROUP_CURSOR
  • RT_GROUP_ICON
  • RT_VERSION
  • RT_DLGINCLUDE
  • RT_PLUGPLAY
  • RT_VXD
  • RT_ANICURSOR
  • RT_ANIICON
  • RT_HTML

リソースディレクトリテーブル2階層目(ID)

 ここには、ツリー構造の最終的なリーフを見分けることができる個別のIDを指定します。

リソースディレクトリテーブル3階層目(言語)

 リソースデータの言語を指定します。日本語であれば0x0411を、英語であれば0x409を指定します。

リソースデータエントリ

 リソースデータエントリは、リソースディレクトリテーブルの次に配置されます。各バイナリデータの概要を、IMAGE_RESOURCE_DATA_ENTRY構造体を羅列することで表現しています。

IMAGE_RESOURCE_DATA_ENTRY構造体
typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
    DWORD   OffsetToData;
    DWORD   Size;
    DWORD   CodePage;
    DWORD   Reserved;
} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;

 OffsetToDataには対象となるリソースバイナリの位置をRVAで指定します。Sizeにはそのバイナリのサイズを指定します。CodePageにはコードページの値を指定しますが、あまり使われるシーンはないようです。最後の、Reservedは0を指定します。

バイナリデータ

 3階層からなるリソースディレクトリテーブル、バイナリの位置とサイズを保持するリソースデータエントリを経て、やっと、バイナリデータにたどり着きます。このバイナリデータに、ビットマップやアイコンなどのファイルデータが直接書き込まれることになります。

おわりに

 今回はセクションヘッダと、インポート・リソースなどの実践的なセクションの生データに関する解説を行いました。ここまで本稿を熟読された方、お疲れ様でした。EXEファイルの大まかなデータフォーマットに関しての解説はここで一区切りです。

 ということは、自動的にある1つの目標がチラつくはずです。それは……

 「EXEファイルを自前で生成してしまうモジュールを作ってしまおう!」

 そうです! ここまでご紹介した内容を活用すれば、EXEファイル内に存在する構造体、その他データを自分で作成したプログラムに任意に持たせることができます。それらのデータをファイルに書き込めば完全オリジナルのEXEファイルが生成できるのです。

 次回は、コンパイラでもリンカでもないのにEXEファイルを生成できてしまうという、これまた摩訶不思議なプログラムを自作してみます。ご期待ください!

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Windows実行ファイル「EXE」の謎に迫る連載記事一覧

もっと読む

この記事の著者

山本 大祐(ヤマモト ダイスケ)

普段はActiveBasicと周辺ツールの開発を行っています。最近は諸先輩方を見習いながら勉強中の身。AB開発日記

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/413 2006/07/04 10:20

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング