2012-10-22 21 views
9

Điều có thể được tìm thấy here.Đập vỡ ngăn xếp example3.c nhầm lẫn

Tôi đang đọc trên đập vỡ ngăn xếp và thấy mình bị kẹt trên example3.c.

0x80004a3 <main+19>: call 0x8000470 <function> 
0x80004a8 <main+24>: addl $0xc,%esp 
0x80004ab <main+27>: movl $0x1,0xfffffffc(%ebp) 
0x80004b2 <main+34>: movl 0xfffffffc(%ebp),%eax 

Tác giả chỉ ra rằng chúng ta muốn bỏ qua 0x80004a8-0x80004b2 và nhảy này là 8 byte; tác giả đã xác định điều này là 8 byte như thế nào? Tôi đã tái mã và gửi nó qua objdump và thấy rằng nó không phải là 8 byte (Tôi đang trên một máy 64 bit nhưng tôi đã thực hiện chắc chắn để biên dịch sử dụng 32 bit):

8048452: e8 b5 ff ff ff   call 804840c <function> 
8048457: c7 44 24 1c 01 00 00 movl $0x1,0x1c(%esp) 
804845e: 00 
804845f: 8b 44 24 1c    mov 0x1c(%esp),%eax 
8048463: 89 44 24 04    mov %eax,0x4(%esp) 
8048467: c7 04 24 18 85 04 08 movl $0x8048518,(%esp) 

Tác giả cũng cho biết " Làm cách nào chúng ta biết thêm 8 vào địa chỉ trả lại? Trước tiên, chúng tôi đã sử dụng giá trị thử nghiệm (ví dụ 1) "Giá trị thử nghiệm này ở đâu?

+0

Moving StackOverflow theo yêu cầu người dùng. (+1, câu hỏi hay.) –

+0

Nếu bạn trừ các địa chỉ giống như trong bài viết đó, bạn nhận được 10 byte :) kiểm tra các liên kết ở phần cuối của câu trả lời của tôi, bù đắp là sai. – iabdalkader

+1

Có một câu trả lời cho biết rằng nó đã được sửa đổi. Đây là [sửa đổi] mới nhất (https://avicoder.me/2016/02/01/smashsatck-revived/) – NathanOliver

Trả lời

-1

Sau nhiều thời gian và suy nghĩ, cuối cùng tôi đã giải quyết được vấn đề. Tài nguyên đã giúp tôi giải quyết vấn đề này là Stack smashing code not working on Linux kernel 2.6.38.7... Please help

Thay đổi lớn nhất đã giúp tôi giải quyết vấn đề này là sử dụng disassembly-flavor intel cho gdb.

đang

tháo rời (để tham khảo):

0804840c <function>: 
804840c: 55      push ebp 
804840d: 89 e5     mov ebp,esp 
804840f: 83 ec 10    sub esp,0x10 
8048412: 8d 45 f7    lea eax,[ebp-0x9] 
8048415: 83 c0 14    add eax,0x14 
8048418: 89 45 fc    mov DWORD PTR [ebp-0x4],eax 
804841b: 8b 45 fc    mov eax,DWORD PTR [ebp-0x4] 
804841e: 8b 00     mov eax,DWORD PTR [eax] 
8048420: 8d 50 05    lea edx,[eax+0x5] 
8048423: 8b 45 fc    mov eax,DWORD PTR [ebp-0x4] 
8048426: 89 10     mov DWORD PTR [eax],edx 
8048428: c9      leave 
8048429: c3      ret  

0804842a <main>: 
804842a: 55      push ebp 
804842b: 89 e5     mov ebp,esp 
804842d: 83 e4 f0    and esp,0xfffffff0 
8048430: 83 ec 20    sub esp,0x20 
8048433: c7 44 24 1c 00 00 00 mov DWORD PTR [esp+0x1c],0x0 
804843a: 00 
804843b: c7 44 24 08 03 00 00 mov DWORD PTR [esp+0x8],0x3 
8048442: 00 
8048443: c7 44 24 04 02 00 00 mov DWORD PTR [esp+0x4],0x2 
804844a: 00 
804844b: c7 04 24 01 00 00 00 mov DWORD PTR [esp],0x1 
8048452: e8 b5 ff ff ff   call 804840c <function> 
8048457: c7 44 24 1c 01 00 00 mov DWORD PTR [esp+0x1c],0x1 
804845e: 00 
804845f: 8b 44 24 1c    mov eax,DWORD PTR [esp+0x1c] 
8048463: 89 44 24 04    mov DWORD PTR [esp+0x4],eax 
8048467: c7 04 24 18 85 04 08 mov DWORD PTR [esp],0x8048518 
804846e: e8 7d fe ff ff   call 80482f0 <[email protected]> 
8048473: c9      leave 
8048474: c3      ret  
8048475: 66 90     xchg ax,ax 
8048477: 66 90     xchg ax,ax 
8048479: 66 90     xchg ax,ax 
804847b: 66 90     xchg ax,ax 
804847d: 66 90     xchg ax,ax 
804847f: 90      nop 

Có hai vấn đề với sự hiểu biết của tôi về vấn đề này:

A) vấn đề đầu tiên của tôi đã tìm ra số lượng byte để tràn ret bên function . Lần nữa; Tôi đã làm điều này bằng cách sử dụng cú pháp intel để tháo và thấy rằng:

