栈及栈溢出

1、内存空间分布

常规的内存布局,在UNIX环境高级编程中:

栈及栈溢出_第1张图片

代码段: (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

栈及栈溢出_第2张图片

readelf -a a.out 

栈及栈溢出_第3张图片

https://blog.csdn.net/love_gaohz/article/details/41310597

2、栈溢出

-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;
 }

栈及栈溢出_第4张图片

栈及栈溢出_第5张图片

类似的:

#include 

int main(void)
{
	int i;
	int a[10];
	for(i = 0; i<=10; ++i)
	{
		a[i] = 0;
		printf("i=%d\n",i);
	}
}

栈及栈溢出_第6张图片

3、栈攻击

假如一个应用程序如下,根据栈溢出漏洞攻击。

#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

栈及栈溢出_第7张图片

 

栈及栈溢出_第8张图片

 

你可能感兴趣的:(栈及栈溢出)