栈踩踏实验

栈踩踏实验文章详细阐述了程序在内存中的分布 包括 data bss got plt rodata 等节的作用

程序的存储结构

分布

在磁盘和内存中的分布如下:
在这里插入图片描述
节视图
.data:已经初始化的全局变量/局部静态变量
.bss:未初始化的全局变量/局部静态变量
.got.plt:全局偏移量表,保存全局变量引用的地址
.rodata:只读数据
text:代码节,保存了程序执行的代码
.init:程序初始化和终止的代码
段视图
stack:栈,向低地址生长
heap:堆,向高地址生长
data:读写权限的数据段
code:具有执行权限的数据段

以hello world为例

// gcc -m32 -no-pie -g -o main main.c
#include <stdio.h>

int main()
{
   
	printf("hello world\n");
	return 0;
}

objdump -h main #可查看各个节的位置

alientek@ubuntu16:~/Desktop/exc$ objdump -h main

main:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .interp       00000013  08048154  08048154  00000154  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  08048168  08048168  00000168  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  08048188  08048188  00000188  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .gnu.hash     00000020  080481ac  080481ac  000001ac  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .dynsym       00000050  080481cc  080481cc  000001cc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynstr       0000004a  0804821c  0804821c  0000021c  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .gnu.version  0000000a  08048266  08048266  00000266  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version_r 00000020  08048270  08048270  00000270  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .rel.dyn      00000008  08048290  08048290  00000290  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rel.plt      00000010  08048298  08048298  00000298  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .init         00000023  080482a8  080482a8  000002a8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 11 .plt          00000030  080482d0  080482d0  000002d0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .plt.got      00000008  08048300  08048300  00000300  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .text         00000192  08048310  08048310  00000310  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .fini         00000014  080484a4  080484a4  000004a4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 15 .rodata       00000014  080484b8  080484b8  000004b8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .eh_frame_hdr 0000002c  080484cc  080484cc  000004cc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .eh_frame     000000cc  080484f8  080484f8  000004f8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 18 .init_array   00000004  08049f08  08049f08  00000f08  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 19 .fini_array   00000004  08049f0c  08049f0c  00000f0c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 20 .jcr          00000004  08049f10  08049f10  00000f10  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 21 .dynamic      000000e8  08049f14  08049f14  00000f14  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 22 .got          00000004  08049ffc  08049ffc  00000ffc  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 23 .got.plt      00000014  0804a000  0804a000  00001000  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 24 .data         00000008  0804a014  0804a014  00001014  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 25 .bss          00000004  0804a01c  0804a01c  0000101c  2**0
                  ALLOC
 26 .comment      00000035  00000000  00000000  0000101c  2**0
                  CONTENTS, READONLY
 27 .debug_aranges 00000020  00000000  00000000  00001051  2**0
                  CONTENTS, READONLY, DEBUGGING
 28 .debug_info   0000008f  00000000  00000000  00001071  2**0
                  CONTENTS, READONLY, DEBUGGING
 29 .debug_abbrev 00000042  00000000  00000000  00001100  2**0
                  CONTENTS, READONLY, DEBUGGING
 30 .debug_line   00000038  00000000  00000000  00001142  2**0
                  CONTENTS, READONLY, DEBUGGING
 31 .debug_str    000000d3  00000000  00000000  0000117a  2**0
                  CONTENTS, READONLY, DEBUGGING

ldd 命令用于打印程序或者共享库文件所依赖的共享库列表。注意,ldd 本身不是一个二进制程序,而是一个 Shell 脚本,使用文本编辑器 vim 可以查看其内容.

alientek@ubuntu16:~/Desktop/exc$ ldd main
        linux-gate.so.1 =>  (0xf7f4d000)
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xf7d75000)
        /lib/ld-linux.so.2 (0xf7f4f000)

gdb-peda 插件

跑起来以后

