2016-08-11 17 views
8

Tôi hiện đang đọc (lần thứ hai) "Hacking: The Art of Exploitation" và đã tình cờ gặp điều gì đó.Gcc có sắp xếp lại các biến cục bộ tại thời gian biên dịch không?

Cuốn sách cho thấy hai cách khác nhau để khai thác hai chương trình tương tự: auth_overflowauth_overflow2

Trong giai đoạn đầu, có một chức năng kiểm tra mật khẩu đặt ra như thế này

int check_authentication(char *password) { 
    int auth_flag = 0; 
    char password_buffer[16]; 

    strcpy(password_buffer, password); 
    ... 
} 

inputing hơn 16 Ký tự ASCII sẽ thay đổi giá trị của auth_flag thành giá trị lớn hơn 0, do đó bỏ qua kiểm tra, như được hiển thị trên đầu ra gdb này:

gdb$ x/12x $esp 
0xbffff400: 0xffffffff 0x0000002f 0xb7e0fd24 0x41414141 
0xbffff410: 0x41414141 0x41414141 0x41414141 0x00000001 
0xbffff420: 0x00000002 0xbffff4f4 0xbffff448 0x08048556 

password_buffer @ 0xbffff40c 
auth_flag @ 0xbffff41c 

Chương trình thứ hai sẽ đảo ngược hai biến:

int check_authentication(char *password) { 
    char password_buffer[16]; 
    int auth_flag = 0; 

    strcpy(password_buffer, password); 
    ... 
} 

Tác giả sau đó gợi ý hơn đó là không thể tràn vào auth_flag, mà tôi thực sự tin tưởng. Tôi sau đó tiến hành tràn bộ đệm, và ngạc nhiên của tôi, nó vẫn hoạt động. Biến auth_flag vẫn ngồi sau bộ đệm, như bạn có thể nhìn thấy trên đầu ra gdb này:

gdb$ x/12x $esp 
0xbffff400: 0xffffffff 0x0000002f 0xb7e0fd24 0x41414141 
0xbffff410: 0x41414141 0x41414141 0x41414141 0x00000001 
0xbffff420: 0x00000002 0xbffff4f4 0xbffff448 0x08048556 

password_buffer @ 0xbffff40c 
auth_flag @ 0xbffff41c 

Tôi tự hỏi nếu gcc không sắp xếp lại các biến cục bộ cho các mục đích Alignement/tối ưu hóa.

Tôi đã cố gắng biên dịch bằng cờ -O0, nhưng kết quả cũng giống nhau.

Có ai trong số các bạn biết tại sao điều này xảy ra không?

Xin cảm ơn trước.

+3

"Sắp xếp lại" bằng cách nào đó ngụ ý rằng bạn mong đợi có một "thứ tự" ban đầu. C++ không thực sự chỉ định bất kỳ loại thứ tự lưu trữ các biến cục bộ nào, bộ nhớ của chúng được gọi là "tự động" - tức là đừng hỏi đừng nói. –

+0

Tôi mong đợi trình biên dịch (với tối ưu hóa của nó bị vô hiệu hoá) để lại thứ tự như được tuyên bố trong mã. Nhưng tôi không biết nhiều về trình biên dịch. Tác giả của cuốn sách dường như cũng mong đợi hành vi tương tự. Tôi vẫn quản lý để làm cho nó hoạt động như tôi muốn bằng cách tuyên bố cả hai biến biến động. – rgehan

+2

Vâng, mong đợi của bạn không may là không tương quan với các quy tắc ngôn ngữ. (Xin lỗi, bạn nói C, không phải C++, nhưng cùng một điểm áp dụng.) "Thực tế khác với mong đợi cá nhân" sẽ là một bản tóm tắt thích hợp về kinh nghiệm của bạn :-) Tự động lưu trữ chỉ là "tự động ở đó", với rất ít chi tiết được bảo đảm. –

Trả lời

11

Tác giả trình biên dịch hoàn toàn miễn phí để triển khai bất kỳ lược đồ phân bổ nào cho các biến cục bộ có lưu trữ tự động. auth_flag có thể được đặt trước hoặc sau password_buffer trên ngăn xếp, nó có thể được đăng ký, nó có thể được elided hoàn toàn nếu phân tích thích hợp của mã cho phép nó. Có thể thậm chí không có ngăn xếp ... Chỉ đảm bảo tiêu chuẩn cung cấp cho bạn là:

strcpy(password_buffer, password); gọi hành vi không xác định nếu chuỗi nguồn có dấu kết thúc null dài hơn mảng đích password_buffer. Cho dù hành vi không xác định này phù hợp với nhu cầu của bạn hoàn toàn nằm ngoài đặc tả ngôn ngữ hay không.

Như một vấn đề của thực tế, một số người triển khai cố ý làm phức tạp nhiệm vụ sẽ là tin tặc bằng cách ngẫu nhiên hành vi trong các trường hợp như mã được đăng.

+0

Đó là những gì Kerrek SB và user694733 đã chỉ ra. Tôi đã không nghĩ rằng đầu ra từ một trình biên dịch có thể hoàn toàn khác với trình biên dịch khác. Điều này hoàn toàn có ý nghĩa. Cảm ơn :) – rgehan

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