提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

@


前言

昨天发布的文章主要是以一些报错问题为主,今天主要是对pwngdb调试以及基础ret2text题目进行总结吧,ps:目前只学了ret2text。
申明:我写博客的目的是为了给自己做一份笔记,如果有一起学习的师傅也陷入了和我一样的困境,希望能够帮助他们,接受师傅们的批评指正。


提示:以下是本篇文章正文内容,下面案例可供参考

一、pwngdb安装

这个完全可以参考以下两位师傅的博客进行安装

https://www.cnblogs.com/seyedog/p/18432103
https://blog.csdn.net/qq_41202237/article/details/118188924

包括环境的配置也是根据两位师傅的来即可

二、使用pwngdb

1.基本使用

我认为使用pwngdb是很有必要的,以便我们进行动态的调试,好好的打基础对以后是有好处的。
我简单说几个指令:(ai的)

gdb 文件名    // 启动调试器并加载目标文件(开启你的“上帝视角”)
ni          // 单步步过(执行下一条汇编指令,遇到 call 函数调用时不进去,直接当成一条指令跑完)
si          // 单步步入(执行下一条汇编指令,遇到 call 函数调用时跟进去,深挖函数内部逻辑)
start       // 启动程序并在入口处(通常是 main)自动暂停(比 run 好用,能让你看清初始化过程)
b *地址      // 在特定内存地址下断点(注意 * 号不能少,它告诉 GDB 这是一个绝对地址而不是函数名)
stack 数字   // 查看栈空间布局(显示指定行数的栈数据,用来观察溢出是否覆盖了返回地址)
c           // 继续执行(让程序一直跑,直到撞到下一个断点、程序结束或崩溃)
x/ <n><f><u> <addr> // 查看内存的万能命令(按指定格式 n:数量 f:格式 u:单位 扫描内存数据)
vmmap       // 查看内存映射表(关键命令!用来找 libc 基址、堆栈位置,以及检查哪里有 rwx 权限可执行 shellcode)

我目前使用的大概就是这些常用指令,可能也不全,以后再慢慢补充吧,也请各位师傅批评指正。

2.汇编

有的师傅认为学pwn要会汇编语言,我觉得是对的,但对我目前来说会一些指令即可
指令如下(ai的)

mov    // 【数据传送】 确实是赋值,但更像“复制”。
       // Pwn 视角:源操作数不变,目标被覆盖。
       // 例子:mov rdi, 0xdeadbeef  (把这个数放进寄存器,通常是为函数传参做准备)

sub    // 【减法】 
       // Pwn 视角:最常用于“开辟栈空间”。
       // 例子:sub rsp, 0x20  (栈顶指针减小,意味着为当前函数腾出了 32 字节的局部变量空间)

add    // 【加法】
       // Pwn 视角:最常用于“回收栈空间”或“调整指针”。
       // 例子:add rsp, 0x20 (函数执行完,把栈顶指针加回去,相当于释放了空间)

push   // 【压栈】 
       // Pwn 视角:两个动作 -> 1. rsp = rsp - 8 (栈顶抬高); 2. 把值放进去。
       // 关键:这是我们在构建 ROP 链时,手动在栈上布置数据的方式。
       
pop    // 【弹栈】
       // Pwn 视角:两个动作 -> 1. 把栈顶的值拿出来; 2. rsp = rsp + 8 (栈顶降低)。
       // 关键:这是 ROP 的核心!比如 `pop rdi; ret`,意思是把栈上的数据弹给 rdi 寄存器,从而控制函数参数。

ret    // 【返回】
       // Pwn 视角:本质是 pop rip。
       // 解释:CPU 会傻傻地把当前栈顶(rsp指向的值)弹出来,赋值给 rip。
       // 攻击点:如果我们把栈顶改成了 shellcode 的地址,ret 就会乖乖跳过去执行 shellcode。

call   // 【调用】
       // Pwn 视角:本质是 push 下一条指令地址 + jmp 目标函数。
       // 解释:它会先把“回家”的地址压入栈(方便以后 ret 回来),然后跳去执行函数。

这些指令都挺好理解的,都不难可以简单学习以下,以上只是我对这些指令的概述仅作参考。
认识完指令再认识几个目前用得到的寄存器
32位:eip,esp,ebp
64位:rip,rsp,rbp
以32位为例吧,因为64位的这几个寄存器的作用和32位的作用都一样。

eip   //指令指针,存储下一条将要被 CPU 执行的指令的内存地址。
esp   //栈顶指针,永远指向当前栈的 最顶部。
ebp   //栈底/基址指针,指向当前函数栈帧的 底部(基准点)。

总体思路是需要想办法让eip的下一条指令跳转到我们所谓的后门即可,下面进行实际操作。


以下程序来自于国资社畜师傅(讲gdb调试讲的很好)

IDA分析

