ELF実行ファイルをobjdumpでCのソースコード付きで逆アセンブルする方法

提供: C言語入門
2016年5月21日 (土) 22:07時点におけるDaemon (トーク | 投稿記録)による版 (ページの作成:「UNIX(FreeBSD/Linux)の実行ファイルは、'''ELF''' と呼ばれる形式(フォーマット)です。Unix環境では、C言語のソースコードは、gccや[...」)

(差分) ←前の版 | 最新版 (差分) | 次の版→ (差分)
移動: 案内検索
スポンサーリンク

UNIX(FreeBSD/Linux)の実行ファイルは、ELF と呼ばれる形式(フォーマット)です。Unix環境では、C言語のソースコードは、gccclangなどのCコンパイラによって、ELFのファイルに変換されます。ELFへの変換は、コンパイルと呼ばれます。ELF ファイルをアセンブラ言語に変換することを逆アセンブルといいます。ここでは、逆アセンブル(ディスアセンブル)したときに、C言語のソースコード付きで逆アセンブルする方法を紹介します。

読み方

逆アセンブル
ぎゃく あせんぶる
disassemble
でぃす あせんぶる

概要

ELF のファイルを調査するために、逆アセンブル(ディスアセンブル, disassemble, 逆コンパイル)します。 逆アセンブルが必要になるシーンとしては、プログラムが異常な振る舞いをしているときに、原因を調査するため、が挙げられます。

objdump コマンドとは

Unix の objdump コマンドは、オブジェクトファイルの情報を表示するためのツールです。 objdump を利用すると ELF のファイルからアセンブラのソースを出力することができます。

C言語付きで逆アセンブルするメリット

アセンブラ言語がスラスラ読めれば良いですが、必ずしも、みんなが読めるわけでもありません。 どんなコードが、どんなコードになるか、の学習の助けにもなります。

C言語付きで逆アセンブルするための前提

コンパイルするときに clanggcc であれば、 -g オプションを利用している必要があります。

C言語付きで逆アセンブルする例

簡単な、プログラムで紹介します。

ソースコード func.c

引数 a と b を足し算して、返すだけの簡単なプログラムです。

/*
 * func.c
 * Copyright (C) 2016 kaoru <kaoru@localhost>
 */
int
foo (int a, int b)
{
        return a + b;
}

単純に逆アセンブルした場合

まずは、func.c を -g オプションなしでコンパイルして、逆アセンブルしてみます。

cc -c func.c
objdump -d func.o

このように、アセンブリ言語だけの出力が得られます。

func.o:     ファイル形式 elf64-x86-64-freebsd
 
 
セクション .text の逆アセンブル:
 
0000000000000000 <foo>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   89 7d fc                mov    %edi,-0x4(%rbp)
   7:   89 75 f8                mov    %esi,-0x8(%rbp)
   a:   8b 75 fc                mov    -0x4(%rbp),%esi
   d:   03 75 f8                add    -0x8(%rbp),%esi
  10:   89 f0                   mov    %esi,%eax
  12:   5d                      pop    %rbp
  13:   c3                      retq

C言語のソースコード付きで逆アセンブルする例

C言語のソースコード付きで逆アセンブルする場合には、 -g オプションをつけます。 また、objdump の引数にも -S オプションを指定します。

cc -g -c func.c
objdump -S -d func.o

得られた出力を以下に示します。

func.o:     ファイル形式 elf64-x86-64-freebsd
 
 
セクション .text の逆アセンブル:
 
0000000000000000 <foo>:
 *
 * Distributed under terms of the MIT license.
 */
int
foo (int a, int b)
{
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   89 7d fc                mov    %edi,-0x4(%rbp)
   7:   89 75 f8                mov    %esi,-0x8(%rbp)
        return a + b;
   a:   8b 75 fc                mov    -0x4(%rbp),%esi
   d:   03 75 f8                add    -0x8(%rbp),%esi
  10:   89 f0                   mov    %esi,%eax
  12:   5d                      pop    %rbp
  13:   c3                      retq

このように、ところどころに C 言語のソースが記載されます。

for を利用したソースコードの例

もう1つ例を示します。

/*
 * sum.c
 * Copyright (C) 2016 kaoru <kaoru@localhost>
 */
int
sum (int max) {
        int i;
        int total = 0;
        for (i = 0; i < max; i++) {
                total += i;
        }
        return total;
}
cc -g -c sum.c
objdump -S -d sum.o > sum.S
sum.o:     ファイル形式 elf64-x86-64-freebsd
 
 
セクション .text の逆アセンブル:
 
0000000000000000 <sum>:
 * Copyright (C) 2016 kaoru <kaoru@localhost>
 *
 * Distributed under terms of the MIT license.
 */
int
sum (int max) {
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   89 7d fc                mov    %edi,-0x4(%rbp)
        int i;
        int total = 0;
   7:   c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%rbp)
        for (i = 0; i < max; i++) {
   e:   c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%rbp)
  15:   8b 45 f8                mov    -0x8(%rbp),%eax
  18:   3b 45 fc                cmp    -0x4(%rbp),%eax
  1b:   0f 8d 1b 00 00 00       jge    3c <sum+0x3c>
                total += i;
  21:   8b 45 f8                mov    -0x8(%rbp),%eax
  24:   8b 4d f4                mov    -0xc(%rbp),%ecx
  27:   01 c1                   add    %eax,%ecx
  29:   89 4d f4                mov    %ecx,-0xc(%rbp)
 */
int
sum (int max) {
        int i;
        int total = 0;
        for (i = 0; i < max; i++) {
  2c:   8b 45 f8                mov    -0x8(%rbp),%eax
  2f:   05 01 00 00 00          add    $0x1,%eax
  34:   89 45 f8                mov    %eax,-0x8(%rbp)
  37:   e9 d9 ff ff ff          jmpq   15 <sum+0x15>
                total += i;
        }
        return total;
  3c:   8b 45 f4                mov    -0xc(%rbp),%eax
  3f:   5d                      pop    %rbp
  40:   c3                      retq

まとめ

  • コンパイル時に -g オプションを使用することで、逆アセンブルしたときに、C言語のソースコードの情報も出力できる
  • objdump は、 -S オプションを利用すると C言語のソースコードの情報があれば、Cのソースコードを出力する

関連項目




スポンサーリンク