Linux防止stack緩沖區(qū)溢出的有效方法
檢測(cè)和防治stack緩沖區(qū)溢出的方法可謂是汗牛充棟,如果講起來(lái),那便是一個(gè)系列,我也不知道該從何說(shuō)起。
然而,總覺(jué)得有點(diǎn)紙上談兵的意思。為什么我會(huì)這么說(shuō)?
因?yàn)檫@玩意兒大家都懂,想破解還是很容易的,只需要破解FS:0x28即可,然后就一瀉千里了,我把guard保留,實(shí)際上里面已經(jīng)糜爛…
若攻若防,都要出其不意,當(dāng)然了,這里有一個(gè)比較直接的方案:
-
每一次函數(shù)調(diào)用均使用 __builtin_return_address(0) 作為最后一個(gè)參數(shù),函數(shù)的最后檢測(cè)8(%rbp)的值和它是否相等。
這種方法可行,姑且不談__builtin_return_address需要絕對(duì)地址轉(zhuǎn)換,單憑可操作性,這種方法絕不優(yōu)雅!
有沒(méi)有什么辦法,不需要程序做任何改變,就能做到檢測(cè)stack緩沖區(qū)溢出呢?
當(dāng)然有!在編譯過(guò)程中添加stub即可!
只需要為每一個(gè)函數(shù)調(diào)用的開(kāi)頭和結(jié)尾加兩段修飾即可:
-
開(kāi)頭在代碼執(zhí)行前的第一時(shí)間保存rbp下面的return address到fs寄存器0x28偏移處。
-
函數(shù)返回前最后一刻檢查rbp下面的return address和fs寄存器0x28偏移處值是否相等。
-
…[其實(shí)fs寄存器還有很多偏移沒(méi)有用到,為啥非要瞄準(zhǔn)0x28,因?yàn)槲蚁胩娴魋tack protector]
我無(wú)心修改Linux的gcc編譯器,我也無(wú)力修改,所以我這里只能演示,下面是一個(gè)代碼:
我在func函數(shù)中主動(dòng)制造了一個(gè)控制權(quán)轉(zhuǎn)移:
如果不加那兩段stub,很顯然,控制流程將轉(zhuǎn)入到別處:
然而,這兩段stub成功保護(hù)了stack按照原有邏輯繼續(xù)下去:
當(dāng)然了,在發(fā)生了這種情況的時(shí)候,至少要記錄一條日志:
執(zhí)行一下試試看:
你可能記得__stack_chk_failed函數(shù),我覺(jué)得這個(gè)機(jī)制不妥,因?yàn)槲以?jīng)成功繞過(guò)了它,所以就我個(gè)人而言,我忘掉了它。
記住兩件套:
至于當(dāng)前棧幀的return address保存在哪里,我覺(jué)得要區(qū)分用戶(hù)態(tài)和內(nèi)核態(tài)。若是用戶(hù)態(tài),那就放在FS寄存器索引的固定偏移處,若是內(nèi)核態(tài),per cpu變量再好不過(guò)了,畢竟一個(gè)CPU同時(shí)只能處在一個(gè)棧幀。
周日的上海陰風(fēng)怒號(hào),這正是我喜歡的天氣,從此以后,所有的一切和經(jīng)理再無(wú)關(guān)系,然而還是有一點(diǎn)點(diǎn),因?yàn)榻?jīng)理灑不了水。謝…
————————————————
版權(quán)聲明:本文為CSDN博主「dog250」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:
https://blog.csdn.net/dog250/java/article/details/105611497