说明
本文主要讲解简单栈溢出的基本原理, 如果有什么不对的地方或者更好的建议, 还请大佬指正.
工具准备
- linux系统
- 调试工具gdb
- gdb插件:pwndbg
- pwntools工具包
关于pwndbg插件和pwntools可以在github搜索并下载安装,需要python环境
函数栈帧与ESP、EBP寄存器
C语言中,每个栈帧对应一个未运行完的函数. 栈帧中保存了函数的局部变量和返回地址, 即保存着函数的执行环境.
------摘自百度百科
ESP寄存器保存着栈帧的栈顶地址, EBP寄存器保存着当前函数栈帧的栈底地址. (32位系统为ESP、EBP, 64位系统为RSP、RBP, 其它寄存器同理)
call指令、leave指令与ret指令
汇编语言中, 用call指令来实现函数的调用, 指令格式: call address;
call指令效果相当于"push eip; jump address;". 不仅是跳转到指定函数地址执行指令, 在跳转之前还将当前IP寄存器中的值(下一条指令的地址)压入到了栈中. 从而可以在被调函数执行完之后, 继续执行当前函数.
在被调函数执行完毕后, 程序要准备退出函数, 需要leave指令来释放函数栈帧, 并使EBP寄存器恢复旧值, 执行的操作相当于"mov esp,ebp; pop ebp; “, 之后ret指令将程序执行流返回上层函数. 有点c语言中return语句的意味. ret指令效果相当于"pop eip;”. 即将栈顶保存的值出栈, 作为下一条将要执行指令的地址赋值给IP寄存器.
造成栈溢出的原因
系统栈是由高地址往低地址增长的, 而数据的写入是按低地址到高地址的顺序写入. 如果程序没有对输入的字符数量做出限制, 就存在数据溢出当前栈帧以及覆盖返回地址的可能, 从而实现控制程序的执行流.
溢出原理
以32位可执行程序为例, 我们将通过调试分析下面这段简单的代码来理解栈溢出.
#include<stdio.h>
#include<unistd.h>
void shell(){
system("/bin/sh");
}
void vulnerable(){
char buf[16];
gets(buf);
}
int main(){
vulnerable();
}
可以看到buf大小只有16字节,而gets()函数却可以无限输入,不检查字符上限, 直到遇到’\n’字符为止.
我们将c文件编译链接成可执行文件:
# 编译参数先不讲解,在后面讲解保护机制时解释
# 只需知道-m32是将.c文件编译成32位程序即可
gcc -m32 -fno-stack-protector -no-pie main.c -o stack
我们用objdump 来反汇编一下生成的可执行文件(部分反汇编代码):
08049172 <shell>:
8049172: 55 push ebp
8049173: 89 e5 mov ebp,esp
8049175: 83 ec 08 sub esp,0x8
8049178: 83 ec 0c sub esp,0xc
804917b: 68 08 a0 04 08 push 0x804a008
8049180: e8 bb fe ff ff call 8049040 <system@plt>
8049185: 83 c4 10 add esp,0x10
8049188: 90 nop
8049189: c9 leave
804918a: c3 ret
0804918b <vulnerable>:
804918b: 55 push ebp
804918c: 89 e5 mov ebp,esp
804918e: 83 ec 18 sub esp,0x18
8049191: 83 ec 0c sub esp,0xc
8049194: 8d 45 e8 lea eax,[ebp-0x18]
8049197: 50 push eax
8049198: e8 93 fe ff ff call 8049030 <gets@plt>
804919d: 83 c4 10 add esp,0x10
80491a0: 90 nop
80491a1: c9 leave
80491a2: c3 ret
080491a3 <main>:
80491a3: 55 push ebp
80491a4: 89 e5 mov ebp,esp
80491a6: 83 e4 f0 and esp,0xfffffff0
80491a9: e8 dd ff ff ff call 804918b <vulnerable>
80491ae: b8 00 00 00 00 mov eax,0x0
80491b3: c9 leave
80491b4: c3 ret
80491b5: 66 90 xchg ax,ax
80491b7: 66 90 xchg ax,ax
80491b9: 66 90 xchg ax,ax
80491bb: 66 90 xchg ax,ax
80491bd: 66 90 x