2012-11-11 38 views
5

Tôi đã cố gắng bỏ qua hướng dẫn bằng cách thay đổi địa chỉ trả lại thông qua ngăn xếp đập. Đoạn mã sau bỏ qua một ++ trong chính và in một đầu ra của "1 3". Tôi đã thực thi mã này trên máy intel 32 bit.Bỏ qua hướng dẫn sử dụng ngăn xếp đập

#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); 
} 

Tôi không thể hiểu tại sao địa chỉ trả lại được lưu trữ ở mức dịch chuyển 24 byte từ địa chỉ bắt đầu của buf. Tôi đã thử thực hiện cùng một mã trên một máy intel 32-bit khác nhau và tôi đã phải sử dụng một chuyển 20 byte thay vì 24 byte. Tôi đã đặt sự hiểu biết của tôi trong hình dưới đây. Tôi không chắc chắn về những gì lấp đầy khoảng cách được đại diện bởi "?" trong hình. Gcc có đặt bất kỳ giá trị canary nào hay tôi đang thiếu thứ gì đó?

Liên kết đến hình: http://www.cse.iitb.ac.in/~shashankr/stack.png

Smashing the stack example3.c confusion hỏi những câu hỏi tương tự, nhưng không thể giải thích lý do của việc dịch chuyển nói chung.

Hình dưới đây cho biết chế độ xem của ngăn xếp thu được bằng cách đặt điểm ngắt trong chức năng.

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

Sau đây là mã lắp ráp cho vui chính và:

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

Xin lưu ý rằng tôi đã tìm ra giá trị 24 bằng thử và sai. Ngoài ra, giá trị 5 thông qua gdb tháo gỡ chức năng chính. – shashank

+0

Biến 'p' cũng phải nằm trên ngăn xếp, vì vậy bạn có thể thêm 4 byte vào đó, tôi tin. Tôi không chắc phần còn lại đến từ đâu. –

+0

Nhìn lại nó cũng có khả năng là các đối số 'a' và' b' không bao giờ bị loại bỏ khỏi ngăn xếp vì lý do hiệu quả, do đó chiếm phần còn lại của bộ nhớ. –

Trả lời

2

Tôi tin rằng câu trả lời là không có gì. Bạn có các phiên bản gcc khác nhau không? Dù sao một trình biên dịch được phép phân bổ nhiều hơn một chút so với cần thiết. Có lẽ đó là "phỏng đoán" ban đầu dựa trên số lượng các biến, nhưng không bị giảm bởi các giai đoạn tối ưu hóa, được phép chuyển bất kỳ biến nào vào sổ đăng ký. Hoặc đó là một số hồ chứa để tiết kiệm ecx, ebp hoặc các thanh ghi khác trong trường hợp chương trình con cần.

Vẫn có một biến địa chỉ cố định để khắc phục sự cố: a. Địa chỉ trả lại = & a [-1].

+0

Có, các máy có các phiên bản gcc khác nhau. Bạn có thể đúng về gcc phân bổ thêm một số không gian trên stack. Khi tôi thực hiện cùng một mã trên máy thứ hai, tôi nhận thấy rằng kích thước của khung ngăn xếp xuất hiện. Nó cũng có thể là do gcc trên máy đầu tiên được sử dụng giá trị canary. Khi tôi đã làm một strcpy để tràn bộ đệm, tôi có một lỗi smash ngăn xếp trên máy đầu tiên.Điều này đã không xảy ra trên máy thứ hai như gcc là phiên bản cũ hơn và có lẽ đã không sử dụng giá trị canary. Ngoài ra, cảm ơn bạn đã đề xuất cách giải quyết để tìm địa chỉ trả lại thông qua địa chỉ của một địa chỉ. – shashank

Các vấn đề liên quan