1

Cでのスタックオーバーフローについて質問があります。小さなテストプログラムを作成したので、8で開始すると、期待どおりの結果が得られ、2番目のbufの境界を上書きします。そのため、buf1は空になります。末尾のゼロは、buf1の最初の要素になりました。これまでのところ、16で試してみると、17 Asでイベントも機能するので、うまくいきます。しかし、私はここでセグメンテーション違反を期待します...セグメンテーション違反は24Asの後に発生します。何故ですか?x86-32 ubuntu、debian、suseでテストしました。常に24バイト後にsegfault...同じコードのAMD64システムでは、32 As後にsegfaultが発生します。予想どおり、24後のx86-32ではなぜですか????

含む

  #include <string.h>

  /*
  * $ gcc -O0 -Wall -fno-stack-protector buffer.c -o buffer
  *
  * $ ./buffer AAAAAAAA
  * buf1: test
  * buf2: test
  * buf1:
  * buf2: AAAAAAAA
  *
  * $ ./buffer AAAAAAAAAAAAAAAAAAAAAAAA
  * buf1: test
  * buf2: test
  * buf1: AAAAAAAAAAAAAAAA
  * buf2: AAAAAAAAAAAAAAAAAAAAAAAA
  * Segmentation fault (core dumped)
  */

  static void exploit(const char *InputString)
  {
char buf1[8];
char buf2[8];

strcpy(buf1, "test");
strcpy(buf2, "test");

printf("buf1: %s\n", buf1);
printf("buf2: %s\n", buf2);

strcpy(buf2, InputString);

printf("buf1: %s\n", buf1);
printf("buf2: %s\n", buf2);
  }


  int main(int argc, const char *argv[])
  {
if (argc > 1)
  exploit(argv[1]);

return 0;
  } 
4

1 に答える 1

0

コンパイラによって生成されたメモリレイアウトを推測しようとしています。コンパイラーは、適切と思われる方法でコードを自由にレイアウトできます。ただし、スタックフレームには次のものが含まれている必要があります。

  • 引数(呼び出し元によってプッシュされた)
  • リターンアドレス(CPUによってプッシュされます)
  • 保存する必要のあるレジスタ。これは、ターゲットアーキテクチャによって異なります。
  • ローカル変数(呼び出し先によって割り当てられます)

テストしたx86マシンではローカル変数とリターンアドレスの間に8バイトがあり、x64マシンでは16バイトです。レジスタが呼び出し先によって保存されている場合、それらは次のスペースに格納されます。

func:
PUSH BP
MOV BP, SP
SUB SP, privateSpace
...
MOV SP, BP
POP BP
RET argSize

http://en.wikipedia.org/wiki/Calling_convention#x86

したがって、リターンアドレスの直後のスペースには、格納されているフレームポインタBPが含まれます。呼び出し元がベースポインタを二度と使用しない場合、この上書きは認識されません。関数はそのベースポインターを使用して戻りますが、関数がシステムコールを介して終了する場合(この意味でメインメソッドが「特別」であることを覚えていますが、主張を引き出すことはできません)、破損したベースポインターは使用されず、破損します。見過ごされます)。

それがベースポインタであるかどうかをテストするには:

  • 第3レベルの呼び出し(メイン、呼び出し元、呼び出し先)を作成します。
  • 呼び出し先からのリターンをログに記録し、ローカル変数にアクセスして、再度ログに記録し、リターンします。
  • ローカル変数にアクセスするときにセグメンテーション違反が発生した場合は、ベースポインタである可能性があります。

その他の考えられる原因:

  • エラーが発生した場合に使用されるデバッグ情報。
  • テストされることはないが、とにかく割り当てられるカナリア(スタックプロテクター)。症状は一切ありません。
  • 引数の数(syscall)これを破損すると、呼び出し元のスタックポインターが破損します。これは、呼び出し元が別の呼び出しを行わない場合、気付かれなくなります。症状:発信者が2回目の呼び出しを行うと、発信者のsegfaultが発生します。
  • thisポインタ。通常の機能には存在しないでください。

他に試すべきこと:

破損の前後に呼び出し先にメモリダンプを作成して、レイアウトを確認します。保存されたベースポインタは、スタックスペース(呼び出し元のスタックフレーム)を指している必要があります。リターンアドレスは、コードスペース(現在のIPの近く)を指している必要があります。char*引数はポインターです。他の2つの引数(>>>>"および"<<<"as char[4])を隣接させると、認識に役立ちます。

于 2012-10-14T06:37:17.263 に答える