gpt4 book ai didi

c - 缓冲区溢出在 x86 上需要 16 个字节,但在 x64 上需要 29 个字节

转载 作者:太空宇宙 更新时间:2023-11-04 02:32:24 26 4
gpt4 key购买 nike

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
char buff[15];
int auth = 0;

printf("\nEnter password: ");
gets(buff);

if (strcmp(buff, "password") != 0) {
printf("\nAccess denied\n");
} else {
auth = 1;
}

if (auth) {
printf("\nAccess granted\n");
}

return 0;
}

这段代码需要16个字节(用户输入的字符)才能在x86上溢出auth并打印“Access granted”。在 x64 上,需要 29 个字节才能执行相同的操作。为什么是这样?似乎我的变量之间有一些填充,或者它们之间有其他东西的地址。我不相信这是阴影空间的影响(这是否也适用于 *nix?),因为只保留前 32 个字节 https://en.wikipedia.org/wiki/X86_calling_conventions#Microsoft_x64_calling_convention

请注意,我没有通过任何优化来编译它以避免寄存器内部的东西。

我在 OS X 上使用 GCC 6.2.0。这是 x86 版本的程序集输出:

    .cstring
LC0:
.ascii "\12Enter password: \0"
LC1:
.ascii "password\0"
LC2:
.ascii "\12Access denied\0"
LC3:
.ascii "\12Access granted\0"
.text
.globl _main
_main:
LFB1:
pushl %ebp
LCFI0:
movl %esp, %ebp
LCFI1:
pushl %ebx
subl $36, %esp
LCFI2:
call ___x86.get_pc_thunk.bx
L1$pb:
movl $0, -12(%ebp)
subl $12, %esp
leal LC0-L1$pb(%ebx), %eax
pushl %eax
call _printf
addl $16, %esp
subl $12, %esp
leal -27(%ebp), %eax
pushl %eax
call _gets
addl $16, %esp
subl $8, %esp
leal LC1-L1$pb(%ebx), %eax
pushl %eax
leal -27(%ebp), %eax
pushl %eax
call _strcmp
addl $16, %esp
testl %eax, %eax
je L2
subl $12, %esp
leal LC2-L1$pb(%ebx), %eax
pushl %eax
call _puts
addl $16, %esp
jmp L3
L2:
movl $1, -12(%ebp)
L3:
cmpl $0, -12(%ebp)
je L4
subl $12, %esp
leal LC3-L1$pb(%ebx), %eax
pushl %eax
call _puts
addl $16, %esp
L4:
movl $0, %eax
movl -4(%ebp), %ebx
leave
LCFI3:
ret
LFE1:
.section __TEXT,__textcoal_nt,coalesced,pure_instructions
.weak_definition ___x86.get_pc_thunk.bx
.private_extern ___x86.get_pc_thunk.bx
___x86.get_pc_thunk.bx:
LFB2:
movl (%esp), %ebx
ret
LFE2:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0
LSCIE1:
.long 0
.byte 0x1
.ascii "zR\0"
.byte 0x1
.byte 0x7c
.byte 0x8
.byte 0x1
.byte 0x10
.byte 0xc
.byte 0x5
.byte 0x4
.byte 0x88
.byte 0x1
.align 2
LECIE1:
LSFDE1:
.set L$set$1,LEFDE1-LASFDE1
.long L$set$1
LASFDE1:
.long LASFDE1-EH_frame1
.long LFB1-.
.set L$set$2,LFE1-LFB1
.long L$set$2
.byte 0
.byte 0x4
.set L$set$3,LCFI0-LFB1
.long L$set$3
.byte 0xe
.byte 0x8
.byte 0x84
.byte 0x2
.byte 0x4
.set L$set$4,LCFI1-LCFI0
.long L$set$4
.byte 0xd
.byte 0x4
.byte 0x4
.set L$set$5,LCFI2-LCFI1
.long L$set$5
.byte 0x83
.byte 0x3
.byte 0x4
.set L$set$6,LCFI3-LCFI2
.long L$set$6
.byte 0xc4
.byte 0xc3
.byte 0xc
.byte 0x5
.byte 0x4
.align 2
LEFDE1:
LSFDE3:
.set L$set$7,LEFDE3-LASFDE3
.long L$set$7
LASFDE3:
.long LASFDE3-EH_frame1
.long LFB2-.
.set L$set$8,LFE2-LFB2
.long L$set$8
.byte 0
.align 2
LEFDE3:
.subsections_via_symbols

对于 x64 版本:

    .cstring
