【ELF形式】セクションヘッダとセクションの関係

今回、セクションヘッダが30個あるという情報を、ELF形式ファイルの先頭から48(0x30)バイト目の位置にある2バイトの情報(e_shnum)から取得しましたが、これはつまり、セクション実体が30個あるということでもあります。

セクションヘッダとは、それに対応するセクションに関するメタ情報(セクションの位置やサイズ)を持つデータです。セクションヘッダとセクションは1対1に対応しています。

セクション0 <==== セクションヘッダ0
セクション1 <==== セクションヘッダ1
セクション2 <==== セクションヘッダ1
セクション28 <==== セクションヘッダ28
セクション29 <==== セクションヘッダ29

上の例では、セクションとセクションヘッダのメモリ上の順番が同じように書いてありますが、セクションヘッダは、ELF形式ファイルの先頭からのオフセットアドレスでセクションを管理しているため、必ずしもセクションヘッダの順番とセクションの順番が一致している必要はありません。

また、セクションヘッダは情報としてセクション名を持ちますが、セクション名の文字列はセクションヘッダにベタに書かれているわけではなく、セクション名を格納する専用セクション(.shstrtab)におけるオフセットアドレスで管理しています。

説明が難しいので、実際の.shstrtabセクションの内容を確認してみます。ELFヘッダより、.shstrtabは「27番目のセクション」であることが分かっていますので、readelfコマンドでセクション番号27を指定(-x27)してダンプしてみます

※セクション番号はゼロベースであることに注意。
※以下ダンプの内容は「セクション」の内容であって「セクションヘッダ」の内容ではないことに注意。この点、しばしば混乱を招く。

$ readelf -x27 sample

セクション '.shstrtab' の 十六進数ダンプ:
  0x00000000 002e7379 6d746162 002e7374 72746162 ..symtab..strtab
  0x00000010 002e7368 73747274 6162002e 696e7465 ..shstrtab..inte
  0x00000020 7270002e 6e6f7465 2e414249 2d746167 rp..note.ABI-tag
  0x00000030 002e6e6f 74652e67 6e752e62 75696c64 ..note.gnu.build
  0x00000040 2d696400 2e676e75 2e686173 68002e64 -id..gnu.hash..d
  0x00000050 796e7379 6d002e64 796e7374 72002e67 ynsym..dynstr..g
  0x00000060 6e752e76 65727369 6f6e002e 676e752e nu.version..gnu.
  0x00000070 76657273 696f6e5f 72002e72 656c2e64 version_r..rel.d
  0x00000080 796e002e 72656c2e 706c7400 2e696e69 yn..rel.plt..ini
  0x00000090 74002e74 65787400 2e66696e 69002e72 t..text..fini..r
  0x000000a0 6f646174 61002e65 685f6672 616d655f odata..eh_frame_
  0x000000b0 68647200 2e65685f 6672616d 65002e69 hdr..eh_frame..i
  0x000000c0 6e69745f 61727261 79002e66 696e695f nit_array..fini_
  0x000000d0 61727261 79002e6a 6372002e 64796e61 array..jcr..dyna
  0x000000e0 6d696300 2e676f74 002e676f 742e706c mic..got..got.pl
  0x000000f0 74002e64 61746100 2e627373 002e636f t..data..bss..co
  0x00000100 6d6d656e 7400                       mment.

というように、実際のセクション名の文字列は、.shstrtabセクション内に

\0 セクション名 \0 セクション名 \0 セクション名 \0 セクション名 \0

というナルターミネートされた状態で格納されています。

現時点で、「27番目のセクションヘッダが管理するのは.shstrtabセクションである」ということが分かっているので、27番目のセクションヘッダに、上の「.shstrtab」の位置情報が本当に格納されているか?確認してみます。

27番目のセクションヘッダのオフセットアドレスは「0x1584」でした。このアドレスをダンプしてみます。

$ od -x -A x -j0x1584 -N0x28 sample
001584 0011 0000 0003 0000 0000 0000 0000 0000
001594 1046 0000 0106 0000 0000 0000 0000 0000
0015a4 0001 0000 0000 0000
0015ac

セクション名の格納位置情報は、セクションヘッダにおける先頭2バイトとなります。上の場合、「0x0011」がそれに当たります。ここから、以下のことが言えます。

「27番目のセクションヘッダは、セクション名の文字列を、.shstrtabの先頭から0x0011(17)バイト目に持っている」

以下を見ると、確かに.shstrtabセクションの先頭17バイト目から「.shstrtab」という文字がセットされています。

  0x00000000 002e7379 6d746162 002e7374 72746162 ..symtab..strtab
  0x00000010 002e7368 73747274 6162002e 696e7465 ..shstrtab..inte

この調子で、他のセクションヘッダからもセクション名の位置情報を取得します。

