簡體   English   中英

Protostar Stack0中的填充和對齊

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM