stringsでなぜprintfが見えるのか
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
はそのまま変換されずに残るようです。
ただし残るといっても関数名が残っているだけで、関数内部の処理はコンパイル済みであり、あくまでも関数の名前の部分だけがそのまま残るみたいです。
ここまで調べるのに結構時間がかかりましたが、最後まとめているときに逆コンパイルについてまとめているサイトを見つけました。これを初めから見ていえればこんなに時間がかからなかったのに・・・
とはいえ、今までわかっていなかったコンパイルの流れや実行ファイルの仕組みを理解できたのは非常に有益でした。
特にコンパイルには広義・狭義の意味があったり、アセンブラ・アセンブリ・アセンブルの違いなども調べていくうちに理解できたので、興味がある人は調べてみてはいかがでしょうか。
参考書籍
セキュリティコンテストチャレンジブック -CTFで学ぼう! 情報を守るための戦い方-
- 作者: 碓井利宣,竹迫良範,廣田一貴,保要隆明,前田優人,美濃圭佑,三村聡志,八木橋優,SECCON実行委員会
- 出版社/メーカー: マイナビ出版
- 発売日: 2015/09/30
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (4件) を見る
- 作者: 清水祐太郎,竹迫良範,新穂隼人,長谷川千広,廣田一貴,保要隆明,美濃圭佑,三村聡志,森田浩平,八木橋優,渡部裕,SECCON実行委員会
- 出版社/メーカー: マイナビ出版
- 発売日: 2017/07/28
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る