以nssctf裡的where_is_my_shell為例
題目提供了一個system函式,和一個buf陣列。陣列的棧空間如圖所示,這裡不討論怎麼解題,只說明payload裡的ret的作用。
假設沒有ret,棧溢位到ret的時候內容如下:
第一個八位元組:
(圖示位置)儲存 pop rdi;ret;的地址
它下面的八個位元組儲存要pop的引數。再下面八個位元組儲存system函式的地址。
這個時候我們可以知道一共存了三個八位元組,第一個八位元組的地址以8為起始,第二個以10為起始,第三個自然就是18為起始。問題就出在這裡,
呼叫system函式的時候,它裡面有一個函式要求system的rsp是16位元組對齊的。即rsp指向system函式並執行時,system在棧中的地址必須是以0結尾的。
而此時是以8為結尾的。所以會產生錯誤。
此時在原本函式ret的位置再加一個ret就可以解決問題。原理如下:
根據彙編知識可知ret指令相當於把rsp所指向的棧中儲存的地址賦給rip執行,然後使rsp+8(即使rsp指向棧中下一個位置).所以在所起作用的三個八位元組前面加上一個ret(佔八個位元組)會使得這三個八位元組的起始位置都往後順延八個位元組。所以此時system函式的起始地址就是以0結尾,滿足16位元組對齊要求。而由於ret的特殊性,在所執行操作前加上一個ret不會影響執行。
加一個ret後的操作如下:
原本函式的ret將我找到的ret地址賦給rip然後使rsp指向pop rdi;ret;的地址。然後rip執行ret指令,即把pop rdi;ret;的地址賦給rip然後執行後續操作。
所以加上ret後不會影響payload的執行,只會使payload裡其它操作的地址往後順延八個位元組。