打开程序
在这里插入图片描述
发现这里有一个dofunc调用,(这里先不讲函数调用)点进去看了以下发现有一个read函数,read是个危险函数,目前暂不做讲解。
在这里插入图片描述
此刻可以找一下后门函数,点看左边的func发现是一个后门函数
在这里插入图片描述
并且已经给写好了直接用即可,当然寻找后门的办法也有很多,以后再介绍吧。
现在目标很明确了,在我们调用了read函数之后,让返回地址返回到我们的后门函数func的地址即可获取shell,要看func的地址可以在ida中看,也可以在pwngdb中看,

pwngdb调试

因为本次博客是纯新手向,所以在本章中也会使用pwngdb调试计算偏移,不过多使用IDA。

在这里插入图片描述
因为我使用了两块屏幕,左边这块屏幕首先启动这个程序命令为 gdb 程序名
进入gdb后,start程序就可以启动了,目前是在main函数。输入了start后右边的屏幕才会像我这样。
右边的屏幕内容可以分为四部分
第一部分是寄存器的值
在这里插入图片描述
第二部分是汇编语言
在这里插入图片描述

第三部分是栈
在这里插入图片描述
第四部分是函数调用链
在这里插入图片描述

我们要进入到dofunc函数去修改返回地址,使用下一个命令:ni
使用了ni命令就会发现,目前箭头值得指的是第二条命令了,继续使用ni命令或者回车命令即可在这里插入图片描述
一直到call dofunc停下
在这里插入图片描述
下面采用si命令进入到dofunc命令里
在这里插入图片描述
这里看到汇编指令是这样的,明天我会补一起函数的调用,所以说有一些指令虽然看懂了但不知道做什么也是正常的
继续ni 知道看到read函数
我们先使用cyclic命令创建一些干扰字符,cyclic 50 然后复制生成的字符即可
在这里插入图片描述
继续ni就会提示让我们输入字符,粘贴cyclic命令生成的字符吗,此时此刻就可以看到栈里填充了我们使用的字符
在这里插入图片描述
这样看的不明显我们可以输入命令 stack 40 来仔细查看栈
在这里插入图片描述

这是ebp,esp的变化,会发现我们的额数据被填充进去了,但是我们要覆盖哪些呢,这是我们疑惑的点,面对这道题目来说我们只需要0xffffd59c即可,也就是ebp下面的地址,估计还有人不理解这是为什么,当然自己也可以去找一个函数调用的视频去看,也可以等着我明天讲一下这个问题,一般题也都是覆盖到ebp下面的地址即可,即在ebp下面的地址那里填写我们的后门函数地址,ebp及其以上地址进行字符覆盖即可,那么这个值怎么算呢,有两种方式。第一种方式用ebp-ecx+0x4即可(32位)之所以减掉ecx是因为我们的地址填充是从ecx的地址开始的,0x4是因为如果不加0x4只会覆盖到ebp上面的一个地址:0xffffd598,这样就可覆盖成功,我们可以使用x/进行计算,p指令也可以。在这里插入图片描述
现在思路应该理明白了,偏移就这么找即可。
下面介绍另外一种用gdb找偏移的方式,因为有的时候gcc编译并不会用寄存器作指针,有的时候不会在这里出现ebp,这样就很尴尬不知道找什么(我目前是这样的),于是就可以发挥esp的作用了,继续执行命令ni,直到ret那里。在这里插入图片描述
我们可以看到stack那里,esp的地址指向了faaa,也就是栈顶,ret返回也会返回到faaa,即下一条命令eip会变成0x61616166
我们使用cyclic -l 命令来查看这个值是多少

在这里插入图片描述
也是20,说明这个就是偏移,我们继续ni我们可以看到eip的值变了
在这里插入图片描述
偏移就这么成功的找到了,这个方式适用于没有找到ebp的方式,具体的专有名词我明天找找看。。。
目前思路全部理清,并且也知道怎么操作了,我们今天先使用gdb手工打一遍即可,我们重新输入start进行操作,这次生成20个字符即可。
在这里插入图片描述这里我们看到ebp及以上地址都被完整的覆盖了!再放一张另一个屏幕的图,等下可以看一下变化。
在这里插入图片描述
在这里插入图片描述

我们现在可以使用手工的方式设置ebp下面的值,我们通过iad找到func的地址
然后使用set命令进行修改
在这里插入图片描述
这样可以明显看到ebp下面的值被改掉了,改成了func的地址
继续使用ni命令
在这里插入图片描述
我们使用一次ni命令,查看以下右边屏幕有发现什么变化吗,我相信聪明的师傅们都看到了变化,在我一开始说的第四部分哪里,BACKTRACE从main变成了func,说明我们成功的修改了返回地址,gdb也识别出来了返回地址,继续ni,一直ni到func函数的system函数后,应该就可以直接执行shell了。
在这里插入图片描述
虽然有一点麻烦,但是这样也是挺爽的,这种都是最基本的题了。。。但是通过调试有更深的感悟了,感谢各位师傅的观看。

总结

重申:我写博客的目的是为了给自己做一份笔记,如果有一起学习的师傅也陷入了和我一样的困境,希望能够帮助他们,接受师傅们的批评指正。

posted on 2026-02-22 14:40  0x4a4  阅读(0)  评论(0)    收藏  举报