infunction()
をスキップするために within のリターン アドレスを変更するには、2 つの情報が必要です。x = 1
main()
1. スタック フレーム内のリターン アドレスの位置。
この値を決定するために gdb を使用しました。( ) にブレークポイントを設定し、ブレークポイントまでコードを実行しfunction()
( ) 、現在のスタック フレームのメモリ内の場所を取得し (または)、( ) のメモリ内の場所を取得します。取得した値を使用して、リターン アドレスの場所を特定できます。break function
run
p $rbp
info reg
buffer
p &buffer
(GCC-g
フラグを使用してコンパイルし、デバッグ シンボルを含め、64 ビット環境で実行)
(gdb) break function
...
(gdb) run
...
(gdb) p $rbp
$1 = (void *) 0x7fffffffe270
(gdb) p &buffer
$2 = (char (*)[5]) 0x7fffffffe260
(gdb) quit
(フレーム ポインタ アドレス + ワードのサイズ) - バッファ アドレス = ローカル バッファ変数からリターン アドレスまでのバイト数
(0x7fffffffe270
+ 8) -0x7fffffffe260
= 24
コール スタックの仕組みを理解するのが難しい場合は、コール スタックと関数プロローグのウィキペディアの記事を読むと役立つ場合があります。これは、C で「バッファ オーバーフロー」の例を作成することの難しさを示しています。24 からのオフセットbuffer
は、特定のパディング スタイルとコンパイル オプションを想定しています。現在、 GCC は、スタック カナリアを挿入しないように指示しない限り、喜んで挿入します。
2. スキップする戻りアドレスに追加するバイト数x = 1
。
0x00000000004002f4
あなたの場合、保存された命令ポインターは( )を指し<main+35>
、関数が戻った後の最初の命令です。0x00000000004002fb
割り当てをスキップするには、保存された命令ポインターが( )を指すようにする必要があります<main+42>
。
これが 7 バイトであるという計算は正しいです ( 0x4002fb
- 0x4002fb
= 7 )。
gdb を使用してアプリケーション ( disas main
) を逆アセンブルし、私の場合の計算も検証しました。この値は、分解を調べて手動で解決するのが最適です。
Ubuntu 10.10 64 ビット環境を使用して、次のコードをテストしたことに注意してください。
#include <stdio.h>
void function(int a, int b, int c)
{
char buffer[5];
int *ret;
ret = (int *)(buffer + 24);
(*ret) += 7;
}
int main()
{
int x = 0;
function(1, 2, 3);
x = 1;
printf("x = %i \n", x);
return 0;
}
出力
x = 0
function()
これは、実際のバッファ オーバーフローではなく、単にリターン アドレスを変更しているだけです。実際のバッファ オーバーフローでは、オーバーフローbuffer[5]
して戻りアドレスを上書きします。ただし、最新の実装のほとんどは、これを防ぐためにスタック カナリアなどの手法を使用しています。