$ od -x -A x -j0x0000114c -N0x28 sample
00114c 0000 0000 0000 0000 0000 0000 0000 0000
*
00116c 0000 0000 0000 0000
001174
$ od -x -A x -j0x1174 -N0x28 sample
001174 001b 0000 0001 0000 0002 0000 8154 0804
001184 0154 0000 0013 0000 0000 0000 0000 0000
001194 0001 0000 0000 0000
00119c
$ od -x -A x -j0x119c -N0x28 sample
00119c 0023 0000 0007 0000 0002 0000 8168 0804
0011ac 0168 0000 0020 0000 0000 0000 0000 0000
0011bc 0004 0000 0000 0000
0011c4
$ od -x -A x -j0x11c4 -N0x28 sample
0011c4 0031 0000 0007 0000 0002 0000 8188 0804
0011d4 0188 0000 0024 0000 0000 0000 0000 0000
0011e4 0004 0000 0000 0000
0011ec
$ od -x -A x -j0x11ec -N0x28 sample
0011ec 0044 0000 fff6 6fff 0002 0000 81ac 0804
0011fc 01ac 0000 0020 0000 0005 0000 0000 0000
00120c 0004 0000 0004 0000
001214
$ od -x -A x -j0x1214 -N0x28 sample
001214 004e 0000 000b 0000 0002 0000 81cc 0804
001224 01cc 0000 0040 0000 0006 0000 0001 0000
001234 0004 0000 0010 0000
00123c
$ od -x -A x -j0x123c -N0x28 sample
00123c 0056 0000 0003 0000 0002 0000 820c 0804
00124c 020c 0000 0045 0000 0000 0000 0000 0000
00125c 0001 0000 0000 0000
001264
$ od -x -A x -j0x1264 -N0x28 sample
001264 005e 0000 ffff 6fff 0002 0000 8252 0804
001274 0252 0000 0008 0000 0005 0000 0000 0000
001284 0002 0000 0002 0000
00128c
$ od -x -A x -j0x128c -N0x28 sample
00128c 006b 0000 fffe 6fff 0002 0000 825c 0804
00129c 025c 0000 0020 0000 0006 0000 0001 0000
0012ac 0004 0000 0000 0000
0012b4
$ od -x -A x -j0x12b4 -N0x28 sample
0012b4 007a 0000 0009 0000 0002 0000 827c 0804
0012c4 027c 0000 0008 0000 0005 0000 0000 0000
0012d4 0004 0000 0008 0000
0012dc
$ od -x -A x -j0x12dc -N0x28 sample
0012dc 0083 0000 0009 0000 0002 0000 8284 0804
0012ec 0284 0000 0010 0000 0005 0000 000c 0000
0012fc 0004 0000 0008 0000
001304
$ od -x -A x -j0x1304 -N0x28 sample
001304 008c 0000 0001 0000 0006 0000 8294 0804
001314 0294 0000 0023 0000 0000 0000 0000 0000
001324 0004 0000 0000 0000
00132c
$ od -x -A x -j0x132c -N0x28 sample
00132c 0087 0000 0001 0000 0006 0000 82c0 0804
00133c 02c0 0000 0030 0000 0000 0000 0000 0000
00134c 0010 0000 0004 0000
001354
$ od -x -A x -j0x1354 -N0x28 sample
001354 0092 0000 0001 0000 0006 0000 82f0 0804
001364 02f0 0000 0184 0000 0000 0000 0000 0000
001374 0010 0000 0000 0000
00137c
$ od -x -A x -j0x137c -N0x28 sample
00137c 0098 0000 0001 0000 0006 0000 8474 0804
00138c 0474 0000 0014 0000 0000 0000 0000 0000
00139c 0004 0000 0000 0000
0013a4
$ od -x -A x -j0x13a4 -N0x28 sample
0013a4 009e 0000 0001 0000 0002 0000 8488 0804
0013b4 0488 0000 0008 0000 0000 0000 0000 0000
0013c4 0004 0000 0000 0000
0013cc
$ od -x -A x -j0x13cc -N0x28 sample
0013cc 00a6 0000 0001 0000 0002 0000 8490 0804
0013dc 0490 0000 002c 0000 0000 0000 0000 0000
0013ec 0004 0000 0000 0000
0013f4
$ od -x -A x -j0x13f4 -N0x28 sample
0013f4 00b4 0000 0001 0000 0002 0000 84bc 0804
001404 04bc 0000 00b0 0000 0000 0000 0000 0000
001414 0004 0000 0000 0000
00141c
$ od -x -A x -j0x141c -N0x28 sample
00141c 00be 0000 000e 0000 0003 0000 9f08 0804
00142c 0f08 0000 0004 0000 0000 0000 0000 0000
00143c 0004 0000 0000 0000
001444
$ od -x -A x -j0x1444 -N0x28 sample
001444 00ca 0000 000f 0000 0003 0000 9f0c 0804
001454 0f0c 0000 0004 0000 0000 0000 0000 0000
001464 0004 0000 0000 0000
00146c
$ od -x -A x -j0x146c -N0x28 sample
00146c 00d6 0000 0001 0000 0003 0000 9f10 0804
00147c 0f10 0000 0004 0000 0000 0000 0000 0000
00148c 0004 0000 0000 0000
001494
$ od -x -A x -j0x1494 -N0x28 sample
001494 00db 0000 0006 0000 0003 0000 9f14 0804
0014a4 0f14 0000 00e8 0000 0006 0000 0000 0000
0014b4 0004 0000 0008 0000
0014bc
$ od -x -A x -j0x14bc -N0x28 sample
0014bc 00e4 0000 0001 0000 0003 0000 9ffc 0804
0014cc 0ffc 0000 0004 0000 0000 0000 0000 0000
0014dc 0004 0000 0004 0000
0014e4
$ od -x -A x -j0x14e4 -N0x28 sample
0014e4 00e9 0000 0001 0000 0003 0000 a000 0804
0014f4 1000 0000 0014 0000 0000 0000 0000 0000
001504 0004 0000 0004 0000
00150c
$ od -x -A x -j0x150c -N0x28 sample
00150c 00f2 0000 0001 0000 0003 0000 a014 0804
00151c 1014 0000 0008 0000 0000 0000 0000 0000
00152c 0004 0000 0000 0000
001534
$ od -x -A x -j0x1534 -N0x28 sample
001534 00f8 0000 0008 0000 0003 0000 a01c 0804
001544 101c 0000 0004 0000 0000 0000 0000 0000
001554 0004 0000 0000 0000
00155c
$ od -x -A x -j0x155c -N0x28 sample
00155c 00fd 0000 0001 0000 0030 0000 0000 0000
00156c 101c 0000 002a 0000 0000 0000 0000 0000
00157c 0001 0000 0001 0000
001584
$ od -x -A x -j0x1584 -N0x28 sample
001584 0011 0000 0003 0000 0000 0000 0000 0000
001594 1046 0000 0106 0000 0000 0000 0000 0000
0015a4 0001 0000 0000 0000
0015ac
$ od -x -A x -j0x15ac -N0x28 sample
0015ac 0001 0000 0002 0000 0000 0000 0000 0000
0015bc 15fc 0000 0420 0000 001d 0000 002d 0000
0015cc 0004 0000 0010 0000
0015d4
$ od -x -A x -j0x15d4 -N0x28 sample
0015d4 0009 0000 0003 0000 0000 0000 0000 0000
0015e4 1a1c 0000 0241 0000 0000 0000 0000 0000
0015f4 0001 0000 0000 0000
0015fc

