C 語言緩衝區溢位的實戰
阿新 • • 發佈:2019-03-31
該內容原始碼參考了 <深入理解計算機系統>[3.10.3]
學習該章節之前,一直有個疑問,Segmentation fault 這樣的錯誤會具體引發的原因是啥, 可不可以從彙編程式碼的層面進行一個學習和了解. 所有就有了這篇文章, 純屬個人學習研究.
完整的測試原始碼
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
*/
char* gets(char* s)
{
int c;
char *dest = s;
// read c char write to dest memory;
while((c = getchar()) != '\n' && c != EOF)
{
*dest++= c;
}
if(c == EOF && dest == s)
{
return NULL;
}
*dest++ ='\0';
return s;
}
void echo(){
char buf[8];
gets(buf);
puts(buf);
}
int main()
{
echo();
return 0;
}
編譯過程,
shell>gcc -g demo.c -o demo
程式編譯成功後,隨便輸入幾個字元, 可以正常的回顯, 但是超過某個長度就會出現文章開始的問題, 那麼新的問題來了,
這個長度是不是就是程式碼中定義的buf的長度呢, 會不會有其他問題發生,
驗證思路:
1 通過彙編程式碼, 檢視暫存器地址中的內容, 直接明瞭的去觀察, 那麼就存在一個對比的過程,
第一遍的時候是正常的輸入, 不會發生錯誤,
第二遍會輸入較長的內容, 對比暫存器中的值.
正常輸入時,
在沒有輸入任何字元的時候, 相關的暫存器的值,
這個是在程式呼叫getchar() 函式前暫存器的值.
(gdb) i r ebp
ebp 0xbfffea68 0xbfffea68
(gdb) x/16cb 0xbfffea68
0xbfffea68: 120 'x' -22 '\352' -1 '\377' -65 '\277' 100 'd' -124 '\204' 4 '\004'
8 '\b'
0xbfffea70: 0 '\000' -106 '\226' 117 'u' 0 '\000' -112 '\220' -22 '\352' -1 '\377
' -65 '\277'
(gdb) i r esp
esp 0xbfffea50 0xbfffea50
(gdb) x/16cb 0xbfffea50
0xbfffea50: -12 '\364' -1 '\377' -118 '\212' 0 '\000' 4 '\004' -30 '\342'
-118 '\212' 0 '\000'
0xbfffea58: -120 '\210' -22 '\352' -1 '\377' -65 '\277' -87 '\251' -124 '\204'
4 '\004' 8 '\b'
(gdb) i r eax
eax 0xbfffea60 0xbfffea60
(gdb) x/16cb 0xbfffea60
0xbfffea60: 37 '%' -98 '\236' 121 'y' 0 '\000' 28 '\034' -21 '\353' -1 '\377'
-65 '\277'
0xbfffea68: 120 'x' -22 '\352' -1 '\377' -65 '\277' 100 'd' -124 '\204' 4 '\004'
8 '\b'
開始呼叫getchar() 函式
此時有個隱藏的資訊是, gets() 函式中, 引數s的地址是 0xbfffea60, 這個需要知道, 就是這個引數出現了問題,
gdb> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
在輸入完成後,
再次檢視暫存器的內容,
(gdb) x/16cb 0xbfffea68
0xbfffea68: 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a'
0xbfffea70: 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a'
(gdb) x/32cb 0xbfffea50
0xbfffea50: 96 '`' -22 '\352' -1 '\377' -65 '\277' 4 '\004' -30 '\342' -118 '\2
12' 0 '\000'
0xbfffea58: -120 '\210' -22 '\352' -1 '\377' -65 '\277' -87 '\251' -124 '\204'
4 '\004' 8 '\b'
0xbfffea60: 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a'
0xbfffea68: 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a'
(gdb) x/16cb 0xbfffea60
0xbfffea60: 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a'
0xbfffea68: 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 97 'a'
對比發現 0xbfffea68 地址中的內容被改寫了, 這個地址是程式被呼叫時的入棧地址, 在gets()函式內部把值改寫了,
導致程式返回的時候,出現了問題,
如果使用者輸入了緩衝區大小內的內容後, 則器暫存器中的值為
(gdb) x/16cb 0xbfffea60
0xbfffea60: 97 'a' 97 'a' 97 'a' 97 'a' 97 'a' 0 '\000' -1 '\377' -65 '\277'
0xbfffea68: 120 'x' -22 '\352' -1 '\377' -65 '\277' 100 'd' -124 '\204' 4 '\004'
8 '\b'
可以發現 0xbfffea68地址中的值和原來的值是一致的, 此時程式退出則是正常的,
具體可以使用的空間的大小的問題, 什麼時候,會觸發返回地址被改寫.