【注意】このサイトに記載されていることを他人に試すことは「不正アクセス禁止法」に該当する場合があります。詳しくはこちらから

リターンアドレスと関数の戻り道(episode-06)

黒ネコと学ぶ・論理的エクスプロイト開発への道

プログラムは、関数を呼び出して処理を進め、終わると必ず「元の場所」に戻ってきます。
私たちは普段、この動きを当たり前のように使っていますが、実はこの「戻り道」こそが、エクスプロイト開発の重要な分岐点になります。
 
episode-05では、GDBを使ってスタックを観察しました。
今回はそのスタックの中にひっそりと存在する 「リターンアドレス」 に注目します。
 

くろちゃん

関数って…終わったら、どうやって元の場所に戻るの?


白猫先生

いいところに気づいたわね。その「戻る先の住所」を管理しているのが、リターンアドレスなの。

この仕組みを理解すると、なぜスタックオーバーフローが危険なのか、なぜ制御が奪われるのかが、論理的に見えてきます。
※イメージです。

関数呼び出しの「見えない約束」


くろちゃん

mainからhelloを呼んだら、helloが終わったあと、mainに戻るよね?


白猫先生

ええ。そのとき、CPUはこう考えているの。

「hello が終わったら、どこに戻ればいい?」
その答えが リターンアドレス です。
 
 

リターンアドレスとは何か?

リターンアドレスとは、関数が終了したあとに、次に実行する命令の場所(アドレス)のことです。
 
・関数が呼び出されるとき、CPUは次の処理を行います。
1.「戻ってくる場所(アドレス)」を決める。
2.そのアドレスを スタックに積む。
3.関数の中へジャンプする。

くろちゃん

えっ、戻り先もスタックに積まれてるの?


白猫先生

そう。だからスタックは「データ」だけじゃなく、「制御情報」も持っているの。

 

スタックの中身をもう一度整理しよう

関数"hello()"の中にいるとき、スタックには例えばこんなものがあります。
・引数
・ローカル変数 x
・リターンアドレス ← ここが重要!
・前のフレーム情報

くろちゃん

リターンアドレスって、結構大事な場所にあるね…


白猫先生

ええ。ここを書き換えられたら、戻る先そのものが変わるわ。

 
 

GDBで「戻り道」を意識してみる

GDBで関数の中にいるとき、こんな流れを思い出してください。
【gdbの画面】
(gdb) break hello
(gdb) run
(gdb) bt
 
"bt"(backtrace)で表示されるのは、どの関数から、どの関数へ来たか。
つまり、戻り道の履歴です。

くろちゃん

backtrace って、地図みたいだね!


白猫先生

その通り。エクスプロイト開発では、この地図を「逆に使う」の。

 
 

なぜエクスプロイトと関係するのか?

ここがとても重要です。
もし攻撃者が、スタック上のデータを書き換えられる。そして リターンアドレスに届いてしまったらどうなるでしょう?

くろちゃん

……戻る先を、攻撃者が決められる?


白猫先生

正解。それが、制御フローの乗っ取りよ。

プログラムは疑いもせず、「ここに戻れ」と書かれたアドレスへジャンプします。
それが本来のコードでなくてもです。
  
大切なのは、今はまだ攻撃しないこと。episode-06のゴールは、
・リターンアドレスは何か。
・なぜ重要なのか。
・どこに置かれているのか。
を、頭の中で図として描けるようになることです。

くろちゃん

なんだか…仕組みが見えてきた気がする。


白猫先生

その“見えた感覚”が、論理的エクスプロイトの入口よ。

 
 

リターンアドレスと関数の戻り道のまとめ

今回は、リターンアドレスと関数の戻り道について学びました。
プログラムは関数を呼び出すたびに、「どこへ戻るか」という情報をスタックに保存しています。
これがリターンアドレスです。
 
スタックは単なるデータ置き場ではなく、プログラムの流れそのものを支配する場所でもあります。
だからこそ、ここが壊れると挙動全体が変わってしまいます。
重要なのは、「怖いテクニック」を覚えることではありません。
なぜ危険なのかを、構造として理解することです。
 
次回は、スタックフレームとRBP(ベースポインタ) に注目し、「どうやってこの構造が保たれているのか」を見ていきます。お楽しみにね。