LC0:
.ascii "\12Enter password: \0"
LC1:
.ascii "password\0"
LC2:
.ascii "\12Access denied\0"
LC3:
.ascii "\12Access granted\0"
.text
.globl _main
_main:
LFB1:
pushq %rbp
LCFI0:
movq %rsp, %rbp
LCFI1:
subq $48, %rsp
movl %edi, -36(%rbp)
movq %rsi, -48(%rbp)
movl $0, -4(%rbp)
leaq LC0(%rip), %rdi
movl $0, %eax
call _printf
leaq -32(%rbp), %rax
movq %rax, %rdi
call _gets
leaq -32(%rbp), %rax
leaq LC1(%rip), %rsi
movq %rax, %rdi
call _strcmp
testl %eax, %eax
je L2
leaq LC2(%rip), %rdi
call _puts
jmp L3
L2:
movl $1, -4(%rbp)
L3:
cmpl $0, -4(%rbp)
je L4
leaq LC3(%rip), %rdi
call _puts
L4:
movl $0, %eax
leave
LCFI2:
ret
LFE1:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0
LSCIE1:
.long 0
.byte 0x1
.ascii "zR\0"
.byte 0x1
.byte 0x78
.byte 0x10
.byte 0x1
.byte 0x10
.byte 0xc
.byte 0x7
.byte 0x8
.byte 0x90
.byte 0x1
.align 3
LECIE1:
LSFDE1:
.set L$set$1,LEFDE1-LASFDE1
.long L$set$1
LASFDE1:
.long LASFDE1-EH_frame1
.quad LFB1-.
.set L$set$2,LFE1-LFB1
.quad L$set$2
.byte 0
.byte 0x4
.set L$set$3,LCFI0-LFB1
.long L$set$3
.byte 0xe
.byte 0x10
.byte 0x86
.byte 0x2
.byte 0x4
.set L$set$4,LCFI1-LCFI0
.long L$set$4
.byte 0xd
.byte 0x6
.byte 0x4
.set L$set$5,LCFI2-LCFI1
.long L$set$5
.byte 0xc
.byte 0x7
.byte 0x8
.align 3
LEFDE1:
.subsections_via_symbols

最佳答案

我又在考虑这个问题,想起了我在聊天中发给你的编译器标志:

-mpreferred-stack-boundary=num

特别是以下段落:

Attempt to keep the stack boundary aligned to a 2 raised to num byte boundary. If -mpreferred-stack-boundary is not specified, the default is 4 (16 bytes or 128 bits).

Warning: When generating code for the x86-64 architecture with SSE extensions disabled, -mpreferred-stack-boundary=3 can be used to keep the stack boundary aligned to 8 byte boundary. Since x86-64 ABI require 16 byte stack alignment, this is ABI incompatible and intended to be used in controlled environment where stack space is important limitation.

因此,15 字节的数组将需要 16 字节的堆栈槽以将其保存在堆栈边界内。

int auth,假设一个 4 字节的 int,也需要一个 16 字节的堆栈槽来遵守 gcc 的堆栈边界标志.用gdb调试程序,我注意到int auth地址是BSP-0x04BSP-0x04BSP-0x10 正在填充,因此适合堆栈槽。因此,要溢出缓冲区直到到达 int auth,您需要 15 个字节(缓冲区大小)+ 1 个字节(缓冲区填充)+ 12 个字节(int auth 填充)+ 1 个字节到达 int

最后,我跟你提过,我在调试时发现了数组和 int 之间的地址。这可能是内存中残留的一些垃圾:由于程序不关心 int 之前的额外 12 个字节,它可能不会清理它,它可能被用来存储一些内存指针。

下面是 x64 代码程序堆栈的表示。

主堆栈

-------------------------------------------- ------
保存的 RBP
---------------------------------------------- ---- 新的 RBP = 0x7FFFFFFFFDD10
授权
---------------------------------------------- ---- RBP - 0x04 = 0x7FFFFFFFDD0C
auth 12 字节填充
---------------------------------------------- ---- RBP - 0x10 = 0x7FFFFFFFFDD00
buff 1 字节填充
---------------------------------------------- ---- RBP - 0x11 = 0x7FFFFFFFDCFF
增益
---------------------------------------------- ---- RBP - 0x20 = 0x7FFFFFFFDCF0
EDI 的值(value)
---------------------------------------------- ---- RBP - 0x24 = 0x7FFFFFFFDCEC
RSI 值
---------------------------------------------- ---- RBP - 0x30 = 0x7FFFFFFFDCE0 栈顶

关于c - 缓冲区溢出在 x86 上需要 16 个字节,但在 x64 上需要 29 个字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41537314/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com