【ELF形式】ELFヘッダ(2)

今回は、以下のソースコードコンパイルして、そのバイナリを解析します。

/* sample.c */
  1 #include <stdio.h>
  2 
  3 int main(void)
  4 {
  5     return 0;
  6 }

まずコンパイル

$ gcc sample.c -o sample -Wall

odコマンドで、実行ファイルの先頭にあるELFヘッダ(52バイト)をバイナリダンプしてみます。

$ od -x -w16 -A x -N52 sample
000000 457f 464c 0101 0001 0000 0000 0000 0000
000010 0002 0003 0001 0000 82f0 0804 0034 0000
000020 114c 0000 0000 0000 0034 0020 0009 0028
000030 001e 001b
000034

前回のe_ident[16]とElf32_Ehdr構造体に当てはめてみると、こうなります。

オフセット バイナリ シンボル 項目 値の意味
0x00000000 7f e_ident[0] マジックナンバ 0x7f
0x00000001 45 e_ident[1] マジックナンバ 'E'
0x00000002 4c e_ident[2] マジックナンバ 'L'
0x00000003 46 e_ident[3] マジックナンバ 'F'
0x00000004 01 e_ident[4] ELF32/ELF64の区別 ELF32
0x00000005 01 e_ident[5] 2の補数、リトルエンディアン データ
0x00000006 01 e_ident[6] ELFバージョン 1(current)
0x00000007 00 e_ident[7] OS/ABI UNIX - System V
0x00000008 00 e_ident[8] ABIバージョン 0
0x00000009 00 e_ident[9] パディング -
0x0000000a 00 e_ident[10] パディング -
0x0000000b1 00 e_ident[11] パディング -
0x0000000c 00 e_ident[12] パディング -
0x0000000d 00 e_ident[13] パディング -
0x0000000e 00 e_ident[14] パディング -
0x0000000f 00 e_ident[15] パディング -
0x0000010 0002 e_type ファイルタイプ EXEC(実行可能ファイル)
0x0000012 0003 e_machine マシンアーキテクチャ Intel 80386
0x0000014 00000001 e_version ファイルのバージョン 0x1
0x0000018 080482f0 e_entry 実行開始アドレス(エントリポイント) 0x080482f0
0x000001c 00000034 e_phoff プログラムヘッダテーブルの位置 0x00000034
0x0000020 0000114c e_shoff セクションヘッダテーブルの位置 0x0000114c
0x0000024 00000000 e_flags (未使用) -
0x0000028 0034 e_ehsize ELFヘッダのサイズ(sizeof(Elf_Ehdr)) 52バイト
0x000002a 0020 e_phentsize プログラムヘッダのサイズ(sizeof(Elf_Phdr) 32バイト
0x000002c 0009 e_phnum プログラムヘッダの個数 9個
0x000002e 0028 e_shentsize セクションヘッダのサイズ(sizeof(Elf_Shdr)) 40バイト
0x0000030 001e e_shnum セクションヘッダの個数 30個
0x0000032 001b e_shstrndx セクション名格納用セクションのセクション番号(0ベース) 27

この情報は、readelfコマンドでも確認できます。

$ readelf -h sample
ELF ヘッダ:
  マジック:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  クラス:                            ELF32
  データ:                            2 の補数、リトルエンディアン
  バージョン:                        1 (current)
  OS/ABI:                            UNIX - System V
  ABI バージョン:                    0
  型:                                EXEC (実行可能ファイル)
  マシン:                            Intel 80386
  バージョン:                        0x1
  エントリポイントアドレス:               0x80482f0
  プログラムの開始ヘッダ:          52 (バイト)
  セクションヘッダ始点:          4428 (バイト)
  フラグ:                            0x0
  このヘッダのサイズ:                52 (バイト)
  プログラムヘッダサイズ:            32 (バイト)
  プログラムヘッダ数:                9
  セクションヘッダ:                  40 (バイト)
  セクションヘッダサイズ:            30
  セクションヘッダ文字列表索引:      27

あれ?「セクションヘッダ」という項目名と「セクションヘッダサイズ」という項目名が間違っていますね。セクションヘッダのサイズが40バイトなわけが無い。正しくは「セクションヘッダ→セクションヘッダサイズ」「セクションヘッダサイズ→セクションヘッダ数」ですね。こんなところにバグが…まあいいか。

上の通り、ELFヘッダには、ELFヘッダ自身のサイズ、プログラムヘッダの個数と1個分のサイズ、セクションヘッダの個数と1個分のサイズ、プログラムヘッダの開始位置、セクションヘッダの開始位置などの情報が格納されているので、その情報を手がかりにすると、ELFの全体レイアウトが見えてきます。

オフセット 内容 サイズ
0x00000000 ELFヘッダ 52バイト
0x00000034 プログラムヘッダ0 20h(32d)バイト
0x00000054 プログラムヘッダ1 20h(32d)バイト
0x00000074 プログラムヘッダ2 20h(32d)バイト
0x00000094 プログラムヘッダ3 20h(32d)バイト
0x000000B4 プログラムヘッダ4 20h(32d)バイト
0x000000D4 プログラムヘッダ5 20h(32d)バイト
0x000000F4 プログラムヘッダ6 20h(32d)バイト
0x00000114 プログラムヘッダ7 20h(32d)バイト
0x00000134 プログラムヘッダ8 20h(32d)バイト
0x00000154 各セクション ff8h(4088d)バイト
0x0000114c セクションヘッダ0 28h(40d)バイト
0x00001174 セクションヘッダ1 28h(40d)バイト
0x0000119c セクションヘッダ2 28h(40d)バイト
0x000011c4 セクションヘッダ3 28h(40d)バイト
0x000011ec セクションヘッダ4 28h(40d)バイト
0x00001214 セクションヘッダ5 28h(40d)バイト
0x0000123c セクションヘッダ6 28h(40d)バイト
0x00001264 セクションヘッダ7 28h(40d)バイト
0x0000128c セクションヘッダ8 28h(40d)バイト
0x000012b4 セクションヘッダ9 28h(40d)バイト
0x000012dc セクションヘッダ10 28h(40d)バイト
0x00001304 セクションヘッダ11 28h(40d)バイト
0x0000132c セクションヘッダ12 28h(40d)バイト
0x00001354 セクションヘッダ13 28h(40d)バイト
0x0000137c セクションヘッダ14 28h(40d)バイト
0x000013a4 セクションヘッダ15 28h(40d)バイト
0x000013cc セクションヘッダ16 28h(40d)バイト
0x000013f4 セクションヘッダ17 28h(40d)バイト
0x0000141c セクションヘッダ18 28h(40d)バイト
0x00001444 セクションヘッダ19 28h(40d)バイト
0x0000146c セクションヘッダ20 28h(40d)バイト
0x00001494 セクションヘッダ21 28h(40d)バイト
0x000014bc セクションヘッダ22 28h(40d)バイト
0x000014e4 セクションヘッダ23 28h(40d)バイト
0x0000150c セクションヘッダ24 28h(40d)バイト
0x00001534 セクションヘッダ25 28h(40d)バイト
0x0000155c セクションヘッダ26 28h(40d)バイト
0x00001584 セクションヘッダ27 28h(40d)バイト
0x000015ac セクションヘッダ28 28h(40d)バイト
0x000015d4 セクションヘッダ29 28h(40d)バイト

と、こういうレイアウトになっているようです。