gdb-peda$ vmmap
Start      End        Perm      Name
0x08048000 0x08049000 r-xp      /home/alientek/Desktop/exc/main
0x08049000 0x0804a000 r--p      /home/alientek/Desktop/exc/main
0x0804a000 0x0804b000 rw-p      /home/alientek/Desktop/exc/main
0xf7dfe000 0xf7dff000 rw-p      mapped
0xf7dff000 0xf7faf000 r-xp      /lib/i386-linux-gnu/libc-2.23.so
0xf7faf000 0xf7fb0000 ---p      /lib/i386-linux-gnu/libc-2.23.so
0xf7fb0000 0xf7fb2000 r--p      /lib/i386-linux-gnu/libc-2.23.so
0xf7fb2000 0xf7fb3000 rw-p      /lib/i386-linux-gnu/libc-2.23.so
0xf7fb3000 0xf7fb6000 rw-p      mapped
0xf7fd3000 0xf7fd4000 rw-p      mapped
0xf7fd4000 0xf7fd7000 r--p      [vvar]
0xf7fd7000 0xf7fd9000 r-xp      [vdso]
0xf7fd9000 0xf7ffc000 r-xp      /lib/i386-linux-gnu/ld-2.23.so
0xf7ffc000 0xf7ffd000 r--p      /lib/i386-linux-gnu/ld-2.23.so
0xf7ffd000 0xf7ffe000 rw-p      /lib/i386-linux-gnu/ld-2.23.so
0xfffdd000 0xffffe000 rw-p      [stack]

elf文件

C语言函数栈帧与传参

函数执行过程

:函数在调用过程中,会在内存中开辟一块名为栈帧的空间,用于存放局部变量等数据,由编译器管理。
:由程序员管理。

ESP(Extended stack pointer)存放的都是栈顶地址。
EBP(Extended base pointer)该指针总是指向当前栈帧的底部(高地址)。

push和pop命令,会自动来更改 esp寄存器。
每个栈帧对应着一个未运行完的函数,包括主函数。栈帧中保存了该函数的返回地址、和局部变量。

别人的: 栈踩踏实验
栈踩踏实验

以add程序为例

参数较少,编译成32位可执行程序,才会采用栈传参。

//main2.c
int  add(int a,int b)
{
   
    int c = 0;
    c = a + b;
    return c;
}
int main()
{
   
    int a=0;
    int b=1;
    int sum=0;
    sum=add(a,b);
    return 0;
}

gdb-peda 看汇编代码

0x80483f8 <main>:    push   ebp 
0x80483f9 <main+1>:  mov    ebp,esp #从栈顶开始跑了
0x80483fb <main+3>:  sub    esp,0x10#可能是流出
0x80483fe <main+6>:  mov    DWORD PTR [ebp-0xc],0x0 #a
0x8048405 <main+13>: mov    DWORD PTR [ebp-0x8],0x1 #b
0x804840c <main+20>: mov    DWORD PTR [ebp-0x4],0x0 #sum
0x8048413 <main+27>: push   DWORD PTR [ebp-0x8] #b入栈
0x8048416 <main+30>: push   DWORD PTR [ebp-0xc] #a入栈
0x8048419 <main+33>: call   0x80483db <add> #调用子函数
0x804841e <main+38>: add    esp,0x8
0x8048421 <main+41>: mov    DWORD PTR [ebp-0x4],eax
0x8048424 <main+44>: mov    eax,0x0
0x8048429 <main+49>: leave  
0x804842a <main+50>: ret  

在执行main时候,EBP=0xffffd128,栈从ESP=0xffffd118开始生长。

0x80483dc <add+1>:   mov    ebp,esp
0x80483de <add+3>:   sub    esp,0x10
0x80483e1 <add+6>:   mov    DWORD PTR [ebp-0x4],0x0 #c
0x80483e8 <add+13>:  mov    edx,DWORD PTR [ebp+0x8] #取函数参数
0x80483eb <add+16>:  mov    eax,DWORD PTR [ebp+0xc] #取函数参数
0x80483ee <add+19>:  add    eax,edx
0x80483f0 <add+21>:  mov    DWORD PTR [ebp-0x4],eax #结果存在c
0x80483f3 <add+24>:  mov    eax,DWORD PTR [ebp-0x4] #返回值放在ax里面
0x80483f6 <add+27>:  leave  
0x80483f7 <add+28>:  ret 

进入 add子函数后,EBP=0xffffd108,ESP从0xffffd0f8开始生长。

栈的分布

0000| 0xffffd0f8 --> 0xf7e2da60 (add    ebx,0x1845a0)#add的栈帧
0004| 0xffffd0fc --> 0x804847b (<__libc_csu_init+75>:   add    edi,0x1)
0008| 0xffffd100 --> 0x1 
0012| 0xffffd104 --> 0xffffd1c4 --> 0xffffd342 ("/home/alientek/Desktop/exc/main2")
0016| 0xffffd108 --> 0xffffd128 --> 0x0 #add的栈帧
0020| 0xffffd10c --> 0x804841e (<main+38>:      add    esp,0x8)
0024| 0xffffd110 --> 0x0 
0028| 0xffffd114 --> 0x1 
0000| 0xffffd118 --> 0x8048439 (<__libc_csu_init+9>:    add    ebx,0x1bc7)#main的栈帧
0004| 0xffffd11c --> 0x0 
0008| 0xffffd120 --> 0x1 
0012| 0xffffd124 --> 0x0 
0016| 0xffffd128 --> 0x0 #main的栈帧
0020| 0xffffd12c --> 0xf7e17647 (<__libc_start_main+247>:       add    esp,0x10)
0024| 0xffffd130 --> 0x1 
0028| 0xffffd134 --> 0xffffd1c4 --> 0xffffd342 ("/home/alientek/Desktop/exc/main2")

栈踩踏

写一个子函数里面数组越界的例子

//main3.c
void test(void)
{
   
    char tmp[4];
    tmp[20]=1;
    return;
}
int main()
{
   
    test();
    return 0;
}

test函数的汇编指令如下,给tmp[20]赋值实际上写到了0xffffd10c这个地址上了,这里记录了test子函数返回时,应该执行的main函数的地址,把地址破坏了,该程序无法继续运行了。

   0x8048447 <test+12>: mov    DWORD PTR [ebp-0xc],eax
   0x804844a <test+15>: xor    eax,eax
   0x804844c <test+17>: mov    BYTE PTR [ebp+0x4],0x1

这段代码的栈如下

0000| 0xffffd0f0 --> 0x1 
0004| 0xffffd0f4 --> 0x400000 ('')
0008| 0xffffd0f8 --> 0xf7e2da60 (add    ebx,0x1845a0)
0012| 0xffffd0fc --> 0x80484db (<__libc_csu_init+75>:   add    edi,0x1)
0016| 0xffffd100 --> 0x1 
0020| 0xffffd104 --> 0xffffd1c4 --> 0xffffd342 ("/home/alientek/Desktop/exc/main3")
0024| 0xffffd108 --> 0xffffd118 --> 0x0 
0028| 0xffffd10c --> 0x804847a (<main+22>:      mov    eax,0x0)
0000| 0xffffd110 --> 0xf7fb23dc --> 0xf7fb31e0 --> 0x0 #main的栈帧
0004| 0xffffd114 --> 0xffffd130 --> 0x1 
0008| 0xffffd118 --> 0x0 #main的BSP
0012| 0xffffd11c --> 0xf7e17647 (<__libc_start_main+247>:       add    esp,0x10)
0016| 0xffffd120 --> 0xf7fb2000 --> 0x1b2db0 
0020| 0xffffd124 --> 0xf7fb2000 --> 0x1b2db0 
0024| 0xffffd128 --> 0x0 
0028| 0xffffd12c --> 0xf7e17647 (<__libc_start_main+247>:       add    esp,0x10)

运行结果

alientek@ubuntu16:~/Desktop/exc$ ./main3
Illegal instruction
编程小号
上一篇 2025-01-09 16:17
下一篇 2025-01-09 16:06

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/106290.html