9

記事はここにあります。

私はスタックを壊すことを読んでいて、example3.cで立ち往生していることに気づきました。

0x80004a3 <main+19>:    call   0x8000470 <function>
0x80004a8 <main+24>:    addl   $0xc,%esp
0x80004ab <main+27>:    movl   $0x1,0xfffffffc(%ebp)
0x80004b2 <main+34>:    movl   0xfffffffc(%ebp),%eax

著者は、からにスキップしたいこと、0x80004a8および0x80004b2このジャンプは8バイトであることを示しています。著者はこれが8バイトであるとどのように判断しましたか?コードを再作成して送信したobjdumpところ、8バイトではないことがわかりました(64ビットマシンを使用していますが、32ビットを使用してコンパイルするようにしています)。

8048452:    e8 b5 ff ff ff          call   804840c <function>
8048457:    c7 44 24 1c 01 00 00    movl   $0x1,0x1c(%esp)
804845e:    00 
804845f:    8b 44 24 1c             mov    0x1c(%esp),%eax
8048463:    89 44 24 04             mov    %eax,0x4(%esp)
8048467:    c7 04 24 18 85 04 08    movl   $0x8048518,(%esp)

著者はまた、「差出人住所に8を追加することをどのようにして知ったのですか?最初にテスト値を使用しました(たとえば1)」と述べました。彼はどこでこのテスト値を使用しましたか?

4

2 に答える 2

3

それは私が記事を解釈する方法ではありません。私が理解しているように、彼はx = 1;割り当てがスキップされるようにリターンアドレスを変更したいと考えています。つまり、彼は実行されるfunction場所に戻りたいと考えていprintfます。

逆アセンブルでわかるように、割り当ては 8 バイト ( c7 44 24 1c 01 00 00 00) であるため、戻りアドレスを 8 バイト前方に移動すると、この命令を超えて移動します。「最初にテスト値を使用しました」というコメントについては..おそらく彼は、逆アセンブラでコードを見て長さを調べた、またはさまざまなオフセットを試した(?)ことを意味しているだけかもしれません。

于 2012-10-22T08:24:06.403 に答える
1

10記事の変位が間違っています。バイトのはずです。関数が呼び出される (またはジャンプが実行される) と、戻りアドレスは命令ポインター + 現在の命令サイズに等しくなるように設定されます。

ret = IP + Curr_Inst_size

したがって、関数への呼び出しが戻ると、命令ポインターは0x80004a8( 0x80004a3+ 呼び出し命令のサイズ) に等しくなるはずです。

    0x80004a3 <main+19>:    call   0x8000470 <function>
--> 0x80004a8 <main+24>:    addl   $0xc,%esp            
    0x80004ab <main+27>:    movl   $0x1,0xfffffffc(%ebp)
    0x80004b2 <main+34>:    movl   0xfffffffc(%ebp),%eax

ただし、代入をスキップする0x80004b2ために代わりに命令ポインターを設定したい場合、必然的に、そこに到達するために別の命令をスキップする必要があります。つまり、命令ポインターにバイトまたは 10 バイトを追加する必要があります。これらの 2 つの手順をスキップするには:(addl $0xc,%esp)(0x80004b2-0x80004a8)

    0x80004a3 <main+19>:    call   0x8000470 <function>
    0x80004a8 <main+24>:    addl   $0xc,%esp            
    0x80004ab <main+27>:    movl   $0x1,0xfffffffc(%ebp)
--> 0x80004b2 <main+34>:    movl   0xfffffffc(%ebp),%eax 

実際の命令サイズは、オペランド、マシン タイプなどによって異なります。ただし、この例では、addlは 3 バイト長で、movlは 7 バイト長です。x86 Instruction Set Referenceで正確な命令サイズを確認するか、このコードをコンパイルして逆アセンブルすると、これら 2 つの命令の長さが 10 バイトであることがわかります。

int main()
{
    asm("addl  $0xc,%esp\n\
         movl  $0x1,0xfffffffc(%ebp)");

}

gdb:

0x08048397 <+3>: 83 c4 0c               add    $0xc,%esp
0x0804839a <+6>: c7 45 fc 01 00 00 00   movl   $0x1,-0x4(%ebp)

例 3 とまったく同じ問題について、ここここでも議論があります。

于 2012-10-22T09:59:11.057 に答える