彙編角度解釋溢位段錯誤

2021-07-14 18:55:33 字數 1688 閱讀 4426

在編寫**時,由於讀寫了系統保護的記憶體或者訪問了給定位址以外的記憶體位址,這時會發生段錯誤,直接性的結果就是**出錯退出,這也僅僅是系統唯一能讓我們直觀的可知這是發生段錯誤了,但是對**在系統中的運**況以及記憶體情況一無所獲,因為高階語言遮蔽了這些底層的實現。但是所有的語言編譯的最終可執行**都是1和0形式的機器**,機器**由組合語言編譯而成,所以彙編是低階語言即直接可以操作記憶體。下面來用彙編來解釋段錯誤:

c**int  test_fun1(char * ptr)

int  test_fun2()

**test_fun2的彙編形式

mov%esp,%ebp

subl$20,%esp

leal-8(%ebp),%ebx

mov%ebx,(%esp)

calltest_fun1

ret

棧結構圖:

因為函式test_fun1中向ptr指向的記憶體寫了10個位元組的資料,而這塊記憶體大小只有5個位元組,所以它會把%ebp的備份覆蓋以及test_fun2的函式的返回位址,所以當它返回時會出錯的。

段錯誤不緊影響**的執行及維護,而且往往會變成黑客入侵的入口,黑客一般分三步來攻擊(借助段錯誤攻擊):

1.定位棧

2.放置可執行**

3.進行溢位操作,用上面可執行**位址來覆蓋程式中的某個位址,以達到程式執行到覆蓋的地點時,執行黑客**

比如上面那段測試**,黑客就會找到該函式的棧,然後對ptr指向的記憶體寫入足夠覆蓋返回位址的資料,一般覆蓋返回位址的資料是指向另一端黑客的**位址,當函式返回時,因為已經覆蓋,所以直接跳轉到黑客的**,這時你的機器就被黑客控制了。

因為黑客是依靠上述三步來進行攻擊,那麼現在的作業系統也從這三方面進行了安全提公升:

1.隨機位址

使用者**編譯後的棧位址是不定的

2.可執行**區域進行限制

現在的棧可讀可寫不能執行

3.系統在**中放置資料檢測是否發生溢位

如test_fun2的新增了檢測資料的彙編形式

push    %ebp

movl%esp,%ebp

subl$20,%esp

movl%gs:20,-4(%esp)

leal-12(%ebp),%ebx

mov%ebx,(%esp)

calltest_fun1

movl-8(%ebp),%eax

xorl%gs:20,%eax

je      .l1

call    __stack_chk_fail

.l1ret

棧如圖:

在存放buf位址的後面加存放了%gs:20,當呼叫完函式test_fun1時,執行xorl%gs:20,%eax,檢測存放的值有無改變,如果已經改變了則異常退出,否則正常執行返回。

所以在現代系統中,只要發生了溢位系統都會檢測到並異常退出程式。

雖然現在的系統都對段錯誤新增了多種手段來檢測段錯誤,預防黑客借助段錯誤攻擊,但是乙個良好的程式設計習慣,條理清晰的邏輯結構是最好的預防段錯誤的方法,程式設計時不要邊想邊寫,而是在編碼之前把整個需要實現的功能,以功能實現過程的邏輯結構畫出來,然後根據這個結構圖再程式設計。

段錯誤與棧溢位

編譯後產生的可執行檔案裡儲存著什麼內容 和作業系統相關 在可執行檔案中,正文段 text segment 儲存指令,資料段 data segment 儲存已初始化的全域性變數,bss bss segment 儲存未賦值的全域性變數所需的空間。呼叫棧並不儲存在可執行檔案中,而是在執行時建立,呼叫棧所在...

隨筆 段錯誤, 數字大小溢位

這兩天被段錯誤,數字溢位弄的很狼狽。總結 對gdb 非常 不熟悉,我一定要做到隨心所欲 記得3個月前看 深入理解計算機系統 第二,三章的時候,那叫乙個痛苦,我也知道,這兩章也是本書的精華之二吧,當時不理解,在我們的程式中,就是隨便定義乙個int 就可以完事了,沒有必要弄的這麼複雜,什麼環,什麼範圍,...

反彙編定義段錯誤

段錯誤是程式設計師最討厭的問題之一,其發生往往很突然,且破壞巨大。典型的段錯誤是由於操作記憶體不當引起的 如使用野指標或訪問受保護的位址等 發生段錯誤時,核心以乙個訊號sigse 強行終止程序,留下的出錯資訊極少,從而導致難以定位。但利用gdb和反彙編工具,可以較準確地定位段錯誤產生的原因。但想用這...