第四話:CALL命令で起こること

今回はいよいよ佳境、CALL命令(とRET命令)についてです。

なぜCALL命令が佳境かというと、最終話で書くつもりのバッファオーバーフローを利用した古き良き攻撃手法は、CALL命令によるサブルーチンの呼び出しと、サブルーチンの処理を終えて元の関数に戻るRET命令がキモだからです。

CALL命令とは

第零話:まずは動かしてみる 〜ブレイクポイントとステップ実行〜」で述べた話を少し振り返ります。

このお話でサンプルとして使っている実行ファイルは、main()からsub()を呼び出し(CALL)てsub()の処理を実行しmain()に戻る(RET)、ということをしています。

下図ではmain()は00401020から始まっていて、00401053でsub()を呼び出しています。sub()の最初のアドレスは00401000なので、「CALL 00401000」でsub()を呼び出し、00401000から0040101Aまで処理を進めたら「RETN」でmain()に戻る、という感じです。

sub()の処理が終わったらRETNでどこに戻ればいいのか?人間が目で見れば、一目瞭然ですよね。

が、コンピュータにはそんなことはできませんので、「RET命令が実行されたときに戻るべきアドレス」をどこかに書き込んでおかなければいけません。CALL命令を実行すると、その処理をしてくれます。

では実際にCALL命令実行の様子を見てみましょう。

sub()が呼び出される場所(「CALL 00401000」のアドレス)にブレイクポイントを設置し実行してください。EIPが「CALL 00401000」のアドレス(ここでは00401053)を指していることもついでに確認。

RET命令で戻るべき場所は、スタック領域に保存されます。スタック領域自体の説明は次話でするとして、今は「OllyDbgのデフォルトではスタック領域は右下のペインに表示される」ということだけ覚えておいてください。戻るべき場所は、「CALL 00401000」の直後の場所、00401058です。では、右下のスタック領域のペインに注目しつつ、ステップイン実行(F7押下)してみてください。

あっ。00401058という値がスタック領域に入りましたね!そしてEIPがsub()の最初のアドレス00401000に変わっています。

「00401058」が保存された場所は「0012FF28」ですね。スタック領域のどこに値を書き込むか/どこから取り出すかは、レジスタ「ESP」が指し示しています。

細かい話ですが、「戻るべきアドレス」は現在のEIPにCALL命令の命令長を足したもの、今回で言えば00401053 + 「CALL 00401000」の命令長(=E8 A8 FF FF FFの命令長=5バイト)= 00401058です。EIPの値を元に計算してます。

RET命令とは

さらにsub()に入ったところからRET命令までステップ実行してみて、スタック領域がどんな風に変わっているか見てみましょう。

先ほどのステップイン実行でsub()の最初に飛んでいるはずなので、F7押下でもう1個ステップ実行します。右下のスタック領域のペインが1行下がって何か値が入りましたね。1行下がっているので、ESPの値も変わります。

ESPと、ESPが指し示すスタック領域(スタック領域のペインのトップ行)に注目しながらRETNまでステップ実行してみてください。スタック領域が上がったり下がったりしつつ(ESPの値が上下しつつ)値が変わって行くのが分かります。

さて、RETNまで来ました。ここではESPは0012FF28ですね。
値は何が入っているでしょうか?

そうです!さっきcall()命令を実行したときに保存した、「sub()のRET命令が実行されたときに戻るべきアドレス」なのです!sub()内でスタック領域に値を書き込んだり取り出したりしますが、RET命令を実行する際には、ESPは戻るべきアドレスの値が入った場所を指し示します。便利。

この値をスタック領域から取り出し、EIPをその値に書き換えることで、正しくsub()が呼び出された直後の命令に戻るというわけです。

ということで、スタック領域の説明をガン無視してCALL/RET命令を説明してみました。ここでは、「なんかうまいことやって正しい位置に戻れるようにしてるんだなあ」ということが分かっていただければ十分かと思います。

次話はそのスタック領域について。nekotricolor怒りのPUSH/POP解説です。

(本稿はここで終わりです。ためになったという方、他のも読みたい!という方、投げ銭していただけると嬉しいです。)

ここから先は

0字

¥ 200

この記事が気に入ったらサポートをしてみませんか?