はじめに (対象読者・この記事でわかること)

この記事は、Linux環境でプログラム開発を行っている方や、バイナリファイルの解析に興味がある方を対象としています。特に、C/C++などのコンパイル言語で開発を行い、生成された実行ファイルや共有ライブラリファイル(ELF形式)の内部にどのような文字列が含まれているかを確認したい方に役立つ内容です。

この記事を読むことで、ELFファイル内の文字列リテラルを抽出・表示するための基本的な手法を理解できます。stringsコマンドやobjdump、readelfなどの標準的なツールを使った具体的な方法を学び、実際に手を動かして試すことができるようになります。また、抽出した文字列をどのように活用できるかについても触れます。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。 - Linuxの基本的なコマンド操作 - C/C++などのプログラミング言語の基礎知識 - コンパイルとリンクの基本的な概念 - ターミナルでの基本的な操作

ELFファイルと文字列リテラルの基礎

ELF(Executable and Linkable Format)は、Linuxや他のUnix系オペレーティングシステムで使用される標準的なファイル形式です。実行ファイル、共有ライブラリ、オブジェクトファイルなど、様々な種類のファイルがこの形式で保存されています。

プログラムをコンパイルすると、ソースコードに記述された文字列リテラル("Hello, World!"のような二重引用符で囲まれた文字列)は、ELFファイル内のデータセクションに保存されます。これらの文字列は、デバッグ情報やリソースとして利用されるだけでなく、プログラムの挙動を理解する上で重要な情報を提供します。

文字列リテラルを抽出することで、以下のような目的で利用できます: - プログラムがどのようなメッセージを表示するかを事前に把握 - 逆解析時にプログラムの動作を推測 - セキュリティ診断における情報収集 - プログラムの動的な挙動を調査

文字列リテラルの抽出方法

ELFファイル内の文字列リテラルを抽出するには、いくつかの方法があります。ここでは、主に3つの方法を紹介します。

方法1:stringsコマンドを使う

stringsコマンドは、ファイル内の可読文字列を抽出するための最も基本的なツールです。ELFファイルに対してstringsコマンドを実行するだけで、ファイル内に含まれる文字列リテラルを簡単に抽出できます。

基本的な使い方は以下の通りです:

Bash
strings [ファイル名]

例えば、sampleという名前のELFファイル内の文字列を抽出するには:

Bash
strings sample

さらに、オプションを追加することで、より詳細な情報を得ることができます。例えば、最小文字数を指定する-nオプションを使うと、指定した文字数以上の文字列のみを抽出できます:

Bash
strings -n 4 sample # 4文字以上の文字列のみ抽出

また、抽出した文字列をファイルに保存したい場合はリダイレクトを使います:

Bash
strings sample > strings.txt

方法2:objdumpを使う

objdumpは、ELFファイルの詳細な情報を表示するための強力なツールです。stringsコマンドと同様に、文字列リテラルの抽出も可能です。

objdumpで文字列を抽出するには、以下のコマンドを使用します:

Bash
objdump -s -j .rodata [ファイル名]

このコマンドでは、-sオプションでセクションの内容を16進数とASCIIの両方で表示し、-j .rodataオプションで.rodataセクション(読み取り専用データセクション)を指定しています。多くの場合、文字列リテラルはこのセクションに格納されています。

方法3:readelfを使う

readelfは、ELFファイルの内部構造を詳細に解析するためのツールです。objdumpと同様に、特定のセクションの内容を表示できます。

readelfで文字列を抽出するには、以下のコマンドを使用します:

Bash
readelf -p .rodata [ファイル名]

このコマンドでは、-pオプションでセクションの内容を印刷します。.rodataセクションに加えて、.dataセクションや.bssセクションなどにも文字列が含まれる場合があるため、必要に応じてセクション名を変更してください。

方法4:Pythonスクリプトを使う

より高度な解析や自動化を行いたい場合、Pythonを使ったスクリプトを書くと便利です。以下に、PythonでELFファイルから文字列を抽出する簡単な例を示します:

Python
import re import sys def extract_strings_from_elf(filename, min_length=4): with open(filename, 'rb') as f: content = f.read() # 正規表現で文字列を抽出 strings = re.findall(rb'[\x20-\x7E]{' + str(min_length).encode() + rb',}', content) for s in strings: print(s.decode('utf-8', errors='ignore')) if __name__ == '__main__': if len(sys.argv) < 2: print("Usage: python extract_strings.py <elf_file> [min_length]") sys.exit(1) filename = sys.argv[1] min_length = int(sys.argv[2]) if len(sys.argv) > 2 else 4 extract_strings_from_elf(filename, min_length)

このスクリプトは、指定したELFファイルから最小文字数以上の可読文字列を抽出して表示します。実行方法は以下の通りです:

Bash
python extract_strings.py sample 4

実践的な例

ここでは、実際に簡単なCプログラムをコンパイルし、そのELFファイルから文字列リテラルを抽出してみましょう。

まず、以下のような簡単なCプログラムを作成します(sample.c):

C
#include <stdio.h> int main() { printf("Hello, World!\n"); printf("This is a test program.\n"); return 0; }

このプログラムをコンパイルします:

Bash
gcc -o sample sample.c

stringsコマンドを使った抽出

stringsコマンドを使って、sampleファイルから文字列を抽出します:

Bash
strings sample

実行結果は以下のようになります(実際の出力とは異なる場合があります):

/lib64/ld-linux-x86-64.so.2
__gmon_start__
libc.so.6
_IO_stdin_used
Hello, World!
This is a test program.
__libc_start_main

ここから、プログラム内で定義した"Hello, World!"と"This is a test program."の文字列が抽出できていることがわかります。また、システムライブラリに関連する文字列も含まれています。

objdumpを使った抽出

次に、objdumpを使って文字列を抽出します:

Bash
objdump -s -j .rodata sample

実行結果は以下のようになります:

Contents of section .rodata:
 0000000000400400 01000200 00000000 48656c6c 6f2c2057 .........Hello, W
 0000000000400410 6f726c64 210a0054 68697320 69732061 orld!.This is a
 0000000000400420 20746573 74207072 6f677261 6d2e00  test program..

16進数で表示されていますが、下の行にASCII文字列も表示されています。"Hello, World!"と"This is a test program."が確認できます。

readelfを使った抽出

最後に、readelfを使って文字列を抽出します:

Bash
readelf -p .rodata sample

実行結果はobjdumpと似ていますが、表示形式が異なります:

String dump of section '.rodata':
  [     0]  Hello, World!
  [    14]  This is a test program.

こちらの方が見やすい形式で文字列が表示されています。

文字列リテラルの活用例

抽出した文字列リテラルは、様々な場面で活用できます。

逆解析時のヒント

プログラムの逆解析を行う際、抽出した文字列はプログラムの動作を理解する上で重要な手がかりになります。例えば、エラーメッセージやログ出力の文字列がわかれば、どの関数がエラーを返しているかを特定できます。

セキュリティ診断

セキュリティ診断では、プログラム内に含まれるパスワードやAPIキーなどの機密情報が文字列として保存されていないかを確認します。stringsコマンドを使って簡単にスキャンできます。

プログラムの動的解析

プログラムの実行時にどのような文字列が使用されているかを知りたい場合、抽出した文字列をリファレンスとして利用できます。

国際化対応

多言語対応のプログラムでは、文字列リテラルがリソースファイルにまとめられていますが、stringsコマンドを使ってどの文字列がどこで使われているかを調査できます。

まとめ

本記事では、ELFファイル内の文字列リテラルを抽出・表示する方法について解説しました。

  • stringsコマンドを使うのが最も簡単で基本的な方法
  • objdumpreadelfを使うと、より詳細な情報を得られる
  • Pythonスクリプトを使うと、自動化や高度な解析が可能
  • 抽出した文字列は、逆解析やセキュリティ診断、プログラムの動的解析などに活用できる

この記事を通して、ELFファイルから文字列リテラルを抽出する基本的な手法を学びました。これらの技術は、プログラムの解析やデバッグ、セキュリティ診断など、様々な場面で役立つでしょう。今後は、より高度なバイナリ解析技術についても記事にする予定です。

参考資料