7

バッファ オーバーフローの脆弱性の基本を調べ、スタックがどのように機能しているかを理解しようとしました。そのために、戻りアドレスのアドレスを何らかの値に変更する簡単なプログラムを書きたいと思いました。最初の引数からオフセットを取得するために、ベース ポインターのサイズを把握するのを手伝ってくれる人はいますか?

void foo(void)
{
    char ret;
    char *ptr;

    ptr = &ret; //add some offset value here 
    *ptr = 0x00;
}

int main(int argc, char **argv)
{
    foo();

    return 1;
}

生成されたアセンブラ コードは次のようになります。

    .file   "test.c"
    .text
    .globl  foo 
    .type   foo, @function
foo:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16 
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    leaq    -9(%rbp), %rax
    movq    %rax, -8(%rbp)
    movq    -8(%rbp), %rax
    movb    $0, (%rax)
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret 
    .cfi_endproc
.LFE0:
    .size   foo, .-foo
    .globl  main
    .type   main, @function
main:
.LFB1:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16 
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    movl    %edi, -4(%rbp)
    movq    %rsi, -16(%rbp)
    call    foo 
    movl    $1, %eax
    leave
    .cfi_def_cfa 7, 8
    ret 
    .cfi_endproc
.LFE1:
    .size   main, .-main
    .ident  "GCC: (GNU) 4.7.1 20120721 (prerelease)"
    .section    .note.GNU-stack,"",@progbits

foo フレーム セグメントの関連部分は次のようになります。

[char ret] [ベースポインタ] [リターンアドレス]

サイズがわずか1バイトの最初の位置があります。http://insecure.org/stf/smashstack.htmlに記載されているように、ベースポインターまたは単語のサイズから1バイトだけ離れていますか? また、ベースポインタのサイズを知るにはどうすればよいですか?

4

3 に答える 3

1

バニラ C でこれを行うことはできません。コンパイラがスタック フレームをどのようにレイアウトするかを制御することはできません。

x86-64 では、リターン アドレスは にあります%rbp + 8。インラインアセンブリを使用してそれを取得できます(gcc構文):

uint64_t returnaddr;
asm("mov 8(%%rbp),%0" : "=r"(returnaddr) : : );

設定も同様です。

コンパイラがセットアップするかどうかわからないので、それでも少し大雑把です%rbp。YMMV。

于 2012-09-27T21:47:05.377 に答える
1

ベースポインターはおそらく単なるポインターであるため、サイズは sizeof(int*) です。retただし、変数とベース ポインターの間には別の値もあります。レジスタの値を想定します(eax?)。無限ループが必要な場合、これは次のような結果になります。

void foo(void)
{
    char ret;
    char *ptr;

    ptr = (char*)(&ret) + (sizeof(ret)  + 2*sizeof(int*)) ;
    *(int*)ptr -= 0x0c;
}

ポインターのサイズを持つと仮定して変更される戻りターゲット (他の命令セットでは異なる場合があります)。デクリメントすることで、復帰先を の呼び出し点より前に設定しfooます。

于 2012-09-27T22:43:42.267 に答える
0

RBP および RSP レジスタは 64 ビット長であるため、64 ビット アーキテクチャを使用しているようです。ptrasを宣言するchar*と、スタックを移動するために 8 回インクリメントする必要があります。代わりに、次のように宣言できますuint64_t *。通常、このデータ型は で使用できます<stdint.h>

ただし、スタック フレームの定義は、ターゲット アーキテクチャによって異なり、コンパイラの動作や最適化によっても異なります。お試し程度なら大丈夫ですけどね。

于 2012-09-27T21:45:31.090 に答える