前の日 / 次の日 / 最新

swk's log

2007-10-27 Sat

* ELF ファイルが Linux のものであるか否かを知る方法 [tech] 1 user

【追記】さらにその後,「『7f454c46 01010100 00000000 00000000』の時点でelfファイルであることは判るが,Linuxで作られたかは0x0114バイトは見ないと判らないはず,この人は『バイナリ萌え』ではない!」との突っ込みを頂きました.

Robot.Mとの優雅な平日:バイナリ萌え,再び・・・

0xcafebabe の話を知った大学生の頃,危うくバイナリ萌えの暗黒面に落ちそうになったものの,軽うじて生還して今は普通人として暮らしています.


というわけでバイナリ萌えでない私にとっては,上の「Linuxで作られたかは0x0114バイトは見ないと判らない」はすごく不思議だった.だって ELF って 8 バイト目に OS/ABI あるじゃん.で,ELFOSABI_LINUX (= 0x03) って定義されてるじゃん.そこ見ればいいんじゃないの?

…と思って手近にあった Vine Linux に転がっているバイナリを調べてみると,8 バイト目は軒並 0x00 なのであった.0x00 は ELFOSABI_NONE であり ELFOSABI_SYSV である.で,確かに readelf すると

% readelf -a /bin/ls | grep OS/ABI
  OS/ABI:                            UNIX - System V

と表示されるのであった.むー.

さてそれではどうやって Linux のものだと判定すればよいのか,そしてそれはなぜ「0x0114バイトは見ないと判らない」のか,ちょっと調べてみることにした.

調べたのは file コマンド.

% file /bin/ls
/bin/ls: ELF 32-bit LSB executable, Intel 80386, version 1, for GNU/Linux 2.2.5, dynamically linked (uses shared libs), stripped

てな感じで Linux だと判定してくれるので,きっと何か手がかりがあるだろう.

というわけで FreeBSD の /usr/src/contrib/file/readelf.c あたりを眺めてみると,donote() の中で判定しているようだ.ELF のプログラムヘッダのうち NOTE タイプのものを探して,その先頭 Elf32_Nhdr サイズ分 (ただし 32 ビット ELF の場合.定義は file/readelf.h の中で,実際のサイズは 12 バイト) スキップしたところに 'G', 'N', 'U', '\0' という 4 バイトがあることを確認し,その次の 1 バイトを調べている.そこが 0x00 だったら GNU/Linux であるという判定をしているようだ.ちなみにそこに出てくる値としては

#define GNU_OS_LINUX    0
#define GNU_OS_HURD     1
#define GNU_OS_SOLARIS  2

が定義されている.ちょwww HURD って単語久々にみたわwwwwwwwww

NOTE タイプのプログラムヘッダがどこにあるかというと,

% readelf -a /bin/ls
(略)
Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
(略)
  NOTE           0x000108 0x08048108 0x08048108 0x00020 0x00020 R   0x4
(略)

てな感じになっていて,先頭からのオフセット 0x108 バイトのところから始まるらしい.ここから Elf32_Nhdr 分の 12 バイト進んだ 0x114 の,さらに 'G', 'N', 'U', '\0' の分の 4 バイト進んだところ,つまりオフセット 0x118 バイトのところを見るとようやく Linux かどうかがわかる,という仕組みのようだ.実際に見てみると,

% hexdump -c /bin/ls | grep ^0000110
0000110 001  \0  \0  \0   G   N   U  \0  \0  \0  \0  \0 002  \0  \0  \0

となる.うーん,なるほど.

ついでに書いとくと,NOTE タイプのプログラムヘッダは必ずしも 0x108 から始まるわけじゃなくて,例えば /bin/rpm なんかは

  NOTE           0x000094 0x08048094 0x08048094 0x00020 0x00020 R   0x4

なのであった.つまりオフセット 0xa4 (= 0x94 + 12 + 4) を見る必要があるってことでいいかな?

% hexdump -c /bin/rpm | grep ^00000a0
00000a0   G   N   U  \0  \0  \0  \0  \0 002  \0  \0  \0 002  \0  \0  \0

よさげである.

というわけで,どうやら「Linuxで作られたかは0x0114バイトは見ないと判らないはず,この人は『バイナリ萌え』ではない!」という突っ込みもバイナリ萌えとしてはまだツメが甘いようです.うーむ,バイナリアン恐るべし.ついて行けん.


で,最初の話に戻るんですが,これらのファイルってどうして OS/ABI に ELFOSABI_LINUX を使わないんでしょう? 逆に言うと ELFOSABI_LINUX ってどういうときに使われてるんでしょう? 教えて偉い人.

[ コメントを全部見る / コメントを書く] [ TrackBack ( )] [固定リンク]

* [baby touch] 『あまり使われないのは、システムコールとかの"実装"に依存し... (2007-11-06 21:15:48)

<< 2007-10 >>
SuMoTuWeThFrSa
123456
78910111213
14151617181920
21222324252627
28293031

2012 : 01 02 03 04 05 06 07 08 09 10 11 12
2011 : 01 02 03 04 05 06 07 08 09 10 11 12
2010 : 01 02 03 04 05 06 07 08 09 10 11 12
2009 : 01 02 03 04 05 06 07 08 09 10 11 12
2008 : 01 02 03 04 05 06 07 08 09 10 11 12
2007 : 01 02 03 04 05 06 07 08 09 10 11 12
2006 : 01 02 03 04 05 06 07 08 09 10 11 12
2005 : 01 02 03 04 05 06 07 08 09 10 11 12
2004 : 01 02 03 04 05 06 07 08 09 10 11 12
2003 : 01 02 03 04 05 06 07 08 09 10 11 12
2002 : 01 02 03 04 05 06 07 08 09 10 11 12
2001 : 01 02 03 04 05 06 07 08 09 10 11 12
2000 : 01 02 03 04 05 06 07 08 09 10 11 12
1999 : 01 02 03 04 05 06 07 08 09 10 11 12
1998 : 01 02 03 04 05 06 07 08 09 10 11 12
1997 : 01 02 03 04 05 06 07 08 09 10 11 12
1996 : 01 02 03 04 05 06 07 08 09 10 11 12

最終更新時間: 2012-02-13 02:02


Shingo W. Kagami - swk(at)kagami.org