表にまとめると、こうなります。

セクション番号 .shstrtab上のセクション名の位置 セクション番号 .shstrtab上のセクション名の位置
0 0x0000 15 0x009e
1 0x001b 16 0x00a6
2 0x0023 17 0x00b4
3 0x0031 18 0x00be
4 0x0044 19 0x00ca
5 0x004e 20 0x00d6
6 0x0056 21 0x00db
7 0x005e 22 0x00e4
8 0x006b 23 0x00e9
9 0x007a 24 0x00f2
10 0x0083 25 0x00f8
11 0x008c 26 0x00fd
12 0x0087 27 0x0011
13 0x0092 28 0x0001
14 0x0098 29 0x0009

つぎに、.shstrtabの内容と位置情報の表を突き合わせて、セクション名を抽出してみます。

$ readelf -x27 sample

セクション '.shstrtab' の 十六進数ダンプ:
  0x00000000 002e7379 6d746162 002e7374 72746162 ..symtab..strtab
  0x00000010 002e7368 73747274 6162002e 696e7465 ..shstrtab..inte
  0x00000020 7270002e 6e6f7465 2e414249 2d746167 rp..note.ABI-tag
  0x00000030 002e6e6f 74652e67 6e752e62 75696c64 ..note.gnu.build
  0x00000040 2d696400 2e676e75 2e686173 68002e64 -id..gnu.hash..d
  0x00000050 796e7379 6d002e64 796e7374 72002e67 ynsym..dynstr..g
  0x00000060 6e752e76 65727369 6f6e002e 676e752e nu.version..gnu.
  0x00000070 76657273 696f6e5f 72002e72 656c2e64 version_r..rel.d
  0x00000080 796e002e 72656c2e 706c7400 2e696e69 yn..rel.plt..ini
  0x00000090 74002e74 65787400 2e66696e 69002e72 t..text..fini..r
  0x000000a0 6f646174 61002e65 685f6672 616d655f odata..eh_frame_
  0x000000b0 68647200 2e65685f 6672616d 65002e69 hdr..eh_frame..i
  0x000000c0 6e69745f 61727261 79002e66 696e695f nit_array..fini_
  0x000000d0 61727261 79002e6a 6372002e 64796e61 array..jcr..dyna
  0x000000e0 6d696300 2e676f74 002e676f 742e706c mic..got..got.pl
  0x000000f0 74002e64 61746100 2e627373 002e636f t..data..bss..co
  0x00000100 6d6d656e 7400                       mment.
