12021-05-26
昨日の日記(12021年5月26日)です。 天気は雨。 電波は悪い。
今日は皆既日食がありましたが、雨降ったので見れませんでした。
散歩
散歩をしていたら、 虫が[削除済み]をしてました。
私はリア充爆発しろと思いながら、 片手に持ったガスバーナーで、 周りの雑草ごと燃やしました。 楽しかったです。
というのは嘘です。 さすがにそんなことはしません。 だってガスがもったいないものね。
ナシゴレン
お昼はナシゴレンでした。 おいしかったです。
exeファイルを読んでみる
C言語で以下のソースコードを、 Visual Studio 2019で、 ターゲットをx64にして、 Releaseモードでビルドしました。
#include <stdio.h> int main() { return 42; }
簡単なソースコードですね。 それをビルドすると、 10752バイト(約11KB)のexeファイルが生成されました。
で、これ、中身がどうなってるか気になりますよね。 それで今日は一日を潰して中身を見てみました。
それではどうぞ
exeファイルの構造
exeファイルは大まかに以下の構造になっています。
- PEファイルヘッダ
- MZスタブ
- COFFファイルヘッダ
- オプションヘッダ
- セクションテーブル
- プログラムコード
- API関数呼び出し用の情報
- 変数や文字列などのデータ
- アイコンなどのリソース
上から順に雑に見ていきましょう。
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進数の値となります。
これに気づくのに数時間かかりました(アホ)。
8664
は
PE Format - Win32 apps | Microsoft Docs
によるとAMD64であることが分かります。
PointerToSymbolTable
とNumberOfSymbols
についてはよくわかりませんが、
今回はそもそもシンボルの数が0なので特に考えなくていいでしょう。
SizeOfOptionalHeader
はオプションヘッダの大きさを表します。
Characteristics
はファイルの属性を意味し、
22(16進数)という値を持っていますが、
これは2(16進数)と20(16進数)に分けられます。
2進数にすると0010 0010で、
右から2ビット目と6ビット目が立っていますね。
これはそれぞれ
IMAGE_FILE_EXECUTABLE_IMAGE
と
IMAGE_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 ........
…途中までしか分かりませんでした。 もうちょっと勉強します。
ということで今日はここまで。 ありがとうございました。