2012-11-11 11 views
5

スタックスマッシングでリターンアドレスを変更して命令をスキップしようとしました。次のコードは、mainの++をスキップし、 "1 3"の出力を出力します。私はこのコードを32ビットのIntelマシン上で実行しました。スタックスマッシングを使用して命令をスキップ

#include<stdio.h> 
void fun(int a,int b) { 
    // buffer 
    char buf[8]; 
    char *p; 
    p = (char *)buf+24; 
    *p=*p+5; 
    return; 
} 

int main() { 
    int a=1,b=2; 
    fun(a,b); 
    a++; 
    b++; 
    printf("%d %d",a,b); 
} 

戻りアドレスがbufの開始アドレスから24バイトの位置に格納されている理由を理解できません。別の32ビットIntelマシンで同じコードを実行しようとしましたが、24バイトの代わりに20バイトのディスプレースメントを使用しなければなりませんでした。私は次の図に私の理解を入れました。私は「?」で表されるギャップを埋めるものが何であるかについてはわかりません。図では、 gccはそこにカナリアの価値を置いているのですか、何か不足していますか?図に

リンク:

Smashing the stack example3.c confusionhttp://www.cse.iitb.ac.in/~shashankr/stack.pngは、同じ質問をしますが、一般的に変位した理由を説明することができませんでした。

次の図は、機能にブレークポイントを配置して得られるスタックを示しています。

stack content http://www.cse.iitb.ac.in/~shashankr/stack4.png

次はメインと楽しみのためのアセンブリコードです:

Dump of assembler (fun): 
0x08048434 <+0>: push %ebp 
0x08048435 <+1>: mov %esp,%ebp 
0x08048437 <+3>: sub $0x18,%esp 
0x0804843a <+6>: mov %gs:0x14,%eax 
0x08048440 <+12>: mov %eax,-0xc(%ebp) 
0x08048443 <+15>: xor %eax,%eax 
0x08048445 <+17>: lea -0x14(%ebp),%eax 
0x08048448 <+20>: add $0x18,%eax 
0x0804844b <+23>: mov %eax,-0x18(%ebp) 
0x0804844e <+26>: mov -0x18(%ebp),%eax 
0x08048451 <+29>: movzbl (%eax),%eax 
0x08048454 <+32>: add $0x5,%eax 
0x08048457 <+35>: mov %eax,%edx 
0x08048459 <+37>: mov -0x18(%ebp),%eax 
0x0804845c <+40>: mov %dl,(%eax) 
0x0804845e <+42>: mov -0xc(%ebp),%eax 
0x08048461 <+45>: xor %gs:0x14,%eax 
0x08048468 <+52>: je  0x804846f <fun+59> 
0x0804846a <+54>: call 0x8048350 <[email protected]> 
0x0804846f <+59>: leave 
0x08048470 <+60>: ret  


Dump of assembler (main) 
0x08048471 <+0>: push %ebp 
0x08048472 <+1>: mov %esp,%ebp 
0x08048474 <+3>: and $0xfffffff0,%esp 
0x08048477 <+6>: sub $0x20,%esp 
0x0804847a <+9>: movl $0x1,0x18(%esp) 
0x08048482 <+17>: movl $0x2,0x1c(%esp) 
0x0804848a <+25>: mov 0x1c(%esp),%eax 
0x0804848e <+29>: mov %eax,0x4(%esp) 
0x08048492 <+33>: mov 0x18(%esp),%eax 
0x08048496 <+37>: mov %eax,(%esp) 
0x08048499 <+40>: call 0x8048434 <fun> 
0x0804849e <+45>: addl $0x1,0x18(%esp) 
0x080484a3 <+50>: addl $0x1,0x1c(%esp) 
0x080484a8 <+55>: mov $0x80485a0,%eax 
0x080484ad <+60>: mov 0x1c(%esp),%edx 
0x080484b1 <+64>: mov %edx,0x8(%esp) 
0x080484b5 <+68>: mov 0x18(%esp),%edx 
0x080484b9 <+72>: mov %edx,0x4(%esp) 
0x080484bd <+76>: mov %eax,(%esp) 
0x080484c0 <+79>: call 0x8048340 <[email protected]> 
0x080484c5 <+84>: leave 
0x080484c6 <+85>: ret  
+0

試行錯誤の結果、値24がわかりました。また、5からgdbのmain関数の値を逆アセンブルします。 – shashank

+0

変数 'p'もスタック上になければならないので、そこに4バイトを追加することができます。私は残りがどこから来ているのか分からない。 –

+0

振り返ってみると、引数 'a'と 'b'が効率の理由からスタックから削除されないため、残りのメモリを考慮している可能性があります。 –

答えて

2

私は答えは何もないと信じています。 gccのバージョンが違いますか?とにかく、コンパイラは必要以上にスタックを割り当てることができます。おそらく、変数の数に基づいた最初の「推測」ですが、変数をレジスタに移動することができる最適化段階では減少しません。または、サブルーチンが必要な場合にecx、ebp、または他のレジスタを保存するためのリザーバです。

問題を解決するには固定アドレス変数が1つあります:です。 戻りアドレス= & a [-1]です。

+0

はい、マシンには異なるgccバージョンがあります。 gccがスタック上に余分なスペースを割り当てることは正しいかもしれません。 2番目のマシンで同じコードを実行すると、スタックフレームのサイズが小さくなっていることがわかりました。また、最初のマシンのgccがcanary値を使用している可能性もあります。バッファをオーバーフローさせるためにstrcpyを実行したとき、最初のマシンでスタック・スマッシュ・エラーが発生しました。これはgccが古いバージョンであり、おそらくカナリー値を使用していないため、2番目のマシンでは発生しませんでした。また、アドレスを介して返信先の場所を見つけるための回避策を提案していただきありがとうございます。 – shashank

関連する問題