2011-12-06 76 views
2

以下のコードは、よく知られている記事Smashing The Stack For Fun And Profitのコードです。オーバーフローコードが機能しない

void function(int a, int b, int c) { 
    char buffer1[5]; 
    char buffer2[10]; 
    int *ret; 
    ret = buffer1 + 12; 
    (*ret)+=8; 
} 

void main() { 
    int x; 
    x=0; 
    function(1,2,3); 
    x=1; 
    printf("%d\n",x); 
} 

私はこのコードの目標を説明しなければならないと思います。 スタックモデルは以下のとおりです。単語の下の数字は、スタック内の変数のバイト数です。だから、もし私が望む文をスキップするためにRETを書き直したいのであれば、buffer1からRETまでのオフセットを8 + 4 = 12と計算する。アーキテクチャはx86 Linuxなので

buffer2 buffer1 BSP RET a b c 
(12) (8)  (4) (4) (4) (4) (4) 

私は声明x=1;をスキップして、画面上printf()出力0をさせたいです。

私はコードをコンパイル:

gcc stack2.c -g 

とGDBでそれを実行します。

Program received signal SIGSEGV, Segmentation fault. 
main() at stack2.c:17 
17 x = 1; 

私はLinuxの一部を使用思う:

gdb ./a.out 

gdbが私にこのような結果を与えますスタックのオーバーフローを防ぐメカニズム。おそらく、LinuxはRETアドレスを別の場所に格納し、関数が返る前にスタックのRETアドレスを比較します。

メカニズムの詳細はなんですか?プログラムの出力を0にするために、コードをどのように書き直すべきですか?

OK、逆アセンブルコードは以下の通りです.gdbの出力は、あなたのために読みやすくなっています。誰でも私に長いコードシーケンスを貼り付ける方法を教えていただけますか?私も疲れて...

Dump of assembler code for function main: 
0x08048402 <+0>: push %ebp 
0x08048403 <+1>: mov %esp,%ebp 
0x08048405 <+3>: sub $0x10,%esp 
0x08048408 <+6>: movl $0x0,-0x4(%ebp) 
0x0804840f <+13>: movl $0x3,0x8(%esp) 
0x08048417 <+21>: movl $0x2,0x4(%esp) 
0x0804841f <+29>: movl $0x1,(%esp) 
0x08048426 <+36>: call 0x80483e4 <function> 
0x0804842b <+41>: movl $0x1,-0x4(%ebp) 
0x08048432 <+48>: mov $0x8048520,%eax 
0x08048437 <+53>: mov -0x4(%ebp),%edx 
0x0804843a <+56>: mov %edx,0x4(%esp) 
0x0804843e <+60>: mov %eax,(%esp) 
0x08048441 <+63>: call 0x804831c <[email protected]> 
0x08048446 <+68>: mov $0x0,%eax 
0x0804844b <+73>: leave 
0x0804844c <+74>: ret 


Dump of assembler code for function function: 
0x080483e4 <+0>: push %ebp 
0x080483e5 <+1>: mov %esp,%ebp 
0x080483e7 <+3>: sub $0x14,%esp 
0x080483ea <+6>: lea -0x9(%ebp),%eax 
0x080483ed <+9>: add $0x3,%eax 
0x080483f0 <+12>: mov %eax,-0x4(%ebp) 
0x080483f3 <+15>: mov -0x4(%ebp),%eax 
0x080483f6 <+18>: mov (%eax),%eax 
0x080483f8 <+20>: lea 0x8(%eax),%edx 
0x080483fb <+23>: mov -0x4(%ebp),%eax 
0x080483fe <+26>: mov %edx,(%eax) 
0x08048400 <+28>: leave 
0x08048401 <+29>: ret 

私は、コードをアセンブルし、私のプログラムに関するいくつかの間違いを見つけチェックして、0x08048432 <+48>マイナス0x0804842b <+41>は7

+1

アセンブリが生成されていることを確認してください。おそらく、関数がインライン展開されている可能性があります。 – kan

+0

アセンブリコードをチェックしているので、関数がインライン化されていないことを約束します。 –

+1

'x = 1'は8バイトのアセンブリコードを生成し、スタックは表示されたようにレイアウトされていると仮定しています(そこに他のものもあります)。アセンブリリストを追加すれば、その答えは本当に明らかになります。 – Skizz

答えて

2

この記事は1996年のものであり、前提が正しくないためです。、

しかし、GNU Cコンパイラ(GCC)は、1998年から進化してきました:

は、上記のリンクから

http://www.ethicalhacker.net/content/view/122/24/

を "楽しさと利益のために近代的なスタックスマッシングする" を参照してくださいその結果、多くの人々が、なぜ彼らがそれらのために働く事例を得ることができないのだろうか、あるいは彼らが働くためのコードを手に入れたのか、どうして彼らが行った変更をしなければならないのか不思議に思っています。

+0

ありがとう! –

0

機能functionは、いくつかを上書きしているので、私は、(*ret)+=7(*ret)+=8を書き換える必要がありその外側のスタックの場所wn、この場合はmainのスタックです。上書きするとわかりませんが、セグメント違反が発生します。これは、オペレーティングシステムによって使用されるいくつかの保護かもしれませんが、スタック上のその位置に間違った値があると、生成されたコードが間違っています。

これは、割り当てられたメモリの外部に書き込むときに起こりうる実際の例です。それは直接クラッシュするかもしれませんが、まったく違う場所でクラッシュするかもしれません。クラッシュしないかもしれません。

+0

-1他の関数のスタックフレームをスタックのルートまで上書きすることはできません。この場合、彼はおそらくスタックの先頭を越えて書くでしょう( 'main()'を呼び出すコードに依存します) –

+2

セグメンテーションフォールトは、そのメモリの外に書き込むプロセスによって引き起こされます。 2つの関数は同じプロセスに属しているので、SIGSEGVを立ち上げることなく、お互いのメモリに手書きで書くことができます(コンパイラやOSがスタックスマッシュを防ぐために非常に奇妙なことをしない限り)。 – Jonathan

0

試しret = buffer1 + 3;

説明:ret整数ポインタです。 1をインクリメントすると、32ビットマシン上のアドレスに4バイトが追加されます。

+0

これは動作しません。 –

+3

'x'、' a'、 'buffer1'のアドレスを表示します。それはエラーのどちら側にあるかをあなたに知らせるはずです。 PS: "動作しません"というエラーメッセージは役に立ちません。この文章をもう一度使用しないでください。 :-) –

+0

OK.I "ret = buffer1 + 3"を書き直してプログラムを実行するのに疲れました。コードを疲れた後に最初のコメントを投稿します。しかし動作しません。 –