readelfコマンドの使い方


1 readelfコマンドとは?

ELF(Executable and Linkable Format)ファイルの情報を表示するコマンドです。
ELFファイルかどうかは、fileコマンドで確認できます。

カーネルモジュールに対して、readelfコマンドを実行してみます。
カーネルモジュールはxzで圧縮されているので、fileコマンドに-zオプションを指定します。
ELFファイルであることがわかります。

カーネルモジュール
[root@server ~]# file -z /lib/modules/3.10.0-957.el7.x86_64/kernel/net/ipv4/netfilter/nf_conntrack_ipv4.ko.xz
/lib/modules/3.10.0-957.el7.x86_64/kernel/net/ipv4/netfilter/nf_conntrack_ipv4.ko.xz: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV) (XZ compressed data)

次に実行ファイルに対して、readelfコマンドを実行してみます。
ELFファイルであることがわかります。

実行ファイル
[root@server ~]# file /usr/bin/bc
/usr/bin/bc: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=60e314fae84e986e67cc4b61986bdbfc108a1f86, stripped

次に共有ライブラリに対して、readelfコマンドを実行してみます。
ELFファイルであることがわかります。

共有ライブラリ
[root@server ~]# file /lib64/libc-2.17.so
/lib64/libc-2.17.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked (uses shared libs), BuildID[sha1]=3c61131d1dac9da79b73188e7702bef786c2ad54, for GNU/Linux 2.6.32, not stripped

2 環境

VMware Workstation 15 Player上の仮想マシンを使いました。
仮想マシンのOS版数は以下のとりです。

OS版数
[root@server ~]# cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)

[root@server ~]# uname -r
3.10.0-957.el7.x86_64
コマンドの版数
[root@server ~]# readelf -v
GNU readelf version 2.27-34.base.el7
Copyright (C) 2016 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) any later version.
This program has absolutely no warranty.

3 オプション一覧

[root@server ~]# readelf -h
readelf: 警告: 行なうべき事はありません。
使用法: readelf <option(s)> elf-file(s)
 ELF 形式のファイルの内容に関する情報を表示します
 Options are:
  -a --all               Equivalent to: -h -l -S -s -r -d -V -A -I
  -h --file-header       Display the ELF file header
  -l --program-headers   Display the program headers
     --segments          An alias for --program-headers
  -S --section-headers   Display the sections' header
     --sections          An alias for --section-headers
  -g --section-groups    Display the section groups
  -t --section-details   Display the section details
  -e --headers           Equivalent to: -h -l -S
  -s --syms              Display the symbol table
     --symbols           An alias for --syms
  --dyn-syms             Display the dynamic symbol table
  -n --notes             Display the core notes (if present)
  -r --relocs            Display the relocations (if present)
  -u --unwind            Display the unwind info (if present)
  -d --dynamic           Display the dynamic section (if present)
  -V --version-info      Display the version sections (if present)
  -A --arch-specific     Display architecture specific information (if any)
  -c --archive-index     Display the symbol/file index in an archive
  -D --use-dynamic       Use the dynamic section info when displaying symbols
  -x --hex-dump=<number|name>
                         Dump the contents of section <number|name> as bytes
  -p --string-dump=<number|name>
                         Dump the contents of section <number|name> as strings
  -R --relocated-dump=<number|name>
                         Dump the contents of section <number|name> as relocated bytes
  -z --decompress        Decompress section before dumping it
  -w[lLiaprmfFsoRt] or
  --debug-dump[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,
               =frames-interp,=str,=loc,=Ranges,=pubtypes,
               =gdb_index,=trace_info,=trace_abbrev,=trace_aranges,
               =addr,=cu_index]
                         Display the contents of DWARF2 debug sections
  --dwarf-depth=N        N 以上の深さの DIE を表示しない
  --dwarf-start=N        N 以上の深さの DIE を表示する
  -I --histogram         Display histogram of bucket list lengths
  -W --wide              出力幅が 80 文字を超えることを許可する
  @<file>                オプションを <file> から読み込む
  -H --help              この情報を表示する
  -v --version           readelf のバージョン番号を表示する

4 事前準備

本記事では、readelfの動作確認のため、nf_conntrack_ipv4.koモジュールを使ってみます。
/lib/modules配下から、ワーキングディレクトリにカーネルモジュールをコピーします。

コピー
[root@server ~]# cp /lib/modules/3.10.0-957.el7.x86_64/kernel/net/ipv4/netfilter/nf_conntrack_ipv4.ko.xz .
[root@server ~]# ls nf_conntrack_ipv4.ko.xz
nf_conntrack_ipv4.ko.xz

カーネルモジュールを解凍します。

カーネルモジュールの解凍
[root@server ~]# xz -d nf_conntrack_ipv4.ko.xz
[root@server ~]# ls -l nf_conntrack_ipv4.ko
-rw-r--r--. 1 root root 28701 11月 24 16:22 nf_conntrack_ipv4.ko

5 ELFヘッダを表示する方法(-h)

[root@server ~]# readelf -h nf_conntrack_ipv4.ko
ELF ヘッダ:
  マジック:  7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  クラス:                            ELF64
  データ:                            2 の補数、リトルエンディアン
  バージョン:                        1 (current)
  OS/ABI:                            UNIX - System V
  ABI バージョン:                    0
  型:                                REL (再配置可能ファイル)
  マシン:                            Advanced Micro Devices X86-64
  バージョン:                        0x1
  エントリポイントアドレス:          0x0
  プログラムの開始ヘッダ:            0 (バイト)
  セクションヘッダ始点:              25856 (バイト)
  フラグ:                            0x0
  このヘッダのサイズ:                64 (バイト)
  プログラムヘッダサイズ:            0 (バイト)
  プログラムヘッダ数:                0
  セクションヘッダ:                  64 (バイト)
  セクションヘッダサイズ:            37
  セクションヘッダ文字列表索引:      36

6 セクション一覧を表示する方法(-S)

readelfコマンドを実行してみます。
nf_conntrack_ipv4.koは、37個のセクションから構成されています。

セクション一覧の表示結果
[root@server ~]# readelf -S nf_conntrack_ipv4.ko
37 個のセクションヘッダ、始点オフセット 0x6500:

セクションヘッダ:
  [番] 名前              タイプ           アドレス          オフセット
       サイズ            EntSize          フラグ Link  情報  整列
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .note.gnu.build-i NOTE             0000000000000000  00000040
       0000000000000024  0000000000000000   A       0     0     4
  [ 2] .text             PROGBITS         0000000000000000  00000070
       0000000000000f92  0000000000000000  AX       0     0     16
  [ 3] .rela.text        RELA             0000000000000000  00001008
       0000000000000c90  0000000000000018   I      33     2     8
  [ 4] .init.text        PROGBITS         0000000000000000  00001c98
       00000000000000f8  0000000000000000  AX       0     0     1
  [ 5] .rela.init.text   RELA             0000000000000000  00001d90
       00000000000002a0  0000000000000018   I      33     4     8
  [ 6] .exit.text        PROGBITS         0000000000000000  00002030
       0000000000000051  0000000000000000  AX       0     0     1
  [ 7] .rela.exit.text   RELA             0000000000000000  00002088
       0000000000000108  0000000000000018   I      33     6     8
  [ 8] __ksymtab_gpl     PROGBITS         0000000000000000  00002190
       0000000000000010  0000000000000000   A       0     0     16
  [ 9] .rela__ksymtab_gp RELA             0000000000000000  000021a0
       0000000000000030  0000000000000018   I      33     8     8
  [10] __kcrctab_gpl     PROGBITS         0000000000000000  000021d0
       0000000000000008  0000000000000000   A       0     0     8
  [11] .rela__kcrctab_gp RELA             0000000000000000  000021d8
       0000000000000018  0000000000000018   I      33    10     8
  [12] .rodata           PROGBITS         0000000000000000  00002200
       00000000000001d3  0000000000000000   A       0     0     32
  [13] .rodata.str1.1    PROGBITS         0000000000000000  000023d3
       00000000000000c4  0000000000000001 AMS       0     0     1
  [14] .rodata.str1.8    PROGBITS         0000000000000000  00002498
       00000000000002cd  0000000000000001 AMS       0     0     8
  [15] .smp_locks        PROGBITS         0000000000000000  00002768
       0000000000000004  0000000000000000   A       0     0     4
  [16] .rela.smp_locks   RELA             0000000000000000  00002770
       0000000000000018  0000000000000018   I      33    15     8
  [17] __ksymtab_strings PROGBITS         0000000000000000  00002788
       0000000000000014  0000000000000000   A       0     0     1
  [18] .modinfo          PROGBITS         0000000000000000  000027a0
       00000000000000e8  0000000000000000   A       0     0     32
  [19] __param           PROGBITS         0000000000000000  00002888
       0000000000000020  0000000000000000   A       0     0     8
  [20] .rela__param      RELA             0000000000000000  000028a8
       0000000000000048  0000000000000018   I      33    19     8
  [21] __mcount_loc      PROGBITS         0000000000000000  000028f0
       00000000000000f0  0000000000000000   A       0     0     8
  [22] .rela__mcount_loc RELA             0000000000000000  000029e0
       00000000000002d0  0000000000000018   I      33    21     8
  [23] __versions        PROGBITS         0000000000000000  00002cc0
       0000000000000d00  0000000000000000   A       0     0     32
  [24] .data             PROGBITS         0000000000000000  000039c0
       0000000000000180  0000000000000000  WA       0     0     32
  [25] .rela.data        RELA             0000000000000000  00003b40
       0000000000000150  0000000000000018   I      33    24     8
  [26] __verbose         PROGBITS         0000000000000000  00003c90
       0000000000000168  0000000000000000  WA       0     0     8
  [27] .rela__verbose    RELA             0000000000000000  00003df8
       0000000000000360  0000000000000018   I      33    26     8
  [28] .data..read_mostl PROGBITS         0000000000000000  00004160
       00000000000003a4  0000000000000000  WA       0     0     32
  [29] .rela.data..read_ RELA             0000000000000000  00004508
       00000000000003c0  0000000000000018   I      33    28     8
  [30] .gnu.linkonce.thi PROGBITS         0000000000000000  000048e0
       0000000000000238  0000000000000000  WA       0     0     32
  [31] .rela.gnu.linkonc RELA             0000000000000000  00004b18
       0000000000000030  0000000000000018   I      33    30     8
  [32] .bss              NOBITS           0000000000000000  00004b48
       0000000000000000  0000000000000000  WA       0     0     1
  [33] .symtab           SYMTAB           0000000000000000  00004b48
       0000000000000e58  0000000000000018          34    95     8
  [34] .strtab           STRTAB           0000000000000000  000059a0
       00000000000009e0  0000000000000000           0     0     1
  [35] .gnu_debuglink    PROGBITS         0000000000000000  00006380
       0000000000000020  0000000000000000           0     0     4
  [36] .shstrtab         STRTAB           0000000000000000  000063a0
       000000000000015f  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)

7 80文字以上を表示する方法(-W)

readelfは、1行が80文字までしか表示しません(デフォルト)。
-Wオプションを使うと、80文字以上を表示することができます。

[root@server ~]# readelf -S -W nf_conntrack_ipv4.ko
37 個のセクションヘッダ、始点オフセット 0x6500:

セクションヘッダ:
  [番] 名前              型              アドレス         Off    サイズ ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .note.gnu.build-id NOTE            0000000000000000 000040 000024 00   A  0   0  4