Để đặt ret ở đúng không gian trong bộ nhớ ret cần phải được đặt thành EIP khi hàm được gọi. Không gian địa chỉ tại số 8048412 di chuyển xuống ngăn xếp 0x9. Bởi vì đây là mã 32 bit; để truy cập vào ret, sau đó chúng tôi thêm thêm 0x4 byte cho kích thước từ. Để truy cập vào ret điều đó có nghĩa là ret được đặt thành 0x9 + 0x4 có 13 chữ số thập phân.

Điều này giải quyết vấn đề đầu tiên khi truy cập vào ret.

B) Vấn đề thứ hai đang bỏ qua vị trí bộ nhớ 0x8048457. Điều này được thực hiện bằng cách thêm 7 byte vào (*ret) làm cho chương trình bỏ qua và thực thi tại 0x804845e00 (NUL). Điều này chỉ là không hiệu quả; vì vậy tôi đã thêm byte bổ sung và thực thi 8 byte xuống ngăn xếp; do đó dẫn đến x = 0;

Tôi nhận thấy số byte chính xác là 8 (c7 44 24 1c 01 00 00 là 7 byte) và 00 là một byte. Điều này giải quyết vấn đề cuối cùng của tôi.

mã C sửa đổi của tôi:

void function(int a, int b, int c) { 
     char buffer1[5]; 
     int *ret; 

     ret = buffer1 + 13; //tried 11, 14, 20, 40, 38, 43 
     (*ret) += 8; // tried 5, 8, 12; 8 is correct value! 
} 

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

bạn nhận ra rằng điều này chỉ giải quyết được vấn đề trên máy của bạn, và không giải thích tại sao chuyển vị là 8 byte trong bài viết? đó là câu hỏi của bạn – iabdalkader

+0

bạn nên chấp nhận một câu trả lời nếu bạn nghĩ rằng nó trả lời câu hỏi của bạn :) tất nhiên nó thuộc vào bạn, tôi chỉ chỉ ra rằng. – iabdalkader

+0

nhưng câu trả lời của riêng bạn không trả lời câu hỏi, đó là lý do tại sao sự dịch chuyển là 8 byte trong bài viết, đó là một sự dịch chuyển sai, tôi tin, dù sao đi nữa, bất cứ điều gì giúp bạn hiểu rõ hơn. – iabdalkader

3

Đó không phải là cách tôi diễn giải bài viết. Theo cách tôi hiểu, anh ấy muốn sửa đổi địa chỉ trả lại để bài tập x = 1; bị bỏ qua, nghĩa là anh ta muốn function quay lại nơi printf sẽ được thực hiện.

Như bạn có thể thấy trong quá trình tháo gỡ, nhiệm vụ là 8 byte (c7 44 24 1c 01 00 00 00), do đó di chuyển địa chỉ trả về 8 byte về phía trước sẽ di chuyển qua hướng dẫn này. Đối với "Chúng tôi sử dụng một giá trị thử nghiệm đầu tiên" bình luận .. có lẽ ông chỉ có nghĩa là ông nhìn vào mã trong một disassembler để tìm ra chiều dài, hoặc rằng ông đã thử nghiệm với offsets khác nhau (?).

1

Chuyển vị trong bài viết sai, phải là 10 byte. Khi một hàm được gọi (hoặc một bước nhảy được thực hiện), địa chỉ trả về được thiết lập để bằng con trỏ hướng dẫn + kích thước hướng dẫn hiện tại:

ret = IP + Curr_Inst_size 

Vì vậy, khi các cuộc gọi đến trở về chức năng, con trỏ lệnh phải bằng 0x80004a8 (0x80004a3 + kích thước hướng dẫn cuộc gọi):

0x80004a3 <main+19>: call 0x8000470 <function> 
--> 0x80004a8 <main+24>: addl $0xc,%esp    
    0x80004ab <main+27>: movl $0x1,0xfffffffc(%ebp) 
    0x80004b2 <main+34>: movl 0xfffffffc(%ebp),%eax 

Tuy nhiên, bạn muốn thiết lập các con trỏ chỉ dẫn để 0x80004b2 thay vào đó, để bỏ qua sự phân công, bạn cũng có, chắc chắn, phải bỏ qua một hướng dẫn (addl $0xc,%esp) t o đạt được điều đó, hay nói cách khác, bạn cần phải thêm (0x80004b2-0x80004a8) byte, hoặc 10 byte, để con trỏ hướng dẫn để bỏ qua những hai hướng dẫn:

0x80004a3 <main+19>: call 0x8000470 <function> 
    0x80004a8 <main+24>: addl $0xc,%esp    
    0x80004ab <main+27>: movl $0x1,0xfffffffc(%ebp) 
--> 0x80004b2 <main+34>: movl 0xfffffffc(%ebp),%eax 

Kích thước hướng dẫn thực tế phụ thuộc vào toán hạng, loại máy vv Nhưng trong ví dụ này, addl dài 3 byte và movl dài 7 byte. Bạn có thể kiểm tra x86 Instruction Set Reference cho kích thước hướng dẫn chính xác, hoặc bạn có thể biên dịch và tháo rời mã này, bạn sẽ thấy rằng hai hướng dẫn dài 10 byte:

int main() 
{ 
    asm("addl $0xc,%esp\n\ 
     movl $0x1,0xfffffffc(%ebp)"); 

} 

gdb:

0x08048397 <+3>: 83 c4 0c    add $0xc,%esp 
0x0804839a <+6>: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%ebp) 

Ngoài ra còn có một cuộc thảo luận herehere về vấn đề tương tự chính xác này trong ví dụ 3.