GDB调试基础
1. 启动GDB
|
|
如上图所示,gdb启动后,默认进入gdb的命令行模式,并打开了一个二进制文件,通过run指令进行了运行。 输入start指令,进入gdb的调试模式。
- STACK 含义:栈(Stack) 描述:栈是程序运行时用于存储局部变量、函数调用信息和返回地址的内存区域。每当函数被调用时,栈会存储当前函数的局部变量、参数和返回地址等信息。栈通常是向下增长的(即栈顶地址减小)。 用途:在调试时,STACK 区域显示的是当前栈的内容,包括函数调用栈、局部变量等。
- HEAP 含义:堆(Heap) 描述:堆是程序动态分配内存的地方(比如通过 malloc、calloc 等动态内存分配函数)。堆的内存是由程序员显式管理的,可以进行手动分配和释放。堆的分配方式通常是向上增长的。 用途:HEAP 区域会显示当前程序使用的动态分配的内存,包括由 malloc、free 等操作分配的内存块。在调试时,这有助于你检查内存泄漏或溢出等问题。
- CODE 含义:代码段(Code Segment) 描述:代码段是存放程序指令(机器代码)的区域。这部分内存是只读的,程序的执行代码存储在这里。一般来说,代码段是只读的,以防止程序在运行时修改其自身的指令。 用途:CODE 区域显示程序的机器指令,可以通过它来检查正在执行的代码,反汇编操作通常会展示这个区域。
- DATA 含义:数据段(Data Segment) 描述:数据段是用来存放程序的全局变量和静态变量的地方。这些变量在程序执行期间保持固定的内存位置。数据段通常包括初始化的数据(如全局变量的初始值)和未初始化的数据(例如 BSS 段)。 用途:DATA 区域显示程序的全局变量和静态变量的内存布局,帮助调试全局状态和数据。
- WX 含义:可写且可执行(Writable and Executable) 描述:标记为 WX 的内存区域是既可写又可执行的。这种内存区域通常是存在漏洞的地方,例如程序可能会被攻击者通过写入一些恶意代码并随后执行它,导致代码注入攻击。 用途:如果程序中有 WX 区域,它可能会被用来检查是否存在不当的内存访问,尤其是在涉及堆栈溢出、代码注入等漏洞时。
- RODATA 含义:只读数据段(Read-Only Data Segment) 描述:只读数据段通常存储程序中常量数据(如字符串常量)。这些数据在程序运行过程中不会被修改,因此通常放在只读内存区域。 用途:RODATA 区域显示的是程序的只读数据,例如 const 字符串、常量数组等。 总结 这些内存区域分别代表了程序运行时不同类型的内存空间: STACK:局部变量、函数调用栈 HEAP:动态分配的内存 CODE:程序的执行代码 DATA:全局变量和静态变量 WX:既可写又可执行的内存区域(通常存在漏洞时) RODATA:只读数据(例如常量)
各部分分支:
寄存器部分 反编译部分,显示汇编指令 栈空间分配 栈调用查看
常用gdb指令:
基本指令
- help //查看帮助
- q //退出gdb
运行指令
- n //单步步过,可以理解为下一步,遇到调用不跟进,相当于step over,源码层面的一步
- ni //常用,同n,汇编层面的一步
- s //单步步入,可以理解为下一步,遇到调用跟进函数中,源码层面的一步
- si //常用,同s,汇编层面的一步
- fini //运行到当前函数结束
- r //run, 巨常用 重新开始执行
- c //执行到断点
断点指令
下普通断点指令b(break):
- b *(0x123456) //常用,给0x123456地址处的指令下断点
- b
*$rebase(0x123456)
//$rebase 在调试开PIE的程序的时候可以直接加上程序的随机地址, 打开随机化PIE保护时常用 - b fun_name //常用,给函数fun_name下断点,目标文件要保留符号才行
- b file_name:fun_name
- b file_name:15 //给file_name的15行下断点,要有源码才行
- b 15
- b +0x10 //在程序当前停住的位置下0x10的位置下断点,同样可以-0x10,就是前0x10
- break fun if $rdi==5 //条件断点,rdi值为5的时候才断
删除和禁用断点
- d b 断点编号 //删除断点 == delete 断点编号 //删除指定断点
- i b //查看断点信息
- disable 断点编号 //禁用指定断点
- enable 断点编号 //启用指定断点
- clear //清楚所有断点
捕获断点catch
- catch syscall //syscall调用是断住
打印指令p(print):
- p fun_name //打印fun_name的地址,需要保留符号
- p 0x10-0x08 //计算0x10-0x08的结果
- p &a //查看变量a的地址
- p *(0x123456) //查看0x123456地址的值,注意和x指令的区别,x指令查看地址的值不用星号
- p $rdi //显示rdi寄存器的值,注意和x的区别,这只是显示rdi的值,而不是rdi指向的值
- p *($rdi) //显示rdi指向的值
- x /nfu 0x123456 //常用,x指令的格式是:x空格/nfu,nfu代表三个参数
参数: N 查看数量,代表显示几个单元(而不是显示几个字节,后面的u表示一个单元多少个字节),放在’/‘后面 F 代表查看所用的格式) U 规定一块内容有几字节——b(1字节)、h(2字节)、w(4字节)、g(8字节),放在’f’后面 F:进制
- x 按十六进制格式显示变量。
- d 按十进制格式显示变量。
- u 按十六进制格式显示无符号整型。
- o 按八进制格式显示变量。
- t 按二进制格式显示变量。
- a 按十六进制格式显示变量。
- c 按字符格式显示变量。
- f 按浮点数格式显示变量。
- s 按字符串显示。
- b 按字符显示。
- i 显示汇编指令。
例子
-
x /10xg 0x123456 //常用,从0x123456开始每个单元八个字节,十六进制显示是个单元的数据
-
x /10xd $rdi //从rdi指向的地址向后打印10个单元,每个单元4字节的十进制数
-
x /10i 0x123456 //常用,从0x123456处向后显示十条汇编指令
-
i r //查看寄存器的值
-
telescope/tele (可加参数)//从某个地址开始展开信息 ❤
杂项
- stack //查看栈
- retaddr //打印包含返回地址的栈地址❤
- canary //直接看canary的值(没用过)
- plt //查看plt表
- got //查看got表
- checksec //检查程序保护
- vmmap //查看内存空间和权限 ❤
堆操作指令(pwndbg独有)
- arena //显示arena详情信息
- arenas //显示所有arena基本信息
- arenainfo //好看的显示信息
- bins
常用,查看所有种类的堆块的链表信息- fastbins //查看fastbin的链表信息
- unsortedbin //查看unsortedbin的链表信息
- smallbins //查看smallbin的链表信息
- largebins //查看largebin的链表信息
- tcache //查看tcache的详情信息
- tcachebins //查看tcachebins的链表信息
- heap //显示堆信息
- heapbase //查看堆起始地址
- heapinfo/heapinfoall //显示堆信息, 但是不如bins好用
- parseheap //解析堆信息 ❤
- tracemalloc //好用,会提示所有操作堆的地方 ❤
以一道NewStar CTF2024 题名gdb
为例
下载附件后进入发现main函数
|
|
SUB_12E5
为加密函数,加密看不懂(出题人故意的)
动调查看
找到偏移地址
b *$rebase(0x181A)
运行到调用处停下,
RDI存储加密内容,RSI存储加密密钥(len),所以我们复制加密内容地址,然后ni单步运行后再输入
tel 0x7fffffffd7d7
此时已经转换成加密后的样子了
发送
b'\x5d\x1d\x43\x55\x53\x45\x57\x45
即可