以下知識全部取自張元,如果需要,最下面reference有給影片連結
當我們在寫C/C++程式時,每當一個函式被呼叫,作業系統會分配一個暫時的記憶體區塊來儲存該函式的區域變數、回傳位址等等,這個區塊就稱為 stack frame,那由於我們之後也要探討buffer overflow的漏洞利用,所以也需要先了解stack frame的內容才可以清楚理解buf的細節
stack frame重要的兩個步驟
一個function的stack frame差不多就像下面那樣子,以下是我參考張元做的stack frame表:
那我們現在來看function prologue跟function epilogue的流程
rip現在是停在call function的部分,被指到代表即將執行這一行,但是還沒執行這一行
func:
    push rbp
    mov rbp, rsp
    sub rsp, 0x70
	...
    mov eax, 0x1
    leave
    ret
    
main:
    push rbp
    mov rbp, rsp
    mov rdi, 1234
    mov rsi, 666
    call func          <== rip
    mov eax, 0 // address = 0x40071A
    leave
    ret

call function這個instruction可以看做是
push next-rip
jmp func
他會把next-rip push到stack
這樣就可以jump到func
func:
    push rbp          <== rip
    mov rbp, rsp
    sub rsp, 0x70
	...
    mov eax, 0x1
    leave
    ret
    
main:
    push rbp
    mov rbp, rsp
    mov rdi, 1234
    mov rsi, 666
    call func          
    mov eax, 0 // address = 0x40071A
    leave
    ret
其實可以發現,compiler在前面三行都是,這個其實就是function prologue的部分
push rbp      ; 保存舊的 base pointer
mov rbp, rsp  ; 設定新的 base pointer
sub rsp, N    ; 預留區域變數空間(N 是需要的大小,指區域變數)
接下來就會執行compiler幫我們加的function prologue的instruction
func:
    push rbp
    mov rbp, rsp          <== rip
    sub rsp, 0x70
	...
    mov eax, 0x1
    leave
    ret
    
main:
    push rbp
    mov rbp, rsp
    mov rdi, 1234
    mov rsi, 666
    call func          
    mov eax, 0 // address = 0x40071A
    leave
    ret

然後就會執行mov rbp, rsp,這樣就會讓rbp指向跟rsp一樣的位址
再來就會執行sub rsp, 0x70
0x70這個值是compiler在compile的時候就已經決定好了
func:
    push rbp
    mov rbp, rsp
    sub rsp, 0x70          <== rip
	...
    mov eax, 0x1
    leave
    ret
    
main:
    push rbp
    mov rbp, rsp
    mov rdi, 1234
    mov rsi, 666
    call func          
    mov eax, 0 // address = 0x40071A
    leave
    ret
那就會挪出0x70的位置給local variable
那我們可以發現我們的rsp跟rbp都已經指向function的stack frame上了
這樣我們就完成我們的function prologue了 uwu
然後我們離開後執行mov eax, 0x1把return value放rax暫存器後
我們就會執行leave ret,那這也是function epilogue的環節
func:
    push rbp
    mov rbp, rsp
    sub rsp, 0x70
	...
    mov eax, 0x1
    leave          <== rip
    ret
    
main:
    push rbp
    mov rbp, rsp
    mov rdi, 1234
    mov rsi, 666
    call func          
    mov eax, 0 // address = 0x40071A
    leave
    ret
mov rsp, rbp
pop rbp
所以rsp也會指到rbp的地方
pop rbp,那pop rbp就是把rsp現在指的地方的值塞到rbp 
接下來我們執行ret
func:
    push rbp
    mov rbp, rsp
    sub rsp, 0x70
	...
    mov eax, 0x1
    leave
    ret          <== rip
    
main:
    push rbp
    mov rbp, rsp
    mov rdi, 1234
    mov rsi, 666
    call func          
    mov eax, 0 // address = 0x40071A
    leave
    ret
pop rip
那這時候我們function epilogue就結束了
 
func:
    push rbp
    mov rbp, rsp
    sub rsp, 0x70
	...
    mov eax, 0x1
    leave
    ret
    
main:
    push rbp
    mov rbp, rsp
    mov rdi, 1234
    mov rsi, 666
    call func          
    mov eax, 0 // address = 0x40071A          <== rip
    leave
    ret
以上就是stack frame的運作以及function prologue跟function epilogue的流程
那我們理解完這些知識後,明天就要接觸buffer overflow了w今天寫這個筆記快累死,明天應該可以輕鬆一點
明天見~~
https://www.youtube.com/watch?v=U8N6aE-Nq-Q&t=2303s