-snip-
  [27] .rela__verbose    RELA            0000000000000000 003df8 000360 18   I 33  26  8
  [28] .data..read_mostly PROGBITS        0000000000000000 004160 0003a4 00  WA  0   0 32
  [29] .rela.data..read_mostly RELA            0000000000000000 004508 0003c0 18   I 33  28  8
  [30] .gnu.linkonce.this_module PROGBITS        0000000000000000 0048e0 000238 00  WA  0   0 32
  [31] .rela.gnu.linkonce.this_module RELA            0000000000000000 004b18 000030 18   I 33  30  8
  [32] .bss              NOBITS          0000000000000000 004b48 000000 00  WA  0   0  1
-snip-

8 セクションヘッダの中身を情報を表示する方法

8.1 HEXで表示する方法(-x)

nf_conntrack_ipv4.koには全部で37個のセクションがありました。
その中に、modinfoというセクションがあります。
ここでは、modinfoセクションの中身を表示してみます。
まず、modinfoのセクション番号を確認します。18番であることがわかります。

modinfoセクションの番号確認
[root@server ~]# readelf -S nf_conntrack_ipv4.ko|grep modinfo
  [18] .modinfo          PROGBITS         0000000000000000  000027a0

-xオプションに18を指定して、modinfoセクションの情報を表示します。

[root@server ~]# readelf -x 18 nf_conntrack_ipv4.ko

セクション '.modinfo' の 十六進数ダンプ:
  0x00000000 6c696365 6e73653d 47504c00 616c6961 license=GPL.alia
  0x00000010 733d6970 5f636f6e 6e747261 636b0061 s=ip_conntrack.a
  0x00000020 6c696173 3d6e665f 636f6e6e 74726163 lias=nf_conntrac
  0x00000030 6b2d3200 00000000 00000000 00000000 k-2.............
  0x00000040 72657470 6f6c696e 653d5900 7268656c retpoline=Y.rhel
  0x00000050 76657273 696f6e3d 372e3600 73726376 version=7.6.srcv
  0x00000060 65727369 6f6e3d37 46443139 33304644 ersion=7FD1930FD
  0x00000070 38324541 45353635 32364242 44320000 82EAE56526BBD2..
  0x00000080 64657065 6e64733d 6e665f63 6f6e6e74 depends=nf_connt
  0x00000090 7261636b 2c6e665f 64656672 61675f69 rack,nf_defrag_i
  0x000000a0 70763400 696e7472 65653d59 00766572 pv4.intree=Y.ver
  0x000000b0 6d616769 633d332e 31302e30 2d393537 magic=3.10.0-957
  0x000000c0 2e656c37 2e783836 5f363420 534d5020 .el7.x86_64 SMP
  0x000000d0 6d6f645f 756e6c6f 6164206d 6f647665 mod_unload modve
  0x000000e0 7273696f 6e732000                   rsions .

8.2 文字列で表示する方法(-p)

-pオプションにセクション番号18を指定して、modinfoセクションの情報を表示します。
modinfoのセクション情報が文字列で表示されたことがわかります。

[root@server ~]# readelf -p 18 nf_conntrack_ipv4.ko

セクション '.modinfo' の文字列ダンプ:
  [     0]  license=GPL
  [     c]  alias=ip_conntrack
  [    1f]  alias=nf_conntrack-2
  [    40]  retpoline=Y
  [    4c]  rhelversion=7.6
  [    5c]  srcversion=7FD1930FD82EAE56526BBD2
  [    80]  depends=nf_conntrack,nf_defrag_ipv4
  [    a4]  intree=Y
  [    ad]  vermagic=3.10.0-957.el7.x86_64 SMP mod_unload modversions

Z 参考情報

Binary Hacks ―ハッカー秘伝のテクニック100選
Loadable Kernel Moduleの作り方
Anatomy of the Linux loadable kernel module
プロプライエタリ・ドライバによるLinuxカーネルの「汚染」