讲解pwngdb的用法,以csapp的bomb lab phase_1为例

2024-04-01 22:36

本文主要是介绍讲解pwngdb的用法,以csapp的bomb lab phase_1为例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

参考资料

  • Guide to Faster, Less Frustrating Debugging

什么情况下会使用gbd

  • 需要逆向ELF文件时(掌握gdb的使用,是二进制安全的基本功)
  • 开发程序时,程序执行结果不符合预期

动态调试ELF文件可以使用另外一种方法:IDA的远程linux动态调试。个人觉得使用ida调试更为方便,因为ida是图形化界面,那么可以使用鼠标交互,比如通过鼠标光标确定打断点的位置等等。而且IDA具有反编译功能,对初学者较为友好。

为什么使用gbd呢
调试程序时,我们可能习惯使用printf , cout函数直接将变量打印在控制台上。如果用printf作为调试的主要方式,好处是这种做法确实方便,但以下缺点也会大大影响调试的进度(以及个人心情)

  • printf一个变量后,发现那个变量的值是正确的,需要继续printf其他变量
  • 大量printf会将编写的代码变得惨不忍睹,在测试完后,还需要将编写的printf删除掉
  • 如果我们要检查一个结构体变量有没有符合预期,使用printf将这个变量的所有属性打印出来十分繁琐。(虽然我更喜欢用IDE自带的调试功能观察2333)

所以我个人认为,在编写程序时,可以适当使用printf作为调试的手段,但如果太过依赖它,反而会事倍功半

接下来说一下gbd的好处:

  • 需要掌握的命令少,和markdown一样,熟练使用了就能转换成自己的肌肉记忆。
  • 具有一个调试器应该有的功能,如可以显示运行程序的寄存器,运行时栈堆,支持反汇编等等 (虽然使用体验确实比不上支持图形化的调试器2333)

常用命令

知乎:GDB使用详解


介绍一下打断点的方式

  • b functionName: 在函数的入口处添加断点
  • b line: 在文件的第line行添加断点
  • b *adderess 在某一个地址添加断点

解下来以csapp的第二个lab为例,讲解pwngdb的使用

这篇博客假设大家已经有汇编语言基础,因此我不会花很多篇幅在汇编语句讲解上 😃

我之所以使用pwngdb,是因为之前做ctf pwn题目时配置好了。pwngdb比起原版的gdb新增了一些独有的指令,尤其是在堆的方面。

csapp lab的网页: https://csapp.cs.cmu.edu/3e/labs.html

分析整个程序的流程如下:
输入disassemble main观察main函数反汇编的结果

0x0000000000400e2d <+141>:	call   0x400b10 <puts@plt>0x0000000000400e32 <+146>:	call   0x40149e <read_line>0x0000000000400e37 <+151>:	mov    rdi,rax0x0000000000400e3a <+154>:	call   0x400ee0 <phase_1>0x0000000000400e3f <+159>:	call   0x4015c4 <phase_defused>0x0000000000400e44 <+164>:	mov    edi,0x4023a80x0000000000400e49 <+169>:	call   0x400b10 <puts@plt>0x0000000000400e4e <+174>:	call   0x40149e <read_line>0x0000000000400e53 <+179>:	mov    rdi,rax0x0000000000400e56 <+182>:	call   0x400efc <phase_2>0x0000000000400e5b <+187>:	call   0x4015c4 <phase_defused>0x0000000000400e60 <+192>:	mov    edi,0x4022ed0x0000000000400e65 <+197>:	call   0x400b10 <puts@plt>0x0000000000400e6a <+202>:	call   0x40149e <read_line>0x0000000000400e6f <+207>:	mov    rdi,rax0x0000000000400e72 <+210>:	call   0x400f43 <phase_3>0x0000000000400e77 <+215>:	call   0x4015c4 <phase_defused>0x0000000000400e7c <+220>:	mov    edi,0x40230b0x0000000000400e81 <+225>:	call   0x400b10 <puts@plt>0x0000000000400e86 <+230>:	call   0x40149e <read_line>0x0000000000400e8b <+235>:	mov    rdi,rax0x0000000000400e8e <+238>:	call   0x40100c <phase_4>0x0000000000400e93 <+243>:	call   0x4015c4 <phase_defused>0x0000000000400e98 <+248>:	mov    edi,0x4023d80x0000000000400e9d <+253>:	call   0x400b10 <puts@plt>0x0000000000400ea2 <+258>:	call   0x40149e <read_line>0x0000000000400ea7 <+263>:	mov    rdi,rax0x0000000000400eaa <+266>:	call   0x401062 <phase_5>0x0000000000400eaf <+271>:	call   0x4015c4 <phase_defused>0x0000000000400eb4 <+276>:	mov    edi,0x40231a0x0000000000400eb9 <+281>:	call   0x400b10 <puts@plt>0x0000000000400ebe <+286>:	call   0x40149e <read_line>0x0000000000400ec3 <+291>:	mov    rdi,rax0x0000000000400ec6 <+294>:	call   0x4010f4 <phase_6>0x0000000000400ecb <+299>:	call   0x4015c4 <phase_defused>

一般来说,函数的返回值会放在eax寄存器中。所以以下的代码

   0x0000000000400e32 <+146>:	call   0x40149e <read_line>0x0000000000400e37 <+151>:	mov    rdi,rax0x0000000000400e3a <+154>:	call   0x400ee0 <phase_1>

read_line读取的字符串先放在rax寄存器中,再经过mov rdi,rax 放在rdi寄存器中。

接下来分析第一关卡:
b phase_1打下断点,r运行程序。接着输入一串字符串,为了表示方便,我称其为input
按下s 程序单步运行,结果如下图。
在这里插入图片描述

在上面的截图中,程序被蓝色的横线分为了三个区域

  • 最上面的是寄存器区域,用于显示各个寄存器的值。寄存器有很多作用:比如数据可以存储在寄存器里,数据也可以通过寄存器在函数之间传递。高级语言中的if , while等等功能都可以通过汇编语言实现,这需要使用到寄存器:比如将数据与寄存器中的值进行比较,如果小于就进行跳转命令等等。
  • 中间区域是反汇编区域,这是程序的运行代码。绿色箭头表示程序当前位置。
  • 最下面的区域是栈区。栈区存放函数的参数,返回地址,局部变量等等内容

如果使用gdb,按下s的时候可能不会跳出这么多内容
可以使用以下命令打印寄存器的值

info registers

或者是

i r

要打印栈的内容和栈帧信息,可以执行以下命令:

info frame

或者是

i f

继续单步执行。
在这里插入图片描述
这段代码告诉我们传入strings_not_equal的参数是什么
一个参数是我们输入的input字符串 。 另一个参数是程序自带的字符串Border relations with Canada have never been better.

解释一下:rdi: 0x003780 <- 0x333231

0x003780 表示rdi寄存器指向内存地址
0x333231 表示这段地址里存放的值
123 是0x333231 ascii码对应的字符

按下s ,分析strings_not_equal函数的代码

0x401338 <strings_not_equal>       push   r120x40133a <strings_not_equal+2>     push   rbp0x40133b <strings_not_equal+3>     push   rbx0x40133c <strings_not_equal+4>     mov    rbx, rdi0x40133f <strings_not_equal+7>     mov    rbp, rsi0x401342 <strings_not_equal+10>    call   string_length                      <string_length>0x401347 <strings_not_equal+15>    mov    r12d, eax0x40134a <strings_not_equal+18>    mov    rdi, rbp0x40134d <strings_not_equal+21>    call   string_length                      <string_length>0x401352 <strings_not_equal+26>    mov    edx, 10x401357 <strings_not_equal+31>    cmp    r12d, eax

这段代码调用string_length函数,用于取得字符串的长度。接着使用cmp r12d , eax比较两个传入字符串的长度。如果长度一样,那么第一关就过了。

接下来验证我们的想法:
分别在0x401342 和0x40134d添加临时断点,tb *0x401342 tb *0x40134d。然后按下c 运行到断点。按下n让函数执行完毕,观察rax 寄存器的值

第一个string_length函数执行完毕的寄存器页面
在这里插入图片描述

第二个string_lenth函数执行完毕的寄存器页面
在这里插入图片描述

按下r重新运行。输入字符串Border relations with Canada have never been better.
这样关卡1就通过了。

使用gdb是熟能生巧的过程,只要多练就能掌握这个软件的使用😃
在这里插入图片描述


照例meme时间

当导师发现你没有在规定时间内完成任务时 be like↓
在这里插入图片描述
摸了一周鱼的我 be like↓
在这里插入图片描述
不多说了,要赶紧完成java web的管理系统和qt的文件编辑器了 😭

这篇关于讲解pwngdb的用法,以csapp的bomb lab phase_1为例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/868308

相关文章

解读GC日志中的各项指标用法

《解读GC日志中的各项指标用法》:本文主要介绍GC日志中的各项指标用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、基础 GC 日志格式(以 G1 为例)1. Minor GC 日志2. Full GC 日志二、关键指标解析1. GC 类型与触发原因2. 堆

MySQL数据库中ENUM的用法是什么详解

《MySQL数据库中ENUM的用法是什么详解》ENUM是一个字符串对象,用于指定一组预定义的值,并可在创建表时使用,下面:本文主要介绍MySQL数据库中ENUM的用法是什么的相关资料,文中通过代码... 目录mysql 中 ENUM 的用法一、ENUM 的定义与语法二、ENUM 的特点三、ENUM 的用法1

JavaSE正则表达式用法总结大全

《JavaSE正则表达式用法总结大全》正则表达式就是由一些特定的字符组成,代表的是一个规则,:本文主要介绍JavaSE正则表达式用法的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录常用的正则表达式匹配符正则表China编程达式常用的类Pattern类Matcher类PatternSynta

MySQL之InnoDB存储引擎中的索引用法及说明

《MySQL之InnoDB存储引擎中的索引用法及说明》:本文主要介绍MySQL之InnoDB存储引擎中的索引用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录1、背景2、准备3、正篇【1】存储用户记录的数据页【2】存储目录项记录的数据页【3】聚簇索引【4】二

mysql中的数据目录用法及说明

《mysql中的数据目录用法及说明》:本文主要介绍mysql中的数据目录用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、版本3、数据目录4、总结1、背景安装mysql之后,在安装目录下会有一个data目录,我们创建的数据库、创建的表、插入的

嵌入式数据库SQLite 3配置使用讲解

《嵌入式数据库SQLite3配置使用讲解》本文强调嵌入式项目中SQLite3数据库的重要性,因其零配置、轻量级、跨平台及事务处理特性,可保障数据溯源与责任明确,详细讲解安装配置、基础语法及SQLit... 目录0、惨痛教训1、SQLite3环境配置(1)、下载安装SQLite库(2)、解压下载的文件(3)、

深度解析Python装饰器常见用法与进阶技巧

《深度解析Python装饰器常见用法与进阶技巧》Python装饰器(Decorator)是提升代码可读性与复用性的强大工具,本文将深入解析Python装饰器的原理,常见用法,进阶技巧与最佳实践,希望可... 目录装饰器的基本原理函数装饰器的常见用法带参数的装饰器类装饰器与方法装饰器装饰器的嵌套与组合进阶技巧

Mysql中isnull,ifnull,nullif的用法及语义详解

《Mysql中isnull,ifnull,nullif的用法及语义详解》MySQL中ISNULL判断表达式是否为NULL,IFNULL替换NULL值为指定值,NULLIF在表达式相等时返回NULL,用... 目录mysql中isnull,ifnull,nullif的用法1. ISNULL(expr) → 判

Java中的for循环高级用法

《Java中的for循环高级用法》本文系统解析Java中传统、增强型for循环、StreamAPI及并行流的实现原理与性能差异,并通过大量代码示例展示实际开发中的最佳实践,感兴趣的朋友一起看看吧... 目录前言一、基础篇:传统for循环1.1 标准语法结构1.2 典型应用场景二、进阶篇:增强型for循环2.

Python get()函数用法案例详解

《Pythonget()函数用法案例详解》在Python中,get()是字典(dict)类型的内置方法,用于安全地获取字典中指定键对应的值,它的核心作用是避免因访问不存在的键而引发KeyError错... 目录简介基本语法一、用法二、案例:安全访问未知键三、案例:配置参数默认值简介python是一种高级编