【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)バイト |
と、こういうレイアウトになっているようです。