gdb/pwndbg的使用
工欲善其事必先利其器,今天整理下gdb插件pwndbg的基础用法,方便查阅。
gdb
0x01 安装
$ git clone https://github.com/pwndbg/pwndbg
$ cd pwndbg
$ ./setup.sh
0x02 启动
- gdb+文件名或者gdb打开之后file 文件名.(只讨论命令行模式,不开启酷炫的GUI模式了)
$ gdb hello
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
******
Your encoding (ANSI_X3.4-1968) is different than UTF-8. pwndbg might not work properly.
You might try launching gdb with:
LC_ALL=en_US.UTF-8 PYTHONIOENCODING=UTF-8 gdb
Make sure that en_US.UTF-8 is activated in /etc/locale.gen and you called locale-gen
******
pwndbg: loaded 172 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from hello...done.
pwndbg>
0x03 断点
- 使用break或者b命令来下断点,值可以是函数名,行号或者源文件加序号
break main //main函数下断点
break 5 //在当前文件第五行下断点
break hello.c //在hello.c的第五行下断点
- info breakpoints命令可以打印出当前的断点信息,或者简写为i b
pwndbg> b main
Breakpoint 1 at 0x40052a: file 1.c, line 5.
pwndbg> i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000000040052a in main at 1.c:5
- delete breakpoints删除所有断点.clear+位置值删除特定断点
pwndbg> b 3
Breakpoint 5 at 0x40052a: file 1.c, line 3.
pwndbg> b 4
Note: breakpoint 5 also set at pc 0x40052a.
Breakpoint 6 at 0x40052a: file 1.c, line 4.
pwndbg> b 5
Note: breakpoints 5 and 6 also set at pc 0x40052a.
Breakpoint 7 at 0x40052a: file 1.c, line 5.
pwndbg> i b
Num Type Disp Enb Address What
5 breakpoint keep y 0x000000000040052a in main at 1.c:3
6 breakpoint keep y 0x000000000040052a in main at 1.c:4
7 breakpoint keep y 0x000000000040052a in main at 1.c:5
pwndbg> clear 1.c:3
Deleted breakpoint 5
pwndbg> i b
Num Type Disp Enb Address What
6 breakpoint keep y 0x000000000040052a in main at 1.c:4
7 breakpoint keep y 0x000000000040052a in main at 1.c:5
pwndbg> delete breakpoints
pwndbg> i b
No breakpoints or watchpoints.
- enable或disable+断点编号来启用或禁用断点
pwndbg> i b
Num Type Disp Enb Address What
8 breakpoint keep y 0x000000000040052a in main at 1.c:5
pwndbg> disable 8
pwndbg> i b
Num Type Disp Enb Address What
8 breakpoint keep n 0x000000000040052a in main at 1.c:5
0x04 步进
-
next/n执行下一条命令,遇到函数不进入.step/s同,遇到函数进入
-
continue/c断续执行到断点
-
只敲一下回车键将重复最后输入的命令
0x05 检查变量
- print/p显示某个值.display/disp会在每一步都显示那个值,pwndbg显示的内容实在是太多了,不推荐用这个
pwndbg> print $rax
$1 = 13
pwndbg>
- printf类似于c语言的printf函数,可以格式化输出内容
pwndbg> printf "%d\n",$rax
4195622
pwndbg> printf "%08x\n",$rax
00400526
0x06 输出格式
- 一般来说,GDB会根据变量的类型输出变量的值。但你也可以自定义GDB的输出的格式。
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十六进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量。
(gdb) p i
$21 = 101
(gdb) p/a i
$22 = 0x65
(gdb) p/c i
$23 = 101 'e'
(gdb) p/f i
$24 = 1.41531145e-43
(gdb) p/x i
$25 = 0x65
(gdb) p/t i
$26 = 1100101
0x07 查看内存
- 使用examine/x来查看内存地址中的值
x/<n/f/u> <addr>
n、f、u是可选的参数。
n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容。
f 表示显示的格式,参见上面。如果地址所指的是字符串,那么格式可以是s,如果地址是指令地址,那么格式可以是i。
u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字节,g表示八字节。当我们指定了字节长度后,GDB会从指定的内存地址开始,读写指定字节,并把其当作一个值取出来。
<addr>表示一个内存地址。
n/f/u三个参数可以一起使用。例如:
命令:x/3uh 0x54320 表示,从内存地址0x54320读取内容,h表示以双字节为一个单位,3表示三个单位,u表示按十进制显示。
pwndbg
0x01 上下文
- 每次GDB停止时,打印当前执行上下文的有用摘要,显示所有的寄存器,栈,反汇编等,如果想显示源码需要在编译的时候加上-g选项.所有内存地址都按其所代表的内存类型进行颜色编码.
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
────────────────────────────────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────────────────────────────────
RAX 0xd
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7ffff7dd3780 (_IO_stdfile_1_lock) ◂— 0x0
RDI 0x1
RSI 0x602010 ◂— 'hello world!\n'
R8 0x602000 ◂— 0x0
R9 0xd
R10 0x7ffff7dd1b78 (main_arena+88) —▸ 0x602410 ◂— 0x0
R11 0x246
R12 0x400430 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe750 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe670 —▸ 0x400550 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe660 —▸ 0x7fffffffe750 ◂— 0x1
RIP 0x40053f (main+25) ◂— mov eax, 0
──────────────────────────────────────────────────────────────────────────[ DISASM ]──────────────────────────────────────────────────────────────────────────
0x40052e <main+8> mov dword ptr [rbp - 4], 1
0x400535 <main+15> mov edi, 0x4005d4
0x40053a <main+20> call puts@plt <0x400400>
► 0x40053f <main+25> mov eax, 0
0x400544 <main+30> leave
0x400545 <main+31> ret
↓
0x7ffff7a2d830 <__libc_start_main+240> mov edi, eax
0x7ffff7a2d832 <__libc_start_main+242> call exit <0x7ffff7a47030>
0x7ffff7a2d837 <__libc_start_main+247> xor edx, edx
0x7ffff7a2d839 <__libc_start_main+249> jmp __libc_start_main+57 <0x7ffff7a2d779>
0x7ffff7a2d83e <__libc_start_main+254> mov rax, qword ptr [rip + 0x3a8ecb] <0x7ffff7dd6710>
──────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]───────────────────────────────────────────────────────────────────────
In file: /1.c
3 int main()
4 {
5 int a = 1;
6 printf("hello world!\n");
7
► 8 return 0;
9 }
──────────────────────────────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe660 —▸ 0x7fffffffe750 ◂— 0x1
01:0008│ 0x7fffffffe668 ◂— 0x100000000
02:0010│ rbp 0x7fffffffe670 —▸ 0x400550 (__libc_csu_init) ◂— push r15
03:0018│ 0x7fffffffe678 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
04:0020│ 0x7fffffffe680 ◂— 0x0
05:0028│ 0x7fffffffe688 —▸ 0x7fffffffe758 —▸ 0x7fffffffe956 ◂— 0x48006f6c6c65682f /* '/hello' */
06:0030│ 0x7fffffffe690 ◂— 0x100000000
07:0038│ 0x7fffffffe698 —▸ 0x400526 (main) ◂— push rbp
────────────────────────────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────────────────────────────
► f 0 40053f main+25
f 1 7ffff7a2d830 __libc_start_main+240
0x02 堆检查
- arena
- mp
- bins
- fastbins
- unsortedin
- smallbins
- largebins
- heap
- malloc_chunk a
- top_chunk
0x03 流程状态检查
- 使用proinfo命令检查当前进程状态
pwndbg> procinfo
exe '/hello'
pid 172
tid 172
ppid 169
uid [0, 0, 0, 0]
gid [0, 0, 0, 0]
groups []
fd[0] /dev/pts/0
fd[1] /dev/pts/0
fd[2] /dev/pts/0
0x04 搜索
- 使用search查找字节,字符串或者是各种整数值和指针
pwndbg> search -s hello
hello 0x4005d4 push 0x6f6c6c65 /* 'hello world!' */
hello 0x6005d4 'hello world!'
warning: Unable to access 16000 bytes of target memory at 0x7ffff7bd4d04, halting search.
[stack] 0x7fffffffe958 0x4f48006f6c6c6568 /* 'hello' */
[stack] 0x7fffffffeff2 0x6f6c6c6568 /* 'hello' */
更多
-
只是总结了一些最简单的用法,更多内容: