stringsでなぜprintfが見えるのか
By cyamax
Linuxへの理解を深めるため、最近CTFの問題を解いています。
CTFの回答を見ていると実行ファイル(バイナリ)に対してstrings
コマンドを実行して、その中にpritnf
があるから書式文字列攻撃を試して・・・と書いてありました。
全く意味がわからなかったので、調べたことのメモになります。
そもそもstringsとは
Linuxのコマンド 。 指定したファイル中の表示可能な文字列を表示します。 バイナリファイルやデータファイルの内容を判断するために利用します。
strings実行例
実行するとHello world!
と表示されるファイルを用意します。
$ ./main
Hello world!
この実行ファイルをstirngsで見てみます。
※stringsはデフォルトではファイルの先頭しか見ないので、オプションの-
をつけることでファイル全体から文字を検索します。
$ strings - main
__PAGEZERO
__TEXT
__text
__TEXT
__stubs
__TEXT
__stub_helper
__TEXT
__cstring
__TEXT
__unwind_info
__TEXT
__DATA
__nl_symbol_ptr
__DATA
__la_symbol_ptr
__DATA
__LINKEDIT
/usr/lib/dyld
/usr/lib/libSystem.B.dylib
Hello world!
@dyld_stub_binder
@_printf
_mh_execute_header
!main
__mh_execute_header
_main
_printf
dyld_stub_binder
stringsは実行ファイル中に存在する文字だけを抽出してくれるのがメリットです。
※lessやcatで実行ファイルを見てもノイズが多くて見にくい
実行ファイル(バイナリ)って変数名とか見れないんじゃないの?
私の認識では高級言語のソースコードをコンパイルしたら変数名や関数は機械語に変換されるため、stringsコマンドでバイナリを見てももちろんソースコードは出てこないし、関数名・変数も機械の都合の良い名前に変換されていると思っていました。
なので例えばint hoge=1111
なんてコードを書いても、コンパイル後はint
はアセンブリ言語のMOV
かなにかに変換されて、変数名hoge
も別の何かに変換されて跡形もなくなると思っていました。
なのでstrings
コマンドで実行ファイルを覗いても、ソースコードの関数は見えないはず(=printfは出てこない)では?と思い混乱しました。
実際にコンパイルしてみた
やってみないとわからないので、
試しに以下のコードを書いてコンパイルしてみました。
C言語でテスト
/* test.c */
#include <stdio.h>
int test(){
int hensu = 1111;
printf("変数の中身は%dです\n",hensu);
return 0;
}
int main(){
printf("Hello world!\n");
test();
return 0;
}
上記コードを保存(test.cなど)して以下コマンドでオブジェクトファイルの作成をします。
gcc -o test.c
するとtest.o
が生成されるので、今回はこれをstrings
で覗きます。
strings結果
MacBook-Pro:Desktop takanori$ strings - test2.o
__text
__TEXT
__cstring
__TEXT
__compact_unwind__LD
__eh_frame
__TEXT
Hello world!
_test
_main
_printf
たしかにprintf
が拾えてる!
まとめ
上記の検証から
変数名hensu
はコンパイル後stringsで見えない。
関数名main
,test
,printf
は見えることがわかった。
どうやら変数名(hensu)や既存の関数(intなど)はコンパイルされると跡形もなくなりますが、自分で作った関数main
,test
や外部の関数printf
はそのまま変換されずに残るようです。
ただし残るといっても関数名が残っているだけで、関数内部の処理はコンパイル済みであり、あくまでも関数の名前の部分だけがそのまま残るみたいです。
ここまで調べるのに結構時間がかかりましたが、最後まとめているときに逆コンパイルについてまとめているサイトを見つけました。これを初めから見ていえればこんなに時間がかからなかったのに・・・
とはいえ、今までわかっていなかったコンパイルの流れや実行ファイルの仕組みを理解できたのは非常に有益でした。
特にコンパイルには広義・狭義の意味があったり、アセンブラ・アセンブリ・アセンブルの違いなども調べていくうちに理解できたので、興味がある人は調べてみてはいかがでしょうか。
参考書籍
[asin:4839956480:detail]
[asin:4839962138:detail]
参考サイト
http://aoking.hatenablog.jp/entry/20121109/1352457273
http://www5d.biglobe.ne.jp/~noocyte/Programming/Decompile.html#CDecompilerPossiblity