函式棧幀(用彙編來剖析)

2022-07-11 07:51:14 字數 3550 閱讀 2900

好久沒寫部落格了,學校開始實習,找了乙個極破的地方,站公交將近兩個小時,一天來回就要死了,說是實習,就是變著樣的培訓,一點實習的意思都沒有,辣雞。

因為位址空間內的棧是從高位址向低位址生長的,也就是說壓棧順序靠後的反而位址比較低,棧底的位址高於棧頂的位址,下面貼上一段測試**

1 #include2

3 #include4

5void

bug()610

int func(int x, int

y)11

1920

2122

intmain()

23

這段**的執行結果,並沒有執行main函式的第二個printf,而是跑到了bug函式中執行,這是因為我修改了函式棧幀中的返回位址部分

本來是打算通過linux系統來看的,但是centos7的棧幀實現似乎有些不同,同樣的**在centos7上面跑不通。

下面是反彙編

1

intmain()

2

因為main函式本身真的是個函式!所以在執行我們編寫的程式之前作業系統需要儲存當前它執行的狀態,就跟函式呼叫很類似100a118e0 push ebp    這句話就是把作業系統的狀態壓棧

200a118e1 mov ebp,esp    然後把棧底指標挪到新的位置

3 00a118e3 sub esp,0d8h   擴充套件新的棧幀,你總不能讓新的棧底和棧頂挨在一起吧? 

過程圖我會在講到func函式的時候給出來,更容易理解,之後的push之類的就是為了儲存現場和執行前準備

1     printf("

i am main\n");

2 00a118fe push offset string

"i am main\n

"(0a16cf0h)

300a11903 call _printf (0a1132ah)

4 00a11908 add esp,4

這部分就是呼叫printf的系統呼叫,因為庫函式更多是對作業系統呼叫的再一次呼叫(封裝?的說法也可以),因為我不是很懂這部分,也就不詳細解釋其中_printf的系統呼叫究竟怎麼工作了

int a = 0xaaaa

;00a1190b mov dword ptr [a],0aaaah

int b = 0xbbbb

;00a11912 mov dword ptr [b],0bbbbh

賦值階段,這裡給了雙字,所以是dword 通過指標賦值~,ptr就是指標,mov dst src就是把後面的給前面的,就是dst=src這樣的

1

func(a, b);

200a11919 mov eax,dword ptr [b]

300a1191c push eax 聯合上一句的賦值語句構成引數壓棧 y=b

400a1191d mov ecx,dword ptr [a]

500a11920 push ecx 聯合上一句的賦值語句構成引數壓棧 x=a

600a11921 call func (0a11366h) call函式呼叫,把fun函式的位址call一下

7 00a11926 add esp,8 push了這麼多不得把棧頂指標挪一挪?

重頭戲來了,這就是這次要講述的主要部分,函式呼叫時候的棧幀!令人驚訝的是傳的實參是放在main函式棧幀中的。我們來結合func的彙編看一下

別著急!還沒結束!彙編解釋來了!

1

int *p = &x;

20009178e lea eax,[x] 這就是取偏移位址,取得x對於當前ebp的偏移位址

300091791

mov dword ptr [p],eax 簡單賦值

4 p--;

500091794

mov eax,dword ptr [p] 看他把暫存器來回賦值的,其實就是將把位址減個4

600091797 sub eax,4

70009179a mov dword ptr [p],eax

8 *p = (int

)bug;

90009179d mov eax,dword ptr [p] 把函式bug的位址傳過來賦值

10000917a0 mov dword ptr [eax],offset bug (09127bh) offset也是取偏移的作用還是和lea有些不同的

11 printf("

x:%d,y:%d\n

", x, y);

12000917a6 mov eax,dword ptr [y] 這就不說了是個系統呼叫,因為我也不是很懂

13000917a9 push eax

14000917aa mov ecx,dword ptr [x]

15000917ad push ecx

16 000917ae push offset string

"x:%d,y:%d\n

"(096b3ch)

17000917b3 call _printf (09132ah)

18000917b8 add esp,0ch

19int c = 0xcccc;20

000917bb mov dword ptr [c],0cccch 建立的區域性變數位置在ebp下面~看圖!

21return

c;22 000917c2 mov eax,dword ptr [c]

沒看到形參對不對?就兩個實參,寫完了不就改了麼?不對哦~

x = 10

;000a178e mov dword ptr [x],0ah

y = 10

;000a1795 mov dword ptr [y],0ah

我把**改成這樣看彙編,這裡並沒有更改之前儲存的暫存器裡的東西,是取得了新的部分哦

dword ptr [x]這個已經不是之前的eax或者是ebx了~

深度剖析函式的呼叫過程(棧幀)

當我們在學習c語言的時候,寫 一定會用到函式 main函式 但函式在使用過程中是如何呼叫的,當我們從彙編的角度來剖析函式的呼叫,會讓我們對函式的認識剛深一層。注 使用的工具是vs2017 下面我將通過一段 來剖析函式是如何呼叫的 include int add int x,int y int mai...

C 反彙編 棧幀(函式呼叫過程)

該系列文章是依據本人平時對 反彙編的學習,歸納總結,所做的學習筆記。如有錯誤或待改善之處,請留下您寶貴的意見或建議。棧幀也叫過程活動記錄,是編譯器用來實現過程 函式呼叫的一種資料結構。棧幀是在程式的執行時棧中分配記憶體塊,專門用於特定的函式呼叫。當乙個函式沒有執行時,它可能並不需要記憶體 但是當乙個...

棧幀 組合語言詳解

原來我以為在c語言中指標已經是非常麻煩了,沒想到棧幀給我甜蜜一擊,但最後一路學習下來也不是多麼麻煩的事。首先我們得明確為什麼有函式,其作用是 在面向過程語言的重要組成成分,它將具有相同功能的語句組合到一塊,便於我們使用,提高程式可讀性,減少 量。以main函式為例,在使用過程中首先呼叫 tmainc...