私が気にする100の事象

気にしなければ始まらない。

12021-05-26

昨日の日記(12021年5月26日)です。 天気は雨。 電波は悪い。

今日は皆既日食がありましたが、雨降ったので見れませんでした。

散歩

散歩をしていたら、 虫が[削除済み]をしてました。

私はリア充爆発しろと思いながら、 片手に持ったガスバーナーで、 周りの雑草ごと燃やしました。 楽しかったです。

というのは嘘です。 さすがにそんなことはしません。 だってガスがもったいないものね。

f:id:skytomo:20210527022545j:plain

ナシゴレン

お昼はナシゴレンでした。 おいしかったです。

f:id:skytomo:20210527022654j:plain

exeファイルを読んでみる

C言語で以下のソースコードを、 Visual Studio 2019で、 ターゲットをx64にして、 Releaseモードでビルドしました。

#include <stdio.h>

int main() {
    return 42;
}

簡単なソースコードですね。 それをビルドすると、 10752バイト(約11KB)のexeファイルが生成されました。

で、これ、中身がどうなってるか気になりますよね。 それで今日は一日を潰して中身を見てみました。

それではどうぞ

exeファイルの構造

exeファイルは大まかに以下の構造になっています。

  1. PEファイルヘッダ
    1. MZスタブ
    2. COFFファイルヘッダ
    3. オプションヘッダ
    4. セクションテーブル
  2. プログラムコード
  3. API関数呼び出し用の情報
  4. 変数や文字列などのデータ
  5. アイコンなどのリソース

上から順に雑に見ていきましょう。

PEファイルヘッダ

MZスタブ

   Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
 00000000: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00    MZ..............
 00000010: B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00    8.......@.......
 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 F0 00 00 00    ............p...
 00000040: 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68    ..:..4.M!8.LM!Th
 00000050: 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F    is.program.canno
 00000060: 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20    t.be.run.in.DOS.
 00000070: 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00    mode....$.......
 00000080: 45 DE DD 36 01 BF B3 65 01 BF B3 65 01 BF B3 65    E^]6.?3e.?3e.?3e
 00000090: 08 C7 20 65 0B BF B3 65 BF CE B2 64 02 BF B3 65    .G.e.?3e?N2d.?3e
 000000a0: BF CE B6 64 10 BF B3 65 BF CE B7 64 0B BF B3 65    ?N6d.?3e?N7d.?3e
 000000b0: BF CE B0 64 02 BF B3 65 5A D7 B2 64 03 BF B3 65    ?N0d.?3eZW2d.?3e
 000000c0: 01 BF B2 65 2E BF B3 65 97 CD BB 64 00 BF B3 65    .?2e.?3e.M;d.?3e
 000000d0: 97 CD 4C 65 00 BF B3 65 97 CD B1 64 00 BF B3 65    .MLe.?3e.M1d.?3e
 000000e0: 52 69 63 68 01 BF B3 65 00 00 00 00 00 00 00 00    Rich.?3e........

exeファイルの一番先っちょの部分ですね。 MZスタブといってPEファイルであることの印として(こういうのをシグネチャといいます) 最初に4D 5A(文字列だとMZ)と書かれています。

   Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
 00000000: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00    MZ..............
!          4D 5A <------------------------------------------- Signature

このMZスタブというのは、 MS-DOSで動かすやつ用です。 つまり、MS-DOS上でないところで動かすと、 ここの部分は読み飛ばされます。

あんまりここを読んでも意味がないということですね。

COFFファイルヘッダ

   Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
 000000f0: 50 45 00 00 64 86 06 00 C4 C4 AD 60 00 00 00 00    PE..d...DD-`....
 00000100: 00 00 00 00 F0 00 22 00                            ....p.".

COFFファイルヘッダからが本番です()

中身を見てみましょう。

   Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
 000000f0: 50 45 00 00 64 86 06 00 C4 C4 AD 60 00 00 00 00    PE..d...DD-`....
!          50 45 00 00 <------------------------------------- Signature
!                      64 86 <------------------------------- Machine
!                            06 00 <------------------------- NumberOfSections
!                                  C4 C4 AD 60 <------------- TimeDataTable
!                                              00 00 00 00 <- PointerToSymbolTable
 00000100: 00 00 00 00 F0 00 22 00                            ....p.".
!          00 00 00 00 <------------------------------------- NumberOfSymbols
!                      F0 00 <------------------------------- SizeOfOptionalHeader
!                            22 00 <------------------------- Characteristics
項目 値 (HEX) 意味
Machine 8664 マシンタイプ:AMD64
NumberOfSections 0006 セクションの数:6
TimeDataTable 60ADC4C4 2021-05-26 3:47:16 (UTC)
PointerToSymbolTable 00000000
NumberOfSymbols 00000000
SizeOfOptionalHeader 00F0 オプションヘッダの大きさ:F0
Characteristics 0022 ファイルの属性(後述)

