棧溢出原理筆記(一)


系統棧的工作原理

1.內存的不同用途
        簡單來說,緩沖區溢出就是在大緩沖區的數據復制到小緩沖區中,由於沒注意小緩沖區的邊界,”撐爆“了小緩沖區。從而沖掉了小緩沖區相鄰內存區域的數據。
根據不同的操作系統,一個進程可能被分配到不同內存區域中去執行,但是不管什么樣的系統,什么計算機架構,進程使用的內存都可以按照功能分為4部分:
        代碼區:可執行指令
        數據區:用於存儲全局變量
        堆區:  進程可以在堆區動態的請求一定大小的內存,並在用完之后歸還給堆區。動態分配和回收是堆區的特點
        棧區:  用於動態的存儲函數之間的調用關系,以保證被調用函數返回時恢復到母函數中繼續執行
        這只是簡單的內存划分,如果想了解關於內存更詳細的論述,請參考《深入理解計算機系統》,windows下,PE文件代碼段中包含的二進制機器代碼會被裝入內存的代碼區,處理器將到這里一條一條的取出指令和操作數,送入算術邏輯單元運算,如果代碼請求開辟動態內存,則會在內存的堆區分配一塊區域返回給代碼區的代碼使用,當函數調用發生時,函數的調用關系等信息會動態的保存在棧區。
程序中所使用的緩沖區可以是在堆區、棧區、數據區,不同地方的緩沖區利用方法不同。
2.棧與系統棧
        棧是一種數據結構,是一種先進后出的數據表,用於標識棧的屬性兩個:棧頂、棧底 。內存中的棧區指的就是系統棧,由系統自動維護。
3.函數調用時發生了什么
        請看如下C代碼:
 

       int B(int b1,int b2){
                int var_b1=b1+b2;
                int var_b2=b1-b2;
                return var_b1*var_b2;
        }
        int A(int a1,int a2){
                int var_a1;
                var_a=B(a1,a2)+a1;
                return a1;               
        }
        int main(int argc,char **argv,char **envp){
                int var_main;
                var_main=A(4,3);
                return var_main;
        }

        根據操作系統的不同、編譯器和編譯選項的不同,同一文件不同函數的代碼在內存代碼區中的分布可能相鄰,也可能不相鄰,可能有先后順序,也可能沒有,但他們都是在代碼所映射的節里
函數調用時,伴隨的系統棧中的操作如下:
在main函數調用A的時候,首先在自己的棧幀中壓入函數返回地址,然后位A創建新棧幀並壓入系統棧 ,
在函數A調用B的時候,同樣先在自己的棧幀中壓入返回地址,然后為B創建新棧幀並壓入系統棧
B返回時,B的棧幀被彈出系統棧,A棧幀的返回地址被露在棧頂,處理器跳到返回地址處執行
在A返回時,A的棧幀被彈出系統棧,main函數棧幀中的返回地址被露在棧頂。處理器跳到返回地址執行
4.寄存器與函數棧幀
        每一個函數獨占自己的棧幀空間,當前正在運行的函數總是在棧頂,win32系統提供兩個寄存器用於標識位於系統棧頂端的棧幀
         ESP:棧指針寄存器,存放一個指針,該指針永遠指向系統棧最上面的棧幀的棧頂
         EBP:基址指針寄存器,該指針永遠指向系統棧最上面的棧幀的底部
         函數棧幀:ESP和EBP之間內存空間為當前棧幀
         在函數棧幀中一般包含以下幾種信息:、
         局部變量:為函數舉報變量開辟的內存空間
         棧幀狀態值:保存前棧幀的頂部和底部(實際上只保存前棧幀的底部,前棧幀的頂部可以通過堆棧平衡得到)
         函數返回地址:保存當前函數調用前的“斷點”信息,也就是函數調用前的指令位置
         函數棧幀的大小不固定,一般和局部變量的多少有關
5.函數調用約定與相關指令
        調用約定描述了函數傳遞參數的方式和棧協同工作的技術細節,下面列出幾種調用方式:
                                C                Syscall                Stdcall                BASIC                FORTRAN                PASCAL
參數入棧順序 右→左         右→左                右→左                左→右                 左→右                左→右
誰恢復棧平衡 母函數                子函數                子函數                子函數                子函數                子函數
        對於Visual C++,支持3種函數調用約定:

        調用約定聲明                參數入棧順序                誰恢復棧平衡
        __cdecl                                右→左                                母函數
        __fastcall                        右→左                                子函數
        __stdcall                        右→左                                子函數

        除了入棧方向和恢復平衡不同之外,參數傳遞有時也會有所不同。例如,每一個C++類成員函數都有一個this指針,在windows下,這個指針保存在ECX中
,但如果用GCC編譯,這個指針會作為最后一個參數入棧

        函數調用大致包括以下幾個步驟:
         參數入棧
         返回地址入棧
         代碼區跳轉
         棧幀調整:具體包括
         保存當前棧幀狀態值(push ebp)
         將當前棧幀切換到新棧幀(mov ebp,esp)
         給新棧幀分配空間(把ESP減去所需空間大小,抬高棧頂)
         
        函數返回大致包括以下幾個步驟:
         保存返回值(通常保存在EAX中)
         彈出當前棧幀,恢復上一個棧幀:具體包括
         在堆棧平衡的基礎上給ESP加上棧幀的大小,降低棧頂,回收當前棧幀空間
         將當前棧幀底部保存的前棧幀EBP值彈入EBP,恢復出上一個棧幀
         將函數返回地址彈給EIP

    跳轉


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM