首先來看看C語言溢出小程序
這個程序看著好像是沒有任何問題,運行是這樣的:
我們主要關注這個check函數,首先定義了一個int類型的數組且其中個數為8個,下一行將fun函數地址存入arr[9]中,其實這里我們可以看到定義數組的時候個數也就是8,實際到達的下標是7,所以我們最多能取數組的值為arr[7],連8都不到,這里我們獲取fun函數地址的時候卻存到了下標為9的地址,跳了一個下標。首先來了解下數組的存儲方式
這是我簡單畫的數組存儲的堆棧圖,數組是使用連續的內存空間來存儲的,說白了和局部變量的存儲差異不大,我們現在開始分析代碼:
現在我們記住ebp和esp的值
現在我們來把這個堆棧圖畫一下
這里按F11進入函數體中,call進函數會將它下一行地址壓入棧中,然后調到函數體,這時再來看看堆棧的變化:
接著往下走,我們看看函數體中的代碼:
進入函數后將ebp壓入棧中,然后將esp中的值移動到ebp中,之后esp-60h(60h/4h=18h=24)提升棧空間,再來看看此時的堆棧:
接下來將ebx,esi,edi依次推入棧中,下面的代碼到rep指令是將緩沖區填充為CCCCCCCCCh,再來看看堆棧的變化:
接著往下走
這里是將數組存到緩沖區中,從低地址向高地址存儲,20h/4h=8h=8從esp的位置向上數八格就是存儲1的位置,依次存儲下來,再來看看棧中的變化:
這里是取fun的地址出來并轉換為int類型,然后存入數組下標為9的地方,我們看看ebp+4這個地址執行前后的變化
執行前
執行后
經過這個對比之后,ebp+4剛好是這個存儲返回地址的地方,我們繼續往下走
異或eax之后,依次取出edi,esi,ebx,然后將ebp的值移動到esp中,隨后取出ebp,再來看看堆棧變化:
上面的操作是使堆棧平衡,接著來看
接著執行了一個ret,ret的操作相當于pop eip,F11一下,看看eip
就這樣進入了fun函數
本次分析就是分析緩沖區都溢出了為何還能執行fun函數,到這里我們可以知道溢出之后覆蓋掉了程序的返回地址,所以導致程序進入了fun函數中。溢出并不可怕,可怕的是不會調試啊!