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