セクション番号 .shstrtab上のセクション名の位置 その位置にある文字列
0 0x0000 "\0"
1 0x001b ".interp"
2 0x0023 ".note.ABI-tag"
3 0x0031 ".note.gnu.build-id"
4 0x0044 ".gnu.hash"
5 0x004e ".dynsym"
6 0x0056 ".dynstr"
7 0x005e ".gnu.version"
8 0x006b ".gnu.version_r"
9 0x007a ".rel.dyn"
10 0x0083 ".rel.plt"
11 0x008c ".init"
12 0x0087 ".plt"
13 0x0092 ".text"
14 0x0098 ".fini"
15 0x009e ".rodata"
16 0x00a6 ".eh_frame_hdr"
17 0x00b4 ".eh_frame"
18 0x00be ".init_array"
19 0x00ca ".fini_array"
20 0x00d6 ".jcr"
21 0x00db ".dynamic"
22 0x00e4 ".got"
23 0x00e9 ".got.plt"
24 0x00f2 ".data"
25 0x00f8 ".bss"
26 0x00fd ".comment"
27 0x0011 ".shstrtab"
28 0x0001 ".symtab"
29 0x0009 ".strtab"

と、綺麗に抽出できました。正直ホッとした…(^^;

この表を作成していて細かいことに気づいたのですが、

10 0x0083 ".rel.plt"
12 0x0087 ".plt"

セクション名".plt"は".rel.plt"と別に格納されているのではなく、".rel.plt"の4バイト目を開始位置として抽出しています。バイト数を節約する工夫でしょうか。

最後に、前回作成したELF形式のレイアウトに、今回取得したセクション名を穴埋めしておきます。

オフセット 内容 サイズ 管理セクション名
0x0000114c セクションヘッダ0 28h(40d)バイト "\0"
0x00001174 セクションヘッダ1 28h(40d)バイト ".interp"
0x0000119c セクションヘッダ2 28h(40d)バイト ".note.ABI-tag"
0x000011c4 セクションヘッダ3 28h(40d)バイト ".note.gnu.build-id"
0x000011ec セクションヘッダ4 28h(40d)バイト ".gnu.hash"
0x00001214 セクションヘッダ5 28h(40d)バイト ".dynsym"
0x0000123c セクションヘッダ6 28h(40d)バイト ".dynstr"
0x00001264 セクションヘッダ7 28h(40d)バイト ".gnu.version"
0x0000128c セクションヘッダ8 28h(40d)バイト ".gnu.version_r"
0x000012b4 セクションヘッダ9 28h(40d)バイト ".rel.dyn"
0x000012dc セクションヘッダ10 28h(40d)バイト ".rel.plt"
0x00001304 セクションヘッダ11 28h(40d)バイト ".init"
0x0000132c セクションヘッダ12 28h(40d)バイト ".plt"
0x00001354 セクションヘッダ13 28h(40d)バイト ".text"
0x0000137c セクションヘッダ14 28h(40d)バイト ".fini"
0x000013a4 セクションヘッダ15 28h(40d)バイト ".rodata"
0x000013cc セクションヘッダ16 28h(40d)バイト ".eh_frame_hdr"
0x000013f4 セクションヘッダ17 28h(40d)バイト ".eh_frame"
0x0000141c セクションヘッダ18 28h(40d)バイト ".init_array"
0x00001444 セクションヘッダ19 28h(40d)バイト ".fini_array"
0x0000146c セクションヘッダ20 28h(40d)バイト ".jcr"
0x00001494 セクションヘッダ21 28h(40d)バイト ".dynamic"
0x000014bc セクションヘッダ22 28h(40d)バイト ".got"
0x000014e4 セクションヘッダ23 28h(40d)バイト ".got.plt"
0x0000150c セクションヘッダ24 28h(40d)バイト ".data"
0x00001534 セクションヘッダ25 28h(40d)バイト ".bss"
0x0000155c セクションヘッダ26 28h(40d)バイト ".comment"
0x00001584 セクションヘッダ27 28h(40d)バイト ".shstrtab"
0x000015ac セクションヘッダ28 28h(40d)バイト ".symtab"
0x000015d4 セクションヘッダ29 28h(40d)バイト ".strtab"