[英]Padding and alignment in Protostar Stack0
今天早上,我在protostar上進行了stack0練習。 該示例是使用gets的簡單堆棧溢出。 我在啟用堆棧保護器和ASLR的x86-64上使用gcc編譯了代碼。
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
modified = 0;
gets(buffer);
if(modified != 0) {
printf("you have changed the 'modified' variable\n");
} else {
printf("Try again?\n");
}
}
因為一個int是4個字節,並且在緩沖區(64個字節的char)之前被壓入堆棧,所以我以為要更改Modifyed的值,我需要將緩沖區溢出1個字節。
但是,這沒有用。 因此,我接下來想到編譯器在修改的緩沖區和緩沖區之間插入了4個字節的填充,使得它們都以字邊界(x86-64的8個字節)開始。 但是,這也不起作用。
最后,我在GDB中運行了可執行文件,發現實際上,GCC正在在修改和緩沖區之間插入12個字節的對齊方式:因此,我不得不向緩沖區中寫入77個字節,以便在修改后溢出(第77個字節是修改后的第一個字節) )。
(gdb) p &modified
$3 = (volatile int *) 0x7fffffffdadc
(gdb) p &buffer[63]
$12 = 0x7fffffffdacf ""
因此,0x7fffffffdadc-0x7fffffffdacf是13個字節。
0000000000400504 <main>:
400504: 55 push %rbp
400505: 48 89 e5 mov %rsp,%rbp
400508: 48 83 ec 60 sub $0x60,%rsp
40050c: 89 7d ac mov %edi,-0x54(%rbp)
40050f: 48 89 75 a0 mov %rsi,-0x60(%rbp)
400513: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
40051a: 48 8d 45 b0 lea -0x50(%rbp),%rax
40051e: 48 89 c7 mov %rax,%rdi
400521: e8 ea fe ff ff callq 400410 <gets@plt>
現在,看一下上面的目標代碼,我們可以看到GCC在堆棧sub $0x60, %rsp
為緩沖區和修改的緩沖區分配了96個字節。
然后,它將目標索引和源索引從%rbp移到地址-0x54和-0x60中。 這樣做的目的是什么?這些寄存器的作用是什么?
接下來,我可以看到movl $0x0,-0x4(%rbp)
設置為0,其中它是來自基本指針的4個字節。 因此,緩沖區的末尾和修改的第一個字節之間有12個字節。
因此,我的問題是:為什么GCC會在修改和緩沖區之間插入12個字節的對齊方式,以使修改后的16個字節對齊,而不是僅8個字節對齊,這會使它與x86-64上的字邊界對齊?
堆棧對齊不僅受特定類型對齊的約束,還受平台ABI的約束。 在您的情況下,堆棧對齊為16個字節,這在x86_64平台上很常見。
您可以搜索x86_16 ABI問題,例如: x86_64對齊堆棧並在不保存寄存器的情況下進行恢復
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.