ハッカー・プログラミング大全

久しぶりにメールを見ると、知らない人からこんなメールが来てました。

ソースコード非公開ソフトウェアのExploitのp.48〜p.50の部分です。

ここの最後の式の意味がわかりません。

0x7fffe90c-esp-4 = 68

の4の意味がどこから出てきたのかわかりません。

確認から本棚から引っ張り出し「ハッカー・プログラミング大全」を読み直しました。

ハッカー・プログラミング大全

ハッカー・プログラミング大全



結論から言うと、この式は

esp(== 0x7fffe954) - sizeof(esp)( == 4) - 0x7fffe90c == 68(10進数)

であり、4はespレジスタのサイズであり、関数の(戻り)アドレスのサイズです。(あとp42のebpオフセットもいい加減だ。)

C言語の実行時スタックは、メモリアドレスの前から順に

前のebpの値 戻りアドレス 引数1 引き数2... 変数1 変数2...

ebp(フレームの頭)                  ↑esp(>=ebp)

で関数の実行時フレームを作るコードになっていると仮定しています(p.23あたり)。

でその関数内で関数が呼び出されるとそのすぐ後ろのアドレスに呼び出す関数のフレームを作ると仮定します。呼び出しが終わるとフレームは破棄(データをパージするわけではなく意味上の破棄)されます。

main関数フレーム strcpy関数フレーム

espはスタックポインタで現在のスタック位置を指します。

バッファオーバーフローを起こすプログラムというのは、たとえば上記のmain-strcpy配置を使うと、strcpy中でmain関数内の変数を書き換えさせるmainプログラムで、そのコピー元のデータのサイズがコピー先の変数サイズより大きくなって、strcpyの戻りアドレスまで上書きしてしまうプログラムのことです。

戻りアドレスの内容が思いっきり変な値を指すとセグメンテーション違反になるけど、そんなにおかしな値でない場合はそのまま実行されます。またセグメンテーション違反をさせてcoreを吐かせると、それをgdbでみることで、その時点でのスタックやレジスタの値がみれます。

例のページでは、

(main).. buf ... strcpy戻りアドレス ...

                  ↑esp(戻りアドレスの後ろ)

でセグメント違反を起こすので、esp - sizeof(esp) - &buf(マーキングパターンが始まってる位置) となります(p.41-42あたりがその説明にあたりそう)。

バッファオーバーフローExploitはそれらを利用したものです。
変数の普通の部分に関数データ(たとえばvoid f() {execl("/bin/sh", "sh", 0);}の機械語バイト列)を置き、戻りアドレス部分にその関数データの先頭を入れれば、普通にそのデータの関数が実行されます(p.42-43あたり)。


という感じでしょうかね。流し読みしたからあまり気にしてなかったけど、ゼロの知識で読もうとするとわかりにくいところが多いな。重要な部分での誤植もあるし、正誤表も見つからない。そういう人が対象ではないのかもしれないけど、読むのにある程度スキルがいることは確かだろう。