Machineでどのようなマシン上での動作を想定しているのかを表します。 64 86というバイト列ですが、 リトルエンディアンなので実際は8664という16進数の値となります。 これに気づくのに数時間かかりました(アホ)。 8664PE Format - Win32 apps | Microsoft Docs によるとAMD64であることが分かります。

PointerToSymbolTableNumberOfSymbolsについてはよくわかりませんが、 今回はそもそもシンボルの数が0なので特に考えなくていいでしょう。

SizeOfOptionalHeaderはオプションヘッダの大きさを表します。

Characteristicsはファイルの属性を意味し、 22(16進数)という値を持っていますが、 これは2(16進数)と20(16進数)に分けられます。 2進数にすると0010 0010で、 右から2ビット目と6ビット目が立っていますね。 これはそれぞれ IMAGE_FILE_EXECUTABLE_IMAGEIMAGE_FILE_LARGE_ADDRESS_AWARE のフラグが立っていることになります。 IMAGE_FILE_EXECUTABLE_IMAGEは、 イメージ ファイルが有効であり、 実行される可能性があることを意味します。 このフラグがセットされていない場合は、 一般にリンカのエラーらしいです。 IMAGE_FILE_LARGE_ADDRESS_AWAREは、 2GB以上のアドレスを扱えるアプリケーションであることを意味します。

オプションヘッダ

次に来るのがオプションヘッダです。 先程、オプションヘッダの大きさがF0だということがわかったので、 00000100~000001f7の部分であることがわかります。

   Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
 00000100:                         0B 02 0E 1C 00 0E 00 00            ........
 00000110: 00 1E 00 00 00 00 00 00 A4 12 00 00 00 10 00 00    ........$.......
 00000120: 00 00 00 40 01 00 00 00 00 10 00 00 00 02 00 00    ...@............
 00000130: 06 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00    ................
 00000140: 00 70 00 00 00 04 00 00 00 00 00 00 03 00 60 81    .p............`.
 00000150: 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00    ................
 00000160: 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00    ................
 00000170: 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00    ................
 00000180: D4 27 00 00 A0 00 00 00 00 50 00 00 E0 01 00 00    T'.......P..`...
 00000190: 00 40 00 00 5C 01 00 00 00 00 00 00 00 00 00 00    .@..\...........
 000001a0: 00 60 00 00 2C 00 00 00 30 22 00 00 70 00 00 00    .`..,...0"..p...
 000001b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
 000001c0: 00 00 00 00 00 00 00 00 A0 22 00 00 38 01 00 00    ........."..8...
 000001d0: 00 00 00 00 00 00 00 00 00 20 00 00 88 01 00 00    ................
 000001e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
 000001f0: 00 00 00 00 00 00 00 00                            ........

さて、中身を見てみましょう。

   Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
 00000100:                         0B 02 0E 1C 00 0E 00 00            ........
!                                  0B 02 <------------------- Magic
!                                        0E <---------------- MajorLinkerVersion
!                                           1C <------------- MinorLinkerVersion
!                                              00 0E 00 00 <- SizeOfCode
 00000110: 00 1E 00 00 00 00 00 00 A4 12 00 00 00 10 00 00    ........$.......
!          00 1E 00 00 <------------------------------------- SizeOfInitializedData
!                      00 00 00 00 <----------------------- SizeOfUninitializedData
!                                  A4 12 00 00 <------------- AddressOfEntryPoint
!                                              00 10 00 00 <- BaseOfCode
 00000120: 00 00 00 40 01 00 00 00 00 10 00 00 00 02 00 00    ...@............
 00000130: 06 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00    ................
 00000140: 00 70 00 00 00 04 00 00 00 00 00 00 03 00 60 81    .p............`.
 00000150: 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00    ................
 00000160: 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00    ................
 00000170: 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00    ................
 00000180: D4 27 00 00 A0 00 00 00 00 50 00 00 E0 01 00 00    T'.......P..`...
 00000190: 00 40 00 00 5C 01 00 00 00 00 00 00 00 00 00 00    .@..\...........
 000001a0: 00 60 00 00 2C 00 00 00 30 22 00 00 70 00 00 00    .`..,...0"..p...
 000001b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
 000001c0: 00 00 00 00 00 00 00 00 A0 22 00 00 38 01 00 00    ........."..8...
 000001d0: 00 00 00 00 00 00 00 00 00 20 00 00 88 01 00 00    ................
 000001e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
 000001f0: 00 00 00 00 00 00 00 00                            ........

…途中までしか分かりませんでした。 もうちょっと勉強します。

ということで今日はここまで。 ありがとうございました。