GDB
基础命令
程序控制
r / run # 运行程序
c / continue # 继续执行
n / next # 单步(不进函数) / c代码
s / step # 单步(进函数) / c代码
ni # 执行一条 CPU 指令 / 汇编
si #
finish # 跑完当前函数
Ctrl + C # 强制暂停(神器)
断点相关
下断点和删除断点
i b / info b #查看所有断点信息
b *0x123456 #地址断点
b fun_name #函数断点
b file_name:15 #给file_name的15行下断点,要有源码才行
b +0x10 #在程序当前停住的位置下0x10的位置下断点,同样可以-0x10,就是前0x10
break fun if $rdi==5 #条件断点,rdi值为5的时候才断
delete 5 / d 5 删除5号断点,直接delete不接数字删除所有
disable 5 禁用5号断点
enable 5 启用5号断点
内存断点
watch 0x123456 //0x123456地址的数据改变的时候会断
watch a //变量a改变的时候会断
info watchpoints //查看watch断点信息
捕获断点
info break //catch的断点可以通过i b查看
catch syscall //syscall系统调用的时候断住
tcatch syscall //syscall系统调用的时候断住,只断一次
除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可以指定系统调用号,或者系统名称
寄存器相关
regs # 所有寄存器(pwndbg)
context # 栈 / 寄存器 / 代码(超级常用)
info registers # gdb 原生
栈 & 内存
stack
telescope $rsp
x/40gx $rsp
x/gx 0x404000
x/20gx $rbp-0x80
x/s 0x404078
打印查看指令
-
内存查看指令
x /nuf 0x123456 n代表显示几个单元(而不是显示几个字节,后面的u表示一个单元多少个字节) u代表一个单元几个字节,b(一个字节),h(俩字节),w(四字节),g(八字节) f代表显示数据的格式,f和u的顺序可以互换,也可以只有一个或者不带n,用的时候很灵活 x 按十六进制格式显示变量。 d 按十进制格式显示变量。 u 按十六进制格式显示无符号整型。 o 按八进制格式显示变量。 t 按二进制格式显示变量。 a 按十六进制格式显示变量。 c 按字符格式显示变量。 f 按浮点数格式显示变量。 s 按字符串显示。 b 按字符显示。 i 显示汇编指令。x /10gx 0x123456 //常用,从0x123456开始每个单元八个字节,十六进制显示是个单元的数据 x /10xd $rdi //从rdi指向的地址向后打印10个单元,每个单元4字节的十进制数 x /10i 0x123456 //常用,从0x123456处向后显示十条汇编指令 -
打印指令(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 0x123456 //显示0x123456前后的汇编指令 x /10i -
寄存器值查看
i r eax
修改和
修改数据指令set
set $rdi=0x10 //把rdi寄存器的值变为0x10
set $eax=1
set *(0x123456)=0x10 //0x123456地址的值变为0x10,
set args “abc” “def” “gh“//给参数123赋值
set args “python -c ‘print “1234\x7f\xde”’” //使用python给参数赋值不可见字符
查找数据
search rdi //从当前位置向后查包含rdi的指令,返回若干
search -h //查看search帮助
find “hello” //查找hello字符串,pwndbg独有
ropgadget //查找ropgadget,pwndbg独有
查看可写段
vmmap
查找连续字符
32字节大小的字符往往是各种算法所需要的常量,故我们可以在read下断,然后扫描内存:
catch syscall read
run
continue
find /b 0x400000, 0x800000, 'e', '4', 'Y', '8' //遇到不可访问内存会停止
search <指定字符串>
如果不知道字符串的内容,在pwndbg中使用下面命令:
import gdb, re
inf = gdb.selected_inferior()
pat = re.compile(rb'[A-Za-z0-9]{32}')
start = 0x400000
end = 0x800000
step = 0x1000
for base in range(start, end, step):
try:
data = inf.read_memory(base, step)
except gdb.MemoryError:
continue
for m in pat.finditer(data):
print(hex(base + m.start()), m.group().decode('ascii', 'ignore'))
end

需要注意的是,这个命令依然会跳过不可读内存
调用栈
寻找某个函数的返回地址
调用链: game()->scanf()
bt #查看调用栈
frame 4 #切换到第四帧(scanf的帧)
info frame #看rip at 0x7fffffffdc28(最后一行),这是当前scanf函数返回地址在栈上的位置。可以把他修改为其他指令的地址来劫持,saved rip=0x4015a存储的是call scanf的下一个汇编指令的地址。
x/gx $rsp #查看当前栈帧的栈顶,通常是当前函数的返回地址
telescope $rsp #看的更清楚


上面那个图是game()函数内的命令。
接下来我们返回到game函数的栈帧
p/x $rbp-0x60 #查看game函数内的一个变量的地址
p/x (&rbp-0x60)+(-3)*8

反汇编
寻找某个函数的返回地址
disas game #反汇编这个函数
b *0x401af #断点在caller命令下一个地址
c
p/x $rbp #查看caller的函数的返回地址
x/gx $rbp-0x78 #查看_QWORD v6[12]; // [rsp+10h] [rbp-60h] BYREF这种变量的地址位置
disassemble/disass命令
disassemble
-
disassemble [Function]
指定要反汇编的函数。如果指定,反汇编命令将产生整个函数的反汇编输出。
(gdb) disassemble main -
isassemble [Address]
指定要反汇编的地址。请注意,当仅指定一个地址时,此命令将反汇编包含给定地址的整个函数,包括其上方的指令。
(gdb) disassemble 0x00000000004008fd -
disassemble [Start],[End]
指定要反汇编的起始地址和结束地址。如果使用这种形式,该命令将不会反汇编整个函数,而只会反汇编起始地址和结束地址之间的指令。
(gdb) disassemble 0x000000000040068a,0x00000000004006ac-
disassemble [Function],+[Length]
disassemble [Address],+[Length]指定从给定地址或函数开始反汇编的字节数,例如:
(gdb) disassemble main, +10 -
libc
指定libc
(gdb) set environment LD_PRELOAD=./libc-2.xx.so
(gdb) run
debuginfod 服务
pwndbg 是可以在有调试符号的情况下显示源码,在程序崩溃时会停在崩溃的地方。
debuginfod是 elfutils项目提供的“调试符号分发服务”,它通过HTTP API把debuginfo、可执行文件和源代码按需推送给调试器,省去手动安装 *.debuginfo包的麻烦。
# 本地先清掉旧缓存,防止 debuginfod 不再拉取
rm -rf ~/.cache/debuginfod_client/$(readelf -n cook|grep -Po 'Build ID: \K.*')
# 启动 gdb 并令程序崩溃
DEBUGINFOD_URLS="http://<靶机>:8000" gdb ./cook
(gdb) r # 不加参数,程序崩溃自动停到源码行
调试c语言代码
创建文件
gcc -g -O0 -Wall main.c -o main

浙公网安备 33010602011771号