2012-06-20 15 views
4

我正在使用Ubuntu 12.04和64位機器。我正在閱讀一本關於緩衝區溢出的書,並且在玩一個例子時發現了一個奇怪的時刻。緩衝區溢出期間EIP值不正確

我有這個非常簡單的C代碼:

void getInput (void){ 
    char array[8];  
    gets (array); 
    printf("%s\n", array); 

} 
main() { 
    getInput();  
    return 0;  
} 

文件中overflow.c

我與32位標誌編譯它導致了書中所有例子假定32位的機器,我這樣做這樣

gcc -fno-stack-protector -g -m32 -o ./overflow ./overflow.c 

在代碼字符數組是隻有8個字節,但在看拆卸我發現,陣列開始從在堆棧上保存的EBP 16個字節遠,所以執行該行:

printf "aaaaaaaaaaaaaaaaaaaa\x10\x10\x10\x20" | ./overflow 

,並得到:

aaaaaaaaaaaaaaaaaaaa 
Segmentation fault (core dumped) 

然後我打開核心文件:

gdb ./overflow core 
#0 0x20101010 in ??() 
(gdb) info registers 
eax   0x19 25 
ecx   0xffffffff -1 
edx   0xf77118b8 -143583048 
ebx   0xf770fff4 -143589388 
esp   0xffef6370 0xffef6370 
ebp   0x61616161 0x61616161 
esi   0x0 0 
edi   0x0 0 
eip   0x20101010 0x20101010 

正如你看到的EIP其實有了新的價值,這是我想要的。但是,當我想要把一些有用的值這樣的0x08048410

printf "aaaaaaaaaaaaaaaaaaaa\x10\x84\x04\x08" | ./overflow 

程序崩潰像往常一樣,但比一些奇怪的事情發生了,當我試圖觀察EIP寄存器的值:

#0 0xf765be1f in ??() from /lib/i386-linux-gnu/libc.so.6 
(gdb) info registers 
eax   0x61616151 1633771857 
ecx   0xf77828c4 -143120188 
edx   0x1 1 
ebx   0xf7780ff4 -143126540 
esp   0xff92dffc 0xff92dffc 
ebp   0x61616161 0x61616161 
esi   0x0 0 
edi   0x0 0 
eip   0xf765be1f 0xf765be1f 

突然EIP開始看起來像這個0xf765be1f,它看起來不像0x08048410。事實上,我注意到從0開始的任何十六進制值就足以得到這個崩潰的EIP值。你知道爲什麼會發生這種情況嗎?是因爲我在64位機器上嗎?

UPD

好球員在要求更多的信息,意見,這裏是getInput功能的拆卸:

(gdb) disas getInput 
Dump of assembler code for function getInput: 
    0x08048404 <+0>: push %ebp 
    0x08048405 <+1>: mov %esp,%ebp 
    0x08048407 <+3>: sub $0x28,%esp 
    0x0804840a <+6>: lea -0x10(%ebp),%eax 
    0x0804840d <+9>: mov %eax,(%esp) 
    0x08048410 <+12>: call 0x8048310 <[email protected]> 
    0x08048415 <+17>: lea -0x10(%ebp),%eax 
    0x08048418 <+20>: mov %eax,(%esp) 
    0x0804841b <+23>: call 0x8048320 <[email protected]> 
    0x08048420 <+28>: leave 
    0x08048421 <+29>: ret 

回答

3

也許代碼在0x08048410被執行,並跳到0xf765be1f的區域。

這是什麼地址?我想這是一個函數(libC?),所以你可以檢查它的彙編代碼,看看它會做什麼。

另請注意,在成功運行中,您設法超出了EBP,而不是EIP。 EBP包含0x61616161,即aaaa,EIP包含0x20101010,即\n\n\n。看起來腐敗的EBP間接得到了EIP腐敗。
嘗試使溢出4個字節更長,然後它應該溢出返回地址。

+0

聽起來不太有說服力。無論如何,0xf765be1f是如何到達EIP的?有沒有RET?無論如何,這需要更詳細的調試。 – m0skit0

+0

@ m0skit0,一旦開始破壞堆棧並執行通配地址,事情變得非常不可預測。 '0x08048410'處的代碼可能不會簡單地跳轉到0xf765be1f,但它可能會按照您的建議返回,或者通過寄存器調用函數。 – ugoren

+0

那麼地址0x08048410就是getInput函數裏調用get函數的地址,我只是試圖再次調用這個函數,這是非常確鑿的證據,我重定向了程序的流程 –

1

這可能是由於這樣的事實:現代操作系統(Linux確實至少,我不知道Windows)和現代libc have mechanisms,它們不允許執行堆棧中的代碼。

+0

嗯,它不能解釋爲什麼第一個值\ x10 \ x10 \ x10 \ x20被正確寫入EIP寄存器,而\ x10 \ x84 \ x04 \ x08變成了一團糟。 –

+0

確實如此:在第一個例子中,你並沒有試圖跳到有效的地址,而是在第二個例子中。 – m0skit0

0

緩衝區溢出調用未定義的行爲,因此可能發生任何事情。理論化可能發生的事情是徒勞的。

+0

好吧,它並不能解釋爲什麼第一個值\ x10 \ x10 \ x10 \ x20被正確寫入EIP寄存器,而\ x10 \ x84 \ x04 \ x08變成亂碼的原因 –

+0

@RustamIssabekov [This](http: //www.catb.org/jargon/html/N/nasal-demons.html)可能解釋它爲什麼發生。 [Here](http://insecure.org/stf/smashstack.html),你可能會發現一些異國情調的堆棧碎片。 –