2012-11-11 36 views
5

我一直試圖通過改變堆棧粉碎的返回地址來跳過指令。以下代碼跳過主要的++並打印「1 3」的輸出。我在32位的英特爾機器上執行了此代碼。使用堆棧粉碎跳過指令

#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位英特爾機器上執行相同的代碼,我不得不使用20字節而不是24字節的位移。我已將我的理解放在下圖中。我不確定填補「?」代表的差距是什麼在圖中。海灣合作委員會在那裏放置任何金絲雀價值還是我錯過了什麼?

鏈接圖:http://www.cse.iitb.ac.in/~shashankr/stack.png

Smashing the stack example3.c confusion問同樣的問題,但不能解釋一般位移的原因。

下圖給出了通過在函數中放置斷點獲得的堆棧視圖。

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。另外,通過gdb反彙編main函數的值爲5。 – shashank

+0

變量'p'也應該在堆棧中,所以你可以在那裏添加4個字節,我相信。我不確定餘額是從哪裏來的。 –

+0

現在回想起來,出於效率的原因,參數'a'和'b'也不會從棧中移除,因此會佔用內存的其餘部分。 –

回答

2

我相信答案是什麼。你有不同的gcc版本嗎?無論如何,允許編譯器分配比所需更多的堆棧。也許這是基於變量數目的初始「猜測」,但是這並不是通過優化階段來減少的,這些優化階段允許將任何變量移動到寄存器。或者在子例程需要的時候保存ecx,ebp或其他寄存器。

反正有一個固定的地址變量可以解決這個問題:a。 返回地址= & a [-1]。

+0

是的,這些機器有不同的gcc版本。你可能對gcc在堆棧上分配一些額外的空間是正確的。當我在第二臺機器上執行相同的代碼時,我注意到堆棧幀的大小降低了。這也可能是因爲第一臺機器上的gcc使用了金絲雀的價值。當我做了一個strcpy溢出緩衝區時,我在第一臺機器上出現了堆棧粉碎錯誤。這在第二臺機器上沒有發生,因爲gcc是舊版本,可能沒有使用金絲雀的價值。另外,感謝您提供一種解決方法,通過地址查找返回地址的位置。 – shashank