gdb


持续更新

前言

本文指令是建立在安装了 pwndbg 插件的 gdb 上的。

基本指令

  • s(step)单步步入,遇到函数调用会进入函数内部
    • si 汇编层面执行单步操作
  • n (next)单步步过,遇到函数不进入
    • ni  常用,同n,汇编层面的一步
  • c (continue)继续执行到断点,没断点就一直执行下去
  • r 重新开始执行
  • start 重新运行程序暂停到_start函数
  • finish 步出函数
  • q quit 退出调试

查看调试信息

  • context 查看调试器上下文

  • argc 查看命令行参数的数量

  • argv 查看命令行参数

  • args 查看程序参数

  • i(info)查看一些信息,只输入info可以看可以接什么参数,下面几个比较常用

    • i b //常用,info break 查看所有断点信息(编号、断点位置)
    • i r //常用,info registers 查看各个寄存器当前的值
    • i f //info function 查看所有函数名,需保留符号
  • show 用于查看调试器的基本信息

    • show directories 查看gdb的源码搜索路径
    • show environment 查看环境变量
  • backtrace 查看调用栈

  • vmmap 内存分配情况

  • jump命令可以用来跳转到指定的代码行或函数地址。

    • 跳转到指定的代码行:jump <line_number>
    • 跳转到指定的函数:jump <function_name>
    • 跳转到指定的内存:jump *<address>
  • dir 命令用于设置或显示源代码文件的搜索路径。具体来说,dir 命令可以用来告诉 GDB 在哪里查找源代码文件,以便在调试时能够正确显示源码。

  • tls查看线程

  • telescope 解引用

  • info variables查看所有的变量信息

  • p &__bss_start查看bss段起始位置

  • info functions 显示函数

  • i frame 打印函数堆栈帧信息

  • info sharedlibrary 显示共享链接库

  • cyclic 50  生成 50 个用来溢出的字符,默认生成 100 个

  • magic 查看常用的漏洞利用点

  • $reabse 开启PIE的情况的地址偏移

    • b *$reabse(0x123456) //断住PIE状态下的二进制文件中0x123456的地方
    • codebase //打印PIE偏移,与rebase不同,这是打印,rebase是使用
  • stack 查看栈

  • retaddr //打印包含返回地址的栈地址

  • canary //直接看canary的值

  • plt //查看plt表

  • got //查看got表

  • hexdump 显示十六进制数据并显示ASCII字符

  • `environ

  • ld

  • elf 显示elf段表的头部信息

  • info files 显示有关elf文件的信息,包括加载的段信息

  • xinfo 以结构体的方式输出内存地址的详细信息

断点指令

下普通断点指令b(break):

  • b 函数名

  • b 行号

  • b *地址

  • b *(0x123456) //常用,给0x123456地址处的指令下断点

    • b *$ rebase(0x123456) //$rebase 在调试开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的时候才断

删除、禁用断点:

  • info break(简写: i b) //查看断点编号
  • delete 5 //常用,删除5号断点,直接delete不接数字删除所有
  • disable 5 //常用,禁用5号断点
  • enable 5 //启用5号断点
  • clear //清除下面的所有断点

内存断点指令watch:

  • watch 0x123456 //0x123456地址的数据改变的时候会断
  • watch a //变量a改变的时候会断
  • info watchpoints //查看watch断点信息

捕获断点catch:

  • catch syscall //syscall系统调用的时候断住
  • tcatch syscall //syscall系统调用的时候断住,只断一次
  • info break //catch的断点可以通过i b查看
1
2
3
4
5
6
7
8
9
10
11
除syscall外还可以使用的有:
1)throw: 抛出异常
2)catch: 捕获异常
3)exec: exec被调用
4)fork: fork被调用
5)vfork: vfork被调用
6)load: 加载动态库
7)load libname: 加载名为libname的动态库
8)unload: 卸载动态库
9)unload libname: 卸载名为libname的动态库
10)syscall [args]: 调用系统调用,args可以指定系统调用号,或者系统名称

打印指令

打印指令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指向的值

打印汇编指令disass(disassemble):

  • disass 0x123456 //显示0x123456前后的汇编指令
  • x /10i //我一般喜欢用x显示指令

查看和修改数据

查看内存指令

  • x /nuf 0x123456 //常用,x指令的格式是:x空格/nfu,nfu代表三个参数
    • n代表显示几个单元(而不是显示几个字节,后面的u表示一个单元多少个字节),放在/后面
    • u代表一个单元几个字节,b(一个字节),h(2字节),w(四字节),g(八字节)
    • f代表显示数据的格式,f和u的顺序可以互换,也可以只有一个或者不带n,用的时候很灵活
1
2
3
4
5
6
7
8
9
10
11
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十六进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量。
s 按字符串显示。
b 按字符显示。
i 显示汇编指令。
  • x /10gx 0x123456 //常用,从0x123456开始每个单元八个字节,十六进制显示10个单元的数据
  • x /10xd $rdi //从rdi指向的地址向后打印10个单元,每个单元4字节的十进制数
  • x /10i 0x123456 //常用,从0x123456处向后显示十条汇编指令

修改数据指令

  • set $rdi=0x10 //把rdi寄存器的值变为0x10
  • set *(0x123456)=0x10 //0x123456地址的值变为0x10,注意带星号
    • set *(short *)(0x123456)=0x1234设置2字节的值
    • set *(int *)(0x123456)=0x12345678设置4个字节的值
    • set *(long long *)(0x123456)=0x12345678设置8个字节的值
  • set args "abc" "def" "gh" //给参数123赋值
  • set args "python -c 'print "1234\x7f\xde"'"' //使用python给参数赋值不可见字符
  • 使用set $pc命令
    • 使用set $pc=0x8048400直接设置程序计数器的值,来达到跳转到指定地址的目的

查找数据

  • search rdi //从当前位置向后查包含rdi的指令,返回若干
  • find "hello" //查找hello字符串,pwndbg独有
  • ropgadget //查找ropgadget,pwndbg独有,没啥用,可以用其他工具
  • search -p canary搜索canary位置

堆操作指令

  • arena //显示arena的详细信息

  • arenas //显示所有arena的基本信息

  • arenainfo //好看的显示所有arena的信息

  • x/32gx &main_arena查看main_arena的内存分配情况

  • x/32gx &main_arena 查看main_arena上的值

  • call malloc_stats() 打印malloc分配的内存

  • p malloc(0x100) 打印分配的堆块

  • info threads 多线程调试

  • bins 

    • fastbins //单独查看fastbins的链表情况
    • largebins //同上,单独查看largebins的链表情况
    • smallbins //同上,单独查看smallbins的链表情况
    • unsortedbin //同上,单独查看unsortedbin链表情况
    • tcachebins //同上,单独查看tcachebins的链表情况
    • tcache //查看tcache详细信息
  • heap 显示堆信息

  • heap -v 查看堆块的详细信息

    • heapbase  查看堆起始地址
    • heapinfoheapinfoall //显示堆得信息,和bins的挺像的,没bins好用
    • parseheap //显示堆结构,很好用
    • vis可视化堆
  • tracemalloc //好用,会跟提示所有操作堆的地方

内存转储命令

  • 使用dump命令
    • dump binary memory <filename> <start_address> <end_address>
      • <filename>:要保存内存转储的文件名
      • <start_address>:要转储的内存区域的起始地址
      • <end_address>:要转储的内存区域的结束地址
  • 查看转储的文件
    • hexdump -C dump.bin
  • 从文件加载内存
    • restore <filename> binary memory <start_address> <end_address>
      • <filename>:包含内存内容的文件名
      • <start_address>:要恢复到的内存区域的其实地址
      • <end_address>:要恢复到的内存区域的结束地址

源码调试

  • list 默认查看附近10行代码
    • list 38 查看38行附近10行代码
    • list 1,10 查看1-10行
    • list main 查看main函数开始10行

远程调试

  • 在目标机器上运行gdbserver
1
gdbserver <hostname>:<port> ./demo
  • 连接gdbserver
1
target remote <hostname>:<port>
  • gdbserver附加现有进程
1
gdbserver --attach <hostname>:<port> pid

内核调试

待施工