【ELF形式】.interpセクション

前回は、.shstrtabセクションからセクション名を抽出し、セクションヘッダ一覧に代入しました。

オフセット 内容 サイズ 管理セクション名
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"

ところで、0番目のセクションのセクション名は空文字列ですが、これは何なのでしょうか。

0番目のセクションヘッダの内容をダンプしてみると、

$ od -x -A x -j0x114c -N0x28 sample
00114c 0000 0000 0000 0000 0000 0000 0000 0000
*
00116c 0000 0000 0000 0000
001174

40バイトが、すべて0で埋め尽くされていますね。セクション名の.shstrtabにおける位置情報が0ですが、.shstrtabの先頭は"\0"なので、結局空文字列ということになります。また、セクション位置(16バイト目からの4バイト領域の値)も0x0000であり、これはELFヘッダの先頭を指すことになりますが、セクションのサイズ情報(20バイト目からの4バイト領域の値)も0x0000なので、結局「サイズ無し」となり、まったく意味をなさないセクションヘッダとなります。このセクションヘッダは何のためにあるんだろう??

さておき今回からは、30個あるセクションの内容について見てみたいと思います。

まず、0番目のセクションヘッダは「空のセクション情報」なので、とりあえず無視しておきます。

1番目のセクションヘッダについて見てみます。

$ 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
Elf_Shdr バイナリ 項目 バイナリの意味
.sh_name 0x1b セクション名 ".interp"
.sh_type 0x01 セクションのタイプ アプリケーションプログラムの本体領域(SHT_PROGBITS)
.sh_flags 0x02 各種フラグ ロード時にメモリ上に領域確保するセクション(SHF_ALLOC)
.sh_addr 0x08048154 ロード先アドレス -
.sh_offset 0x0154 ELF形式中でのセクションの位置 -
.sh_size 0x0013 セクションのバイトサイズ -
.sh_link 0x00 (セクションのタイプ依存で利用) -
.sh_info 0x00 (同上) -
.sh_addralign 0x01 セクションがメモリにロードされる際のバイトアラインメント -
.sh_entsize 0x00 構造体配列になっているセクションで利用される。配列要素のサイズ -

.interpセクションの内容をダンプしてみます。

$ od -x -A x -w16 -j0x154 -N0x13 sample
000154 6c2f 6269 6c2f 2d64 696c 756e 2e78 6f73
000164 322e 0000
000167

バイナリデータのままだとよく分からないので、readelfコマンドで当該セクションをダンプしてみます。

$ readelf -x0 sample

セクション '.interp' の 十六進数ダンプ:
  0x08048154 2f6c6962 2f6c642d 6c696e75 782e736f /lib/ld-linux.so
  0x08048164 2e3200                              .2.

おお、ASCIIデータだったのですね。でも、「/lib/ld-linux.so.2」って何でしょうか。

$ file /lib/ld-linux.so.2
/lib/ld-linux.so.2: symbolic link to `i386-linux-gnu/ld-2.17.so'
$ file /lib/i386-linux-gnu/ld-2.17.so
/lib/i386-linux-gnu/ld-2.17.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, BuildID[sha1]=0x6121c48261246146c8b05fde9cfc7de3fa0f9148, stripped

/lib/ld-linux.so.2は、/lib/i386-linux-gnu/ld-2.17.soのシンボリックリンクでした。

では、このld-linux.so.2とは何者か?というと、(リンカ・ローダ本によると)実行形式のロードと動的リンクを行うプログラムだそうです。ここは簡易ローダを実装する際に詳しく見ることにして、今は深堀りしないでおきます。

"Understanding ld-linux.so.2"
http://www.cs.virginia.edu/~dww4s/articles/ld_linux.html