3

次のような関数があります。

int bof(char *str)
{
    char buffer[12];

    strcpy(buffer, str);

    return 1;
}

その差出人住所を上書きしようとしています。たとえば、を使用してこれを行うことができることがわかりましたmemcpy(buffer+24, "\x15\xf1\xff\xbf", 4)。理解できないのは、なぜ にアクセスする必要があるのか​​ということですbuffer + 24。私の C メモリ モデルの理解によると、この関数が実行されたときのスタックは次のようになります。

bottom of                                                            top of
memory                                                               memory
           buffer(12)     sfp(4)   ret(4)   str(4)
<------   [            ][       ][       ][       ] --->

top of                                                            bottom of
stack                                                                 stack

これは、ret アドレスを buffer+16 から開始する必要があることを示唆しています。余分な 8 バイトはどこから入ってくるのでしょうか?

ちなみに、私はこれを32ビットシステムで実行しています。

4

2 に答える 2

3

ISO C 99 およびそれ以前の標準を確認すると、C メモリ モデルのようなものがないことがわかります。すべてのコンパイラは、機能仕様を満たすために好きなモデルを自由に使用できます。簡単な例の 1 つは、コンパイラがフレーム ポインタを使用または省略できることです。また、戻り値にスペースを割り当てたり、レジスタを使用したりすることもできます。

このコードを自分のマシンでコンパイルすると、

_bof:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $40, %esp
    movl    8(%ebp), %eax
    movl    %eax, 4(%esp)
    leal    -20(%ebp), %eax
    movl    %eax, (%esp)
    call    _strcpy
    movl    $1, %eax
    leave
    ret

leal命令は でバッファ開始位置を計算していますbp-20。プロローグの後、スタック フレームは次のようになります。

[ bp+8: str ] [bp+4: rtn address ] [bp: saved bp] [ bp-20: buf ] ...

したがって、ここで戻りアドレスを変更するには、28 バイトを書き込む必要があるようです。私の推測では、コンパイラはスタック フレームを段落の境界に揃えようとしていると思われます。strcpy arg セットアップを含むフル フレームは 48 バイトで、3 段落です。段落の配置は、バスとキャッシュのパフォーマンスに役立ちます。

于 2012-11-06T05:36:26.410 に答える
2

これは、C メモリ モデルまたは C 関数呼び出しスタック レイアウトではありません。これは、特定のコンパイラとハードウェア アーキテクチャについて知っている単なる実装です。ARM 32 ビット CPU では、関数呼び出しの引数 1 ~ 4 はスタックにプッシュされず、r0 ~ r3 を使用して引数を渡し、4 つ以上の引数がある場合は他の引数をスタックにプッシュします。関数の戻りアドレス戻りアドレスを保持するための特別なレジスタ LR があるため、スタックへのプッシュも必要ない場合があります。

于 2012-11-06T07:01:42.820 に答える