ELF実行ファイルをobjdumpでCのソースコード付きで逆アセンブルする方法
UNIX(FreeBSD/Linux)の実行ファイルは、ELF と呼ばれる形式(フォーマット)です。Unix環境では、C言語のソースコードは、gccやclangなどのCコンパイラによって、ELFのファイルに変換されます。ELFへの変換は、コンパイルと呼ばれます。ELF ファイルをアセンブラ言語に変換することを逆アセンブルといいます。ここでは、逆アセンブル(ディスアセンブル)したときに、C言語のソースコード付きで逆アセンブルする方法を紹介します。
読み方
- 逆アセンブル
- ぎゃく あせんぶる
- disassemble
- でぃす あせんぶる
目次
概要
ELF のファイルを調査するために、逆アセンブル(ディスアセンブル, disassemble, 逆コンパイル)します。 逆アセンブルが必要になるシーンとしては、プログラムが異常な振る舞いをしているときに、原因を調査するため、が挙げられます。
objdump コマンドとは
Unix の objdump コマンドは、オブジェクトファイルの情報を表示するためのツールです。 objdump を利用すると ELF のファイルからアセンブラのソースを出力することができます。
C言語付きで逆アセンブルするメリット
アセンブラ言語がスラスラ読めれば良いですが、必ずしも、みんなが読めるわけでもありません。 どんなコードが、どんなコードになるか、の学習の助けにもなります。
C言語付きで逆アセンブルするための前提
コンパイルするときに clang や gcc であれば、 -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のソースコードを出力する
関連項目
ツイート