blog

テクノロジー|Linuxでバイナリファイルを解析する10の方法

これらの簡単なコマンドとツールは、バイナリファイルを簡単に解析する作業を手助けしてくれます。...

Oct 17, 2025 · 11 min. read
シェア

これらの簡単なコマンドとツールは、バイナリファイルの分析タスクを簡単に実行するのに役立ちます。

"この世界には10種類の人間がいる:バイナリーを理解する人間と理解しない人間"

あなたは毎日バイナリファイルを使っていますが、バイナリファイルについてほとんど知りません。バイナリというのは、コマンドラインツールから本格的なアプリケーションまで、あなたが毎日実行している実行ファイルのことです。

Linuxには、バイナリを簡単に分析するためのツールが豊富に用意されています。仕事の役割に関係なく、Linuxで仕事をするのであれば、これらのツールの基本を知ることは、システムをよりよく理解するのに役立ちます。

この記事では、これらのLinuxツールやコマンドの中で最も人気のあるものをいくつか紹介します。もし見つからなければ、パッケージマネージャを使っていつでもインストールして調べることができます。覚えておいてください:適切な場面で適切なツールを使えるようになるには、多くの忍耐と練習が必要です。

file

機能:ファイルの種類を判別します。

fileコマンドは、作業中のファイルの種類を判断するのに役立ちます。

  1. $ file /bin/ls
  2. /bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=d3b2794dcb1f7ec86, stripped
  3. $ file /etc/passwd
  4. /etc/passwd: ASCII text

ldd

内容: 共有オブジェクトの依存関係を表示します。

実行可能なバイナリファイルに対して上記のfileコマンドを使用した場合、出力に必ず""メッセージが表示されます。これは何を意味するのでしょうか?

ソフトウェアを開発するときは、ライブラリを再作成しないようにしましょう。出力を印刷したり、標準入力から読み込んだり、ファイルを開いたりといった、ほとんどのソフトウェア・プログラムが必要とする共通のタスクがあります。これらの共通タスクはすべて、独自のバリエーションを書くのではなく、誰もが使用できる共通の関数セットに抽象化されています。これらの共通関数は、libc または glibc と呼ばれるライブラリに含まれています。

実行ファイルが依存しているライブラリーはどうやって見つけるのでしょうか?そこで ldd コマンドの出番です。動的にリンクされたバイナリに対してこのコマンドを実行すると、依存するライブラリとそのパスがすべて表示されます。

  1. $ ldd /bin/ls
  2. linux-vdso.so.1 => (0x00007ffef5ba1000)
  3. libselinux.so.1 => /lib64/libselinux.so.1 (0x00007fea9f)
  4. libcap.so.2 => /lib64/libcap.so.2 (0x00007fea9f)
  5. libacl.so.1 => /lib64/libacl.so.1 (0x00007fea9f)
  6. libc.so.6 => /lib64/libc.so.6 (0x00007fea9f)
  7. libpcre.so.1 => /lib64/libpcre.so.1 (0x00007fea9ee17000)
  8. libdl.so.2 => /lib64/libdl.so.2 (0x00007fea9ec13000)
  9. /lib64/ld-linux-x86-64.so.2 (0x00007fea9fa7b000)
  10. libattr.so.1 => /lib64/libattr.so.1 (0x00007fea9ea0e000)
  11. libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fea9e7f2000)

ltrace

機能:ライブラリー・コール・トラッカー。

これで、実行プログラムが依存するライブラリを見つけるのに ldd コマンドを使う方法がわかりました。しかし、ライブラリには何百もの関数が含まれていることがあります。これらの数百の関数のうち、バイナリで実際に使用されている関数はどれでしょうか?

ltrace コマンドは、実行時にライブラリから呼び出されたすべての関数を表示します。以下の例では、呼び出された関数の名前と、その関数に渡された引数を見ることができます。出力の右端には、これらの関数が返すものも表示されます。

  1. $ ltrace ls
  2. __libc_start_main(0x, 0x7ffd, 0x <unfinished ...>
  3. strrchr("ls", '/') = nil
  4. setlocale(LC_ALL, "") = "en_US.UTF-8"
  5. bindtextdomain("coreutils", "/usr/share/locale") = "/usr/share/locale"
  6. textdomain("coreutils") = "coreutils"
  7. __cxa_atexit(0x, 0, 0, 0x56572) = 0
  8. isatty(1) = 1
  9. getenv("QUOTING_STYLE") = nil
  10. getenv("COLUMNS") = nil
  11. ioctl(1, x7ffd) = 0
  12. << snip >>
  13. fflush(0x7ff7baae61c0) = 0
  14. fclose(0x7ff7baae61c0) = 0
  15. +++ exited (status 0) +++

hexdump

内容:ファイルの内容をASCII、10進数、16進数、または8進数で表示します。

不明なファイルをhexdumpで開くと、そのファイルの内容を正確に確認することができます。また、いくつかのコマンドラインオプションを使用して、ファイルデータを ASCII で表示することもできます。これにより、ファイルの種類を確認することができます。

  1. $ hexdump -C /bin/ls | head
  2.  7f 00   00 00  |.ELF............|
  3.  e 00 00  d4 00  |..>......B@.....|
  4.   00 00  f0 c3  |@...............|
  5.   38 00   1e 00  |....@.8...@.....|
  6.   00 00   00 00  |........@.......|
  7.   00 00   00 00  |@.@.....@.@.....|
  8.  f8 00  f8 00  |................|
  9.   00 00   00 00  |................|
  10.   00 00   00 00  |8.......8.@.....|
  11.   00 00  1c 00  |8.@.............|

strings

内容:ファイルから印字可能な文字列を出力します。

バイナリの中の印字可能な文字を探すだけなら、hexdumpは使いすぎのように思えますし、stringsコマンドを使うこともできます。

ソフトウェアを開発する際には、印刷メッセージ、デバッグ情報、ヘルプメッセージ、エラーなど、あらゆる種類のテキスト/ASCII情報が追加されます。これらの情報がすべてバイナリファイルに存在する限り、stringsコマンドを使って画面にダンプすることができます。

  1. $ strings /bin/ls

readelf

内容:ELFファイルに関する情報を表示します。

ELF()は、Linuxだけでなく、さまざまなUNIXシステムで、実行可能ファイルやバイナリ・ファイルの主流となっているファイル形式です。file コマンドのようなツールを使用して、ファイルが ELF 形式であることがわかったら、次のステップとして readelf コマンドとそのさまざまなオプションを使用して、ファイルをさらに分析します。

  1. $ readelf -h /bin/ls
  2. ELF Header:
  3.   Magic:   7f
  4.   Class:                             ELF64
  5.   Data:                              2's complement, little endian
  6.   Version:                           1 (current)
  7.   OS/ABI:                            UNIX - System V
  8.   ABI Version:                       0
  9.   Type:                              EXEC (Executable file)
  10.   Machine:                           Advanced Micro Devices X86-64
  11.   Version:                           0x1
  12.   Entry point address:               0x
  13.   Start of program headers:          64 (bytes into file)
  14.   Start of section headers:           (bytes into file)
  15.   Flags:                             0x0
  16.   Size of this header:               64 (bytes)
  17.   Size of program headers:           56 (bytes)
  18.   Number of program headers:         9
  19.   Size of section headers:           64 (bytes)
  20.   Number of section headers:         31
  21.   Section header string table index: 30

オブジャンダンプ

内容:オブジェクトファイルの情報を表示します。

バイナリファイルはあなたが書いたソースコードから作成され、このソースコードはコンパイラと呼ばれるツールによってコンパイルされます。このコンパイラは、ソースコードに関連する機械語命令を生成し、その機械語命令はCPUによって特定のタスクのために実行されます。これらの機械語コードは、アセンブリ言語として知られるニーモニックによって解読することができます。アセンブリ言語は、プログラムによって実行され、最終的にCPU上で実行される操作を理解するのに役立つ命令のセットです。

objdump ユーティリティは、バイナリファイルまたは実行可能ファイルを読み込んで、アセンブリ言語命令を画面にダンプします。objdump コマンドの出力を理解するには、アセンブリ言語の知識が不可欠です。

覚えておいてください:アセンブリ言語はアーキテクチャ固有です。

  1. $ objdump -d /bin/ls | head
  2. /bin/ls: file format elf64-x86-64
  3. Disassembly of section .init:
  4. <_init@@Base>:
  5. 83 ec 08 sub $0x8,%rsp
  6. 8b e 21 00 mov 0x218e6d(%rip),%rax # 61afc8 <__gmon_start__>
  7. 40215b: test %rax,%rax

strace

機能:システムコールとシグナルを追跡します。

以前紹介したltraceを使ったことがある人は、straceも同じようなものだと思ってください。唯一の違いは、strace ユーティリティはコールをトレースするライブラリではなく、システムコールをトレースすることです。システムコールは、カーネルとインターフェイスして仕事をするものです。

例えば、画面に何かを印刷したい場合、標準ライブラリlibcのprintf関数やputs関数を使いますが、その下には、実際に画面に印刷するwriteというシステムコールがあります。

  1. $ strace -f /bin/ls
  2. execve("/bin/ls", ["/bin/ls"], [/* 17 vars */]) = 0
  3. brk(NULL) = 0x
  4. mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0
  5. access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
  6. open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
  7. fstat(3, {st_mode=S_IFREG|0644, st_size=40661, ...}) = 0
  8. mmap(NULL, 40661, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f
  9. close(3) = 0
  10. << snip >>
  11. fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
  12. mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f
  13. write(1, "R2 RH ", 7R2 RH
  14. close(1) = 0
  15. munmap(0x7f, 4096) = 0
  16. close(2) = 0
  17. exit_group(0) = ?
  18. +++ exited with 0 +++

nm

内容:オブジェクトファイル内のシンボルをリストアップします。

使用しているバイナリ・ファイルがストリップされていない場合、nmコマンドはコンパイル中にバイナリ・ファイルに埋め込まれた貴重な情報を提供してくれます。nmはバイナリ・ファイルから変数や関数を特定するのに役立ちます。バイナリ・ファイルのソース・コードにアクセスできない場合、これがどれほど役に立つか想像できるでしょう。

nmを実証するために、-gオプションでコンパイルされた小さなプログラムを簡単に書くと、このバイナリがストリップされていないことがわかります。

  1. $ cat hello.c
  2. #include <stdio.h>
  3. int main() {
  4. printf("Hello world!");
  5. return 0;
  6. $ gcc -g hello.c -o hello
  7. $ file hello
  8. hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=3de46c8efb98bce4ad21568ba3d8a5d, not stripped
  9. $ ./hello
  10. Hello world!$
  11. $ nm hello | tail
  12. e20 d __JCR_END__
  13. e20 d __JCR_LIST__
  14. b0 T __libc_csu_fini
  15. T __libc_csu_init
  16. U __libc_start_main@@GLIBC_2.2.5
  17. d T main
  18. U printf@@GLIBC_2.2.5
  19. t register_tm_clones
  20. T _start
  21. D __TMC_END__

gdb

機能: GNU Debugger。

バイナリのすべてを静的に解析できるわけではありません。ltraceやstraceのようにバイナリを実行するコマンドの一部が実行されるのは事実ですが、ソフトウェアは様々な条件で構成されており、異なる代替パスが実行される可能性があります。

このような経路を分析する唯一の方法は、プログラムが任意の時点で停止または一時停止し、さらに先の行を実行する前に情報を分析できるランタイム環境です。

そのためにデバッガがあり、Linuxではgdbがデバッガのデファクトスタンダードです。プログラムをロードしたり、特定の場所にブレークポイントを設定したり、メモリやCPUレジスタを解析したり、その他多くのことができます。上記の他のツールを補完し、より多くのランタイム解析を行うことができます。

一つ注意しなければならないのは、gdbを使ってプログラムをロードすると、そのプログラム独自の(gdb)プロンプトが表示されるということです。それ以降のコマンドはすべて、終了するまでこのgdbプロンプトで実行されます。

コンパイルされたhelloプログラムを使用し、gdbで動作を確認します。

  1. $ gdb -q ./hello
  2. Reading symbols from /home/flash/hello...done.
  3. (gdb) break main
  4. Breakpoint 1 at 0x: file hello.c, line 4.
  5. (gdb) info break
  6. Num Type Disp Enb Address What
  7. 1 breakpoint keep y 0x in main at hello.c:4
  8. (gdb) run
  9. Starting program: /home/flash/./hello
  10. Breakpoint 1, main () at hello.c:4
  11. 4 printf("Hello world!");
  12. Missing separate debuginfos, use: debuginfo-install glibc-2..el7_6.6.x86_64
  13. (gdb) bt
  14. #0 main () at hello.c:4
  15. (gdb) c
  16. Continuing.
  17. Hello world![Inferior 1 (process 29620) exited normally]
  18. (gdb) q

結論

これらのネイティブLinuxバイナリ解析ツールの使用に慣れ、それらが提供する出力を理解したら、 ような、より高度で専門的なオープンソースバイナリ解析ツールに進むことができます。

Read next

技術|LinuxのVirtualBoxで仮想マシンからUSBにアクセスする

仮想マシン内からUSBストレージにアクセスすることは絶対にできます。Linux を使っているなら、その方法は以下の通りです。

Oct 17, 2025 · 3 min read