我正在通过实验室工作,以演示对流利用的缓冲。我可以使用它,但是有一个地方我不太了解我希望有人能为我解释。
这是带有漏洞的代码:
/* Vunlerable program: stack.c */
/* You can get this program from the lab’s website */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int bof(char *str)
{
char buffer[24];
/* The following statement has a buffer overflow problem */
strcpy(buffer, str); ➀
return 1;
}
int main(int argc, char **argv)
{
char str[517];
FILE *badfile;
badfile = fopen("badfile", "r");
fread(str, sizeof(char), 517, badfile);
bof(str);
printf("Returned Properly\n");
return 1;
}
实验室的第一步是确定分配给缓冲区的内存大小[24]。为此,我需要在bof函数上运行gdb,我可以看到我的系统上分配的内存为0x20,即32位。
如果更改缓冲区的大小,则可以运行gdb并找到分配的内存插槽。但是我是否应该能够知道在没有gdb的情况下将为buffer [24]分配多少内存?如果我更改为buffer [8],我应该一眼就知道32位系统上的内存块是什么,或者它在系统上是否有所不同?如果我应该知道,有人可以解释如何做。
答案 0 :(得分:1)
这取决于目标平台,编译器和编译标志。
例如,处于调试模式(-O0
)的GCC 7.2 x86在16字节边界上对齐堆栈帧并分配帧指针(ebp)。
示例:(godbolt link)
bof(char*):
push ebp ; -4
mov ebp, esp
sub esp, 40 ; -40
sub esp, 8 ; -8
push DWORD PTR [ebp+8] ; -4
lea eax, [ebp-32] ; 32 bytes to top of stack frame
push eax ; -4
call strcpy ; stack is aligned to 16 bytes (-64)
add esp, 16
mov eax, 1
leave
ret
在(-O2
)上启用了优化的情况下,省略了帧指针,但堆栈仍按16个字节(godbolt link)对齐:
bof(char*):
sub esp, 52 ; -52
push DWORD PTR [esp+56] ; -4
lea eax, [esp+20] ; 36 bytes to top of stack frame
push eax ; -4
call strcpy ; stack is aligned to 16 bytes (-64)
mov eax, 1
add esp, 60
ret
强制进行4字节堆栈对齐(-O2 -mpreferred-stack-boundary=2
)(godbolt link):
bof(char*):
sub esp, 24 ; -24
push DWORD PTR [esp+28] ; -4
lea eax, [esp+4] ; 24 bytes to top of stack frame
push eax ; -4
call strcpy
mov eax, 1
add esp, 32
ret
在(-O2 -fstack-protector-all
)(godbolt link)上启用了堆栈保护器:
bof(char*):
sub esp, 52 ; -52
mov eax, DWORD PTR gs:20
mov DWORD PTR [esp+36], eax ; stack check value at -16 (-52+36)
xor eax, eax
push DWORD PTR [esp+56] ; -4
lea eax, [esp+16] ; 40 bytes to top of stack frame, leaving exactly 24 bytes to check value
push eax
call strcpy
add esp, 16
mov edx, DWORD PTR [esp+28]
xor edx, DWORD PTR gs:20
jne .L5
mov eax, 1
add esp, 44
ret
.L5:
call __stack_chk_fail
其他编译器可能会有完全不同的结果。
在现实生活中,在汇编模式下通过分析指令并计数字节数到函数的返回地址来利用缓冲区溢出,因此无论源代码是什么或如何编译(此信息通常不可用)无论如何)。