[Linux] バイナリファイル（ELFファイル）の調査に使えるコマンドまとめ

# ELF（Executable and Linkable Format）とは

　Executable and Linkable Format (ELF) とは、コンパイラが生成するオブジェクト、および、ライブラリとリンクされた実行ファイルのファイルフォーマットである。a.outフォーマット、COFFの後継として広く採用されている。セクション数の制限が緩く、メモリ上で連続していないファイルや、ロードされる場所と実行される場所が違う箇所を含む場合にも対応が可能な柔軟な設計となっている。

　System V が採用し、GNUツールチェーンがサポートしていることもあり、今ではBSD派生OSや、LinuxをはじめとするフリーなOSにおける実行ファイルフォーマットそして、ゲーム機等を含む組み込み機器開発に於いても好んで使われている。

by https://ja.wikipedia.org/wiki/Executable_and_Linkable_Format

---

「[Binary Hacks ─ ハッカー秘伝のテクニック100選](http://0xcc.net/binhacks/)」あたりが詳しいです。

# オブジェクトファイルの情報を表示する
## objdump
```
$ objdump -j .plt -S /bin/ls | head -n 30

/bin/ls:     file format elf64-x86-64


Disassembly of section .plt:

0000000000402190 <__ctype_toupper_loc@plt-0x10>:
  402190:	ff 35 72 7e 21 00    	pushq  0x217e72(%rip)        # 61a008 <_fini+0x20810c>
  402196:	ff 25 74 7e 21 00    	jmpq   *0x217e74(%rip)        # 61a010 <_fini+0x208114>
  40219c:	0f 1f 40 00          	nopl   0x0(%rax)

00000000004021a0 <__ctype_toupper_loc@plt>:
  4021a0:	ff 25 72 7e 21 00    	jmpq   *0x217e72(%rip)        # 61a018 <_fini+0x20811c>
  4021a6:	68 00 00 00 00       	pushq  $0x0
  4021ab:	e9 e0 ff ff ff       	jmpq   402190 <_init+0x28>

00000000004021b0 <__uflow@plt>:
  4021b0:	ff 25 6a 7e 21 00    	jmpq   *0x217e6a(%rip)        # 61a020 <_fini+0x208124>
  4021b6:	68 01 00 00 00       	pushq  $0x1
  4021bb:	e9 d0 ff ff ff       	jmpq   402190 <_init+0x28>

00000000004021c0 <getenv@plt>:
  4021c0:	ff 25 62 7e 21 00    	jmpq   *0x217e62(%rip)        # 61a028 <_fini+0x20812c>
  4021c6:	68 02 00 00 00       	pushq  $0x2
  4021cb:	e9 c0 ff ff ff       	jmpq   402190 <_init+0x28>

00000000004021d0 <sigprocmask@plt>:
  4021d0:	ff 25 5a 7e 21 00    	jmpq   *0x217e5a(%rip)        # 61a030 <_fini+0x208134>
  4021d6:	68 03 00 00 00       	pushq  $0x3
  4021db:	e9 b0 ff ff ff       	jmpq   402190 <_init+0x28>
```

# ELF ファイルに関する情報を表示
## readelf

```
$ readelf -w -a /bin/ls
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
...
```

# オブジェクトファイルのシンボルを表示する
## nm
以下をコンパイルした `a.out` に対して実行

```cpp
#include <iostream>

int main(int argc, char const* argv[])
{
    std::cout << "test" << std::endl;                                                                                                                                                                        
    return 0;
}
```

```
$ nm a.out 
0000000000601060 B __bss_start
0000000000601170 b completed.6972
                 U __cxa_atexit@@GLIBC_2.2.5
0000000000601050 D __data_start
0000000000601050 W data_start
0000000000400790 t deregister_tm_clones
0000000000400800 t __do_global_dtors_aux
0000000000600e08 t __do_global_dtors_aux_fini_array_entry
0000000000601058 D __dso_handle
0000000000600e18 d _DYNAMIC
0000000000601060 D _edata
0000000000601178 B _end
00000000004008c4 T _fini
0000000000400820 t frame_dummy
0000000000600df8 t __frame_dummy_init_array_entry
0000000000400a18 r __FRAME_END__
0000000000601000 d _GLOBAL_OFFSET_TABLE_
0000000000400740 t _GLOBAL__sub_I_main
                 w __gmon_start__
0000000000400668 T _init
0000000000600e08 t __init_array_end
0000000000600df8 t __init_array_start
00000000004008d0 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000600e10 d __JCR_END__
0000000000600e10 d __JCR_LIST__
                 w _Jv_RegisterClasses
00000000004008c0 T __libc_csu_fini
0000000000400850 T __libc_csu_init
                 U __libc_start_main@@GLIBC_2.2.5
0000000000400710 T main
00000000004007c0 t register_tm_clones
0000000000400766 T _start
0000000000601060 D __TMC_END__
                 U _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4
                 U _ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4
0000000000601060 B _ZSt4cout@@GLIBCXX_3.4
                 U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@@GLIBCXX_3.4
0000000000601171 b _ZStL8__ioinit
                 U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@@GLIBCXX_3.4
```

# オブジェクトのシンボルを削除する
## strip
```shell-session:stripを実行してからnmを実行してみる
$ strip a.out 
$ nm a.out 
nm: a.out: no symbols
```

*参考*

+ [Man page of strip](https://linuxjm.osdn.jp/html/GNU_binutils/man1/strip.1.html)

# 共有ライブラリの依存関係を表示
## ldd
```shell-session:lsでの実行例
$ ldd /bin/ls
	linux-vdso.so.1 =>  (0x00007ffe96d48000)
	libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007fef2846a000)
	libacl.so.1 => /lib/x86_64-linux-gnu/libacl.so.1 (0x00007fef28262000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fef27e9c000)
	libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007fef27c5e000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fef27a5a000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fef286a7000)
	libattr.so.1 => /lib/x86_64-linux-gnu/libattr.so.1 (0x00007fef27854000)
```

# 共有ライブラリの関数呼び出しをトレース
## ltrace
```shell-session:lsでの実行例
$ ltrace /bin/ls
__libc_start_main(0x4028c0, 1, 0x7ffca0650708, 0x411e60 <unfinished ...>
strrchr("/bin/ls", '/')                                                      = "/ls"
setlocale(LC_ALL, "")                                                        = "LC_CTYPE=en_US.UTF-8;LC_NUMERIC="...
bindtextdomain("coreutils", "/usr/share/locale")                             = "/usr/share/locale"
textdomain("coreutils")                                                      = "coreutils"
__cxa_atexit(0x40a200, 0, 0, 0x736c6974756572)                               = 0
isatty(1)                                                                    = 1
getenv("QUOTING_STYLE")                                                      = nil
getenv("COLUMNS")                                                            = nil
ioctl(1, 21523, 0x7ffca06502b0)                                              = 0
...
```

# システムコールの呼び出しをトレース
## strace

```
$ strace /bin/ls
execve("/bin/ls", ["/bin/ls"], [/* 72 vars */]) = 0
brk(0)                                  = 0x7d4000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0f51bce000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=94491, ...}) = 0
...
close(1)                                = 0
munmap(0x7f0f51bcd000, 4096)            = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++
```

`-tt` などでタイムスタンプ、`-T` で実行時間を表示可能

```
$ strace -tt -T /bin/ls 2>&1 | head -n 10
21:52:03.157481 execve("/bin/ls", ["/bin/ls"], [/* 72 vars */]) = 0 <0.001690>
21:52:03.160439 brk(0)                  = 0x654000 <0.000068>
21:52:03.161176 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) <0.000416>
21:52:03.163197 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe0b1da6000 <0.000381>
21:52:03.164400 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) <0.000419>
21:52:03.165426 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 <0.000350>
21:52:03.166938 fstat(3, {st_mode=S_IFREG|0644, st_size=94491, ...}) = 0 <0.000156>
21:52:03.167878 mmap(NULL, 94491, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fe0b1d8e000 <0.000179>
21:52:03.168485 close(3)                = 0 <0.000186>
21:52:03.169073 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) <0.000209>
```

マルチスレッドの場合は `-f` をつけると良い。

*参考*

+ [strace コマンドの使い方をまとめてみた](http://blog.livedoor.jp/sonots/archives/18193659.html)

# ファイル中の表示可能な文字列を表示する 
## strings

*参考*