常规的内存布局,在UNIX环境高级编程中:
代码段: (code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域通常为固定大小的、只读的。同时,字符串常量也属于这部分。
数据段:数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。初始化为非零值的全局变量。
BSS段:(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。初始化为0或未初始化的全局变量和静态变量。
堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小不固定,可动态扩张或缩减。动态内存区域,使用malloc等手动
申请的内存。
栈(stack):栈又称堆栈,存放程序的局部变量除此以外,在函数被调用时,栈用来传递参数和返回值等。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。
局部变量、参数、返回值都存在这里,函数调用开始会参数入栈、局部变量入栈;调用结束依次出栈。
段名 | 内容 |
代码段 | 可执行代码、字符串常量 |
数据段 | 已初始化全局变量、已初始化全局静态变量、局部静态变量、常量数据 |
BSS段 | 未初始化全局变量,初始化为0的全局变量 |
栈 | 局部变量、函数参数 |
堆 | 动态内存分配 |
/*代码段、数据段和BSS段存储变量类型*/
#include
const int g_A = 10; //代码段
int g_B = 20; //数据段
static int g_C = 30; //数据段
static int g_D; //BSS段
int g_E; //BSS段
char *p1; //BSS段
void main( )
{
int local_A; //栈
static int local_C = 0; //数据段
static int local_D; //数据段
char *p3 = "123456"; //123456在代码段,p3在栈上
p1 = (char *)malloc( 10 ); //堆,分配得来得10字节的区域在堆区
strcpy( p1, "123456" ); //123456{post.content}放在常量区,编译器可能会将它与p3所指向 的"123456"优化成一块
printf("\n");
printf( "代码段,全局初始化变量, 只读const, g_A, addr:0x%08x\n", &g_A);
printf("\n");
printf( "数据段,全局变量, 初始化 g_B, addr:0x%08x\n", &g_B);
printf( "数据段,静态全局变量, 初始化, g_C, addr:0x%08x\n", &g_C);
printf("\n");
printf( "BSS段, 全局变量, 未初始化 g_E, addr:0x%08x\n", &g_E, g_E );
printf( "BSS段, 静态全局变量, 未初始化, g_D, addr:0x%08x\n", &g_D );
printf( "BSS段, 静态局部变量, 初始化, local_C, addr:0x%08x\n", &local_C);
printf( "BSS段, 静态局部变量, 未初始化, local_D, addr:0x%08x\n", &local_D);
printf("\n");
printf( "栈, 局部变量, local_A, addr:0x%08x\n", &local_A );
printf("\n");
printf( "堆, malloc分配内存, p1, addr:0x%08x\n", p1 );
}
gcc -g a.c
readelf -a a.out
https://blog.csdn.net/love_gaohz/article/details/41310597
-fno-stack-protector
gcc victim.c -o victim -z execstack -g -fno-stack-protector
小端模式(Little-endian):低字节存储在低地址
#include
#include
int main(int argc, char *argv[])
{
int flag = 0;
char passwd[10];
memset(passwd,0,sizeof(passwd));
strcpy(passwd, argv[1]);
if(0 == strcmp("LinuxGeek", passwd))
{
flag = 1;
}
if(flag)
{
printf("\n Password cracked \n");
}
else
{
printf("\n Incorrect passwd \n");
}
return 0;
}
类似的:
#include
int main(void)
{
int i;
int a[10];
for(i = 0; i<=10; ++i)
{
a[i] = 0;
printf("i=%d\n",i);
}
}
假如一个应用程序如下,根据栈溢出漏洞攻击。
#include
int main() {
char name[64];
printf("What's your name?");
scanf("%s", name);
printf("Hello, %s!\n", name);
return 0;
}
esp:堆栈指针(esp)指向堆栈的顶部
ebp:基指针或帧指针,指向当前运行的函数的栈桢中的一个固定位置,并为访问函数参数和本地变量提供一个稳定的参考点(基)。ebp仅在函数调用开始或结束时更改。
gcc victim.c -o victim -z execstack -g -fno-stack-protector
[section .text]
global _start
_start:
jmp END
BEGIN:
mov rax, 1
mov rdi, 1
pop rsi
mov rdx, 5
syscall
mov rax, 0x3c
mov rdi, 0
syscall
END:
call BEGIN
DB "Hack!"
nasm -f elf64 shell.asm
ld -s -o shell shell.o
用objdump
程序提取出机器码 objdump -d shell -M intel