After using GDB for a while, you may find that some features, such as viewing stack layouts, are not very convenient to use directly with GDB. However, the core issues of operating systems often lie in memory management. For example, printing a doubly linked list is not easy to handle with GDB alone. So, is there a more user-friendly tool that can be used on top of GDB to debug some core operating system issues? The answer is yes, and that tool is Pwndbg, which allows for easier troubleshooting of core system problems.
Installing Pwndbg
Clone the repository directly and then install it.
git clone https://github.com/pwndbg/pwndbg.git
pip3 install poetry
./setup.sh
If you do not wish to recompile, you can directly download the precompiled binary according to the latest release build.
https://github.com/pwndbg/pwndbg/releases/download/2025.05.30/pwndbg_2025.05.30_arm64-portable.tar.xz
After successful installation, you can see that it loads a Python file by default through gdbinit, as shown below.
root@kylin:~# cat .gdbinit
source /root/pwndbg/gdbinit.py
Example Code
To demonstrate the advantages of Pwndbg over GDB, we will prepare a code example in malloc.c as follows:
#include <stdlib.h>
#include <string.h>
int main()
{
void *p = malloc(100*sizeof(char));
memset(p, 0x55, 100*sizeof(char));
memcpy(p + 100*sizeof(char), "kylin", strlen("kylin") + 1);
free(p);
}
After compiling, you can debug it with GDB.
Basic Debugging
When the code hits a breakpoint, Pwndbg provides all the information as shown below:
───────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]────────────────────────────────────────────────────────────────────────────────────────────
X0 0x412304 ◂— 0x2006e696c796b/* 'kylin' */
X1 0x400780 ◂— ldpsw x11, x30, [x11, #-0xa0] /* 'kylin' */
X2 6
X3 0x412304 ◂— 0x2006e696c796b/* 'kylin' */
X4 0x400786 ◂— madd w0, w0, w1, w0
X5 0x41230a ◂— 2
X6 0x696c796b
X7 0x6e696c
X8 0x38
X9 0x7ff7fadac0 (main_arena+96) —▸ 0x412300 ◂— 'UUUUkylin'
X10 0
X11 0x28
X12 0x7ff7e43e50 ◂— udf #0
X13 0
X14 0
X15 0x70
X16 0x7ff7ec4a10 (__memcpy_generic) ◂— prfm pldl1keep, [x1] /* ' ' */
X17 0x411000 ([email protected]) —▸ 0x7ff7ec4a10 (__memcpy_generic) ◂— prfm pldl1keep, [x1] /* ' ' */
X18 0
X19 0x4006d0 (__libc_csu_init) ◂— stp x29, x30, [sp, #-0x40]!
X20 0
X21 0x400570 (_start) ◂— mov x29, #0
X22 0
X23 0
X24 0
X25 0
X26 0
X27 0
X28 0
X29 0x7ffffff2b0 —▸ 0x7ffffff2d0 ◂— 0
SP 0x7ffffff2b0 —▸ 0x7ffffff2d0 ◂— 0
LR 0x4006bc (main+64) ◂— ldr x0, [sp, #0x18]
PC 0x4006bc (main+64) ◂— ldr x0, [sp, #0x18]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM / aarch64 / set emulate on ]────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x4006bc <main+64> ldr x0, [sp, #0x18] X0, [0x7ffffff2c8] => 0x4122a0 ◂— 'UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU...'
0x4006c0 <main+68> bl #free@plt <free@plt>
0x4006c4 <main+72> mov w0, #0 W0 => 0
0x4006c8 <main+76> ldp x29, x30, [sp], #0x20
0x4006cc <main+80> ret
0x4006d0 <__libc_csu_init> stp x29, x30, [sp, #-0x40]!
0x4006d4 <__libc_csu_init+4> mov x29, sp
0x4006d8 <__libc_csu_init+8> stp x19, x20, [sp, #0x10]
0x4006dc <__libc_csu_init+12> adrp x20, #0x410000 X20 => 0x410000 ◂— 0x10102464c457f
0x4006e0 <__libc_csu_init+16> add x20, x20, #0xe00
0x4006e4 <__libc_csu_init+20> stp x21, x22, [sp, #0x20]
──────────────────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]──────────────────────────────────────────────────────────────────────────────────────────────────────────────
In file: /root/malloc.c:9
4int main()
5 {
6 void *p = malloc(100*sizeof(char));
7 memset(p, 0x55, 100*sizeof(char));
8 memcpy(p + 100*sizeof(char), "kylin", strlen("kylin") + 1);
► 9 free(p);
10 }
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ x29 sp 0x7ffffff2b0 —▸ 0x7ffffff2d0 ◂— 0
01:0008│ 0x7ffffff2b8 —▸ 0x7ff7e60d90 (__libc_start_main+232) ◂— bl #0x7ff7e764b0
02:0010│ 0x7ffffff2c0 —▸ 0x4006d0 (__libc_csu_init) ◂— stp x29, x30, [sp, #-0x40]!
03:0018│ 0x7ffffff2c8 —▸ 0x4122a0 ◂— 'UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUkylin'
04:0020│ 0x7ffffff2d0 ◂— 0
05:0028│ 0x7ffffff2d8 —▸ 0x4005bc (_start+76) ◂— bl #0x400550
06:0030│ 0x7ffffff2e0 ◂— 0
07:0038│ 0x7ffffff2e8 ◂— 0
────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────────────────────────────────────────────────────
►0 0x4006bc main+64
1 0x7ff7e60d90 __libc_start_main+232
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
This includes the following sections:
Registers
The first part is the values of the registers, as all traces capture the current register values at the first moment. Pwndbg provides further simplifications based on the registers, such as:
- Parsing memory values
<span>0x412304 ◂— 0x2006e696c796b /* 'kylin' */</span> - Automatic symbol resolution
<span>0x7ff7ffd668 (_rtld_global_ro)</span> - Automatic character resolution
<span>0x7ff7fe5b28 ◂— '/lib/aarch64-linux-gnu/'</span> - Automatic disassembly of instructions
<span>0x4006d0 (__libc_csu_init) ◂— stp x29, x30, [sp, #-0x40]!</span> - Automatic linked list resolution
<span>X29 0x7fffffdf80 —▸ 0x7fffffdfb0 —▸ 0x7fffffe040 —▸ 0x7fffffe450 —▸ 0x7fffffe470 ◂— …</span> - Automatic PLT calculation
<span>0x411000 ([email protected]) —▸ 0x7ff7ec4a10 (__memcpy_generic) ◂— prfm pldl1keep, [x1] /* ' ' */</span>
This is much more convenient than calculating it ourselves in GDB.
Disassembly of Code Segment
The second part is the disassembly of the code corresponding to the breakpoint. Unlike GDB’s diss, it provides comments at key points, such as:
- Automatic comments on calculated register values
<span>ldr x0, [sp, #0x18] X0, [0x7ffffff2c8] => 0x4122a0 ◂— 'UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU…'</span> - Automatic comments on status register values
<span>cmp x20, x0 0x7ff7fffed0 - 0x0 CPSR => 0x20000000 [ n z C v q pan il d a i f el:0 sp ]</span> - Automatic comments on function jump locations
<span>bl #free@plt</span> - Automatic comments on LR register values
<span>ret <0x7ff7fd2f64></span> - Automatic comments on SP register linked lists
<span>mov sp, x29 SP => 0x7fffffdfb0 —▸ 0x7fffffe040 —▸ 0x7fffffe450 —▸ 0x7fffffe470 ◂— …</span> - Automatic comments on general register values
<span>mov w0, w28 W0 => 3</span> - Automatic comments on page values
<span>adrp x20, #0x410000 X20 => 0x410000 ◂— 0x10102464c457f</span>
Source Code
If GDB can find the source code, it will print the source code content directly.
In file: /root/malloc.c:9
4 int main()
5 {
6 void *p = malloc(100*sizeof(char));
7 memset(p, 0x55, 100*sizeof(char));
8 memcpy(p + 100*sizeof(char), "kylin", strlen("kylin") + 1);
► 9 free(p);
10 }
Stack Layout
The third part is the stack layout of the current function, which also provides detailed comments, as follows:
00:0000│ x29 sp 0x7ffffff2b0 —▸ 0x7ffffff2d0 ◂— 0
01:0008│ 0x7ffffff2b8 —▸ 0x7ff7e60d90 (__libc_start_main+232) ◂— bl #0x7ff7e764b0
02:0010│ 0x7ffffff2c0 —▸ 0x4006d0 (__libc_csu_init) ◂— stp x29, x30, [sp, #-0x40]!
03:0018│ 0x7ffffff2c8 —▸ 0x4122a0 ◂— 'UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUkylin'
04:0020│ 0x7ffffff2d0 ◂— 0
05:0028│ 0x7ffffff2d8 —▸ 0x4005bc (_start+76) ◂— bl #0x400550
06:0030│ 0x7ffffff2e0 ◂— 0
07:0038│ 0x7ffffff2e8 ◂— 0
Stack Frame Layout
In addition to the current stack layout, it also prints the code stack frame directly, as follows:
► 0 0x4006bc main+64
1 0x7ff7e60d90 __libc_start_main+232
Printing Context
Based on the above information, by default, when a breakpoint is hit, basic information will be printed. During debugging, you can also print the context at any time. For example, after modifying certain values, you can print all information at once, as follows:
pwndbg> context
Printing Memory
Using hexdump, you can directly view the memory content of malloc without needing to dump or use x to calculate.
pwndbg> hexdump p
+0000 0x4122a0 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 │UUUUUUUU│UUUUUUUU│
... ↓ skipped 2 identical lines (32 bytes)
+0030 0x4122d0 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 │UUUUUUUU│UUUUUUUU│
More User-Friendly Memory Viewing
In the code, I intentionally appended “kylin” after p. You can see that the hexdump of p has boundaries, while telescope prints directly afterwards, as shown below:
pwndbg> telescope p
00:0000│ 0x4122a0 ◂— 'UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUkylin'
... ↓ 7 skipped
Searching Memory
If you want to search in GDB, you must dump it out to find it. However, Pwndbg allows you to search for what you want directly using search. I marked “kylin” in p, and you can search as follows:
pwndbg> search kylin
Searching for value: 'kylin'
malloc 0x400780 ldpsw x11, x30, [x11, #-0xa0] /* 'kylin' */
malloc 0x410780 0x6e696c796b /* 'kylin' */
[heap] 0x412304 0x2006e696c796b /* 'kylin' */
libc-2.31.so 0x7ff7f665aa ldpsw x11, x30, [x11, #-0xa0]
warning: Unable to access 16000 bytes of target memory at 0x7ff7fa1d04, halting search.
[vdso] 0x7ff7ffc94d ldpsw x11, x30, [x11, #-0xa0] /* 'kylin1~20.04) 10.3.0' */
Printing GOT and PLT
The values of these two sections need to be calculated manually in GDB, while Pwndbg calculates them for you by default, as shown below:
pwndbg> got
State of the GOT of /root/malloc:
GOT protection: Partial RELRO | Found 7 GOT entries passing the filter
[0x411000] memcpy@GLIBC_2.17 -> 0x7ff7ec4a10 (__memcpy_generic) ◂— prfm pldl1keep, [x1] /* ' ' */
[0x411008] malloc@GLIBC_2.17 -> 0x7ff7eb9130 (malloc) ◂— adrp x2, #0x7ff7fac000
[0x411010] __libc_start_main@GLIBC_2.17 -> 0x7ff7e60ca8 (__libc_start_main) ◂— stp x29, x30, [sp, #-0x150]!
[0x411018] memset@GLIBC_2.17 -> 0x7ff7ec59c0 (__memset_generic) ◂— dup v0.16b, w1
[0x411020] __gmon_start__ -> 0x4004e0 ◂— stp x16, x30, [sp, #-0x10]!
[0x411028] abort@GLIBC_2.17 -> 0x4004e0 ◂— stp x16, x30, [sp, #-0x10]!
[0x411030] free@GLIBC_2.17 -> 0x4004e0 ◂— stp x16, x30, [sp, #-0x10]!
pwndbg> plt
Section .plt 0x4004e0-0x400570:
0x400500: memcpy@plt
0x400510: malloc@plt
0x400520: __libc_start_main@plt
0x400530: memset@plt
0x400540: __gmon_start__@plt
0x400550: abort@plt
Debugging Arena
Pwndbg provides convenient access to view the structure information of the arena for memory management, as shown below:
pwndbg> arena
Arena for thread 1 is located at: 0x7ff7fada60
{
mutex = 0,
flags = 0,
have_fastchunks = 0,
fastbinsY = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
top = 0x412300,
last_remainder = 0x0,
bins = {0x7ff7fadac0 <main_arena+96>, 0x7ff7fadac0 <main_arena+96>, 0x7ff7fadad0 <main_arena+112>, 0x7ff7fadad0 <main_arena+112>, 0x7ff7fadae0 <main_arena+128>, 0x7ff7fadae0 <main_arena+128>, 0x7ff7fadaf0 <main_arena+144>, 0x7ff7fadaf0 <main_arena+144>, 0x7ff7fadb00 <main_arena+160>, 0x7ff7fadb00 <main_arena+160>, 0x7ff7fadb10 <main_arena+176>, 0x7ff7fadb10 <main_arena+176>, 0x7ff7fadb20 <main_arena+192>, 0x7ff7fadb20 <main_arena+192>, 0x7ff7fadb30 <main_arena+208>, 0x7ff7fadb30 <main_arena+208>, 0x7ff7fadb40 <main_arena+224>, 0x7ff7fadb40 <main_arena+224>, 0x7ff7fadb50 <main_arena+240>, 0x7ff7fadb50 <main_arena+240>, 0x7ff7fadb60 <main_arena+256>, 0x7ff7fadb60 <main_arena+256>, 0x7ff7fadb70 <main_arena+272>, 0x7ff7fadb70 <main_arena+272>, 0x7ff7fadb80 <main_arena+288>, 0x7ff7fadb80 <main_arena+288>, 0x7ff7fadb90 <main_arena+304>, 0x7ff7fadb90 <main_arena+304>, 0x7ff7fadba0 <main_arena+320>, 0x7ff7fadba0 <main_arena+320>, 0x7ff7fadbb0 <main_arena+336>, 0x7ff7fadbb0 <main_arena+336>, 0x7ff7fadbc0 <main_arena+352>, 0x7ff7fadbc0 <main_arena+352>, 0x7ff7fadbd0 <main_arena+368>, 0x7ff7fadbd0 <main_arena+368>, 0x7ff7fadbe0 <main_arena+384>, 0x7ff7fadbe0 <main_arena+384>, 0x7ff7fadbf0 <main_arena+400>, 0x7ff7fadbf0 <main_arena+400>, 0x7ff7fadc00 <main_arena+416>, 0x7ff7fadc00 <main_arena+416>, 0x7ff7fadc10 <main_arena+432>, 0x7ff7fadc10 <main_arena+432>, 0x7ff7fadc20 <main_arena+448>, 0x7ff7fadc20 <main_arena+448>, 0x7ff7fadc30 <main_arena+464>, 0x7ff7fadc30 <main_arena+464>, 0x7ff7fadc40 <main_arena+480>, 0x7ff7fadc40 <main_arena+480>, 0x7ff7fadc50 <main_arena+496>, 0x7ff7fadc50 <main_arena+496>, 0x7ff7fadc60 <main_arena+512>, 0x7ff7fadc60 <main_arena+512>, 0x7ff7fadc70 <main_arena+528>, 0x7ff7fadc70 <main_arena+528>, 0x7ff7fadc80 <main_arena+544>, 0x7ff7fadc80 <main_arena+544>, 0x7ff7fadc90 <main_arena+560>, 0x7ff7fadc90 <main_arena+560>, 0x7ff7fade00 <main_arena+576>, 0x7ff7fade00 <main_arena+576>, 0x7ff7fade10 <main_arena+592>, 0x7ff7fade10 <main_arena+592>, 0x7ff7fade20 <main_arena+608>, 0x7ff7fade20 <main_arena+608>, 0x7ff7fade30 <main_arena+624>, 0x7ff7fade30 <main_arena+624>, 0x7ff7fade40 <main_arena+640>, 0x7ff7fade40 <main_arena+640>, 0x7ff7fade50 <main_arena+656>, 0x7ff7fade50 <main_arena+656>, 0x7ff7fade60 <main_arena+672>, 0x7ff7fade60 <main_arena+672>, 0x7ff7fade70 <main_arena+688>, 0x7ff7fade70 <main_arena+688>, 0x7ff7fade80 <main_arena+704>, 0x7ff7fade80 <main_arena+704>, 0x7ff7fade90 <main_arena+720>, 0x7ff7fade90 <main_arena+720>, 0x7ff7fadea0 <main_arena+736>, 0x7ff7fadea0 <main_arena+736>, 0x7ff7fadeb0 <main_arena+752>, 0x7ff7fadeb0 <main_arena+752>, 0x7ff7fadec0 <main_arena+768>, 0x7ff7fadec0 <main_arena+768>, 0x7ff7faded0 <main_arena+784>, 0x7ff7faded0 <main_arena+784>, 0x7ff7fadee0 <main_arena+800>, 0x7ff7fadee0 <main_arena+800>, 0x7ff7fadef0 <main_arena+816>, 0x7ff7fadef0 <main_arena+816>, 0x7ff7fae000 <main_arena+832>, 0x7ff7fae000 <main_arena+832>, 0x7ff7fae010 <main_arena+848>, 0x7ff7fae010 <main_arena+848>, 0x7ff7fae020 <main_arena+864>, 0x7ff7fae020 <main_arena+864>, 0x7ff7fae030 <main_arena+880>, 0x7ff7fae030 <main_arena+880>, 0x7ff7fae040 <main_arena+896>, 0x7ff7fae040 <main_arena+896>, 0x7ff7fae050 <main_arena+912>, 0x7ff7fae050 <main_arena+912>, 0x7ff7fae060 <main_arena+928>, 0x7ff7fae060 <main_arena+928>, 0x7ff7fae070 <main_arena+944>, 0x7ff7fae070 <main_arena+944>, 0x7ff7fae080 <main_arena+960>, 0x7ff7fae080 <main_arena+960>, 0x7ff7fae090 <main_arena+976>, 0x7ff7fae090 <main_arena+976>, 0x7ff7fae0a0 <main_arena+992>, 0x7ff7fae0a0 <main_arena+992>, 0x7ff7fae0b0 <main_arena+1008>, 0x7ff7fae0b0 <main_arena+1008>, 0x7ff7fae0c0 <main_arena+1024>, 0x7ff7fae0c0 <main_arena+1024>, 0x7ff7fae0d0 <main_arena+1056>, 0x7ff7fae0d0 <main_arena+1056>, 0x7ff7fae0e0 <main_arena+1072>, 0x7ff7fae0e0 <main_arena+1072>, 0x7ff7fae0f0 <main_arena+1088>, 0x7ff7fae0f0 <main_arena+1088>, 0x7ff7fae100 <main_arena+1104>, 0x7ff7fae100 <main_arena+1104>, 0x7ff7fae110 <main_arena+1120>, 0x7ff7fae110 <main_arena+1120>, 0x7ff7fae120 <main_arena+1136>, 0x7ff7fae120 <main_arena+1136>, 0x7ff7fae130 <main_arena+1152>, 0x7ff7fae130 <main_arena+1152>, 0x7ff7fae140 <main_arena+1168>, 0x7ff7fae140 <main_arena+1168>, 0x7ff7fae150 <main_arena+1184>, 0x7ff7fae150 <main_arena+1184>, 0x7ff7fae160 <main_arena+1200>, 0x7ff7fae160 <main_arena+1200>, 0x7ff7fae170 <main_arena+1216>, 0x7ff7fae170 <main_arena+1216>, 0x7ff7fae180 <main_arena+1232>, 0x7ff7fae180 <main_arena+1232>, 0x7ff7fae190 <main_arena+1248>, 0x7ff7fae190 <main_arena+1248>, 0x7ff7fae1a0 <main_arena+1264>, 0x7ff7fae1a0 <main_arena+1264>, 0x7ff7fae1b0 <main_arena+1280>, 0x7ff7fae1b0 <main_arena+1280>, 0x7ff7fae1c0 <main_arena+1296>, 0x7ff7fae1c0 <main_arena+1296>, 0x7ff7fae1d0 <main_arena+1312>, 0x7ff7fae1d0 <main_arena+1312>, 0x7ff7fae1e0 <main_arena+1328>, 0x7ff7fae1e0 <main_arena+1328>, 0x7ff7fae1f0 <main_arena+1344>, 0x7ff7fae1f0 <main_arena+1344>, 0x7ff7fae200 <main_arena+1360>, 0x7ff7fae200 <main_arena+1360>, 0x7ff7fae210 <main_arena+1376>, 0x7ff7fae210 <main_arena+1376>, 0x7ff7fae220 <main_arena+1392>, 0x7ff7fae220 <main_arena+1392>, 0x7ff7fae230 <main_arena+1408>, 0x7ff7fae230 <main_arena+1408>, 0x7ff7fae240 <main_arena+1424>, 0x7ff7fae240 <main_arena+1424>, 0x7ff7fae250 <main_arena+1440>, 0x7ff7fae250 <main_arena+1440>, 0x7ff7fae260 <main_arena+1456>, 0x7ff7fae260 <main_arena+1456>, 0x7ff7fae270 <main_arena+1472>, 0x7ff7fae270 <main_arena+1472>, 0x7ff7fae280 <main_arena+1488>, 0x7ff7fae280 <main_arena+1488>, 0x7ff7fae290 <main_arena+1504>, 0x7ff7fae290 <main_arena+1504>, 0x7ff7fae2a0 <main_arena+1520>, 0x7ff7fae2a0 <main_arena+1520>, 0x7ff7fae2b0 <main_arena+1536>, 0x7ff7fae2b0 <main_arena+1536>, 0x7ff7fae2c0 <main_arena+1552>, 0x7ff7fae2c0 <main_arena+1552>, 0x7ff7fae2d0 <main_arena+1568>, 0x7ff7fae2d0 <main_arena+1568>, 0x7ff7fae2e0 <main_arena+1584>, 0x7ff7fae2e0 <main_arena+1584>, 0x7ff7fae2f0 <main_arena+1600>, 0x7ff7fae2f0 <main_arena+1600>, 0x7ff7fae300 <main_arena+1616>, 0x7ff7fae300 <main_arena+1616>, 0x7ff7fae310 <main_arena+1632>, 0x7ff7fae310 <main_arena+1632>, 0x7ff7fae320 <main_arena+1648>, 0x7ff7fae320 <main_arena+1648>, 0x7ff7fae330 <main_arena+1664>, 0x7ff7fae330 <main_arena+1664>, 0x7ff7fae340 <main_arena+1680>, 0x7ff7fae340 <main_arena+1680>...},
binmap = {0, 0, 0, 0},
next = 0x7ff7fada60 <main_arena>,
next_free = 0x0,
attached_threads = 1,
system_mem = 135168,
max_system_mem = 135168
}
Viewing Heap
Since you can view the arena, you can also view the program’s heap, as shown below:
pwndbg> heap
Allocated chunk | PREV_INUSE
Addr: 0x412000
Size: 0x290 (with flag bits: 0x291)
Allocated chunk | PREV_INUSE
Addr: 0x412290
Size: 0x70 (with flag bits: 0x71)
Top chunk | IS_MMAPED | NON_MAIN_ARENA
Addr: 0x412300
Size: 0x20068 (with flag bits: 0x2006e)
Viewing Bins
Since you can view the heap, you can also view the bins inside malloc.
pwndbg> bins cache
tcachebins
empty
fastbins
0x20: 0x4132d0 —▸ 0x414578 —▸ 0x4145b8 ◂— 0x31/* '1' */
0x30: 0x413938 ◂— 0x411
0x40: 0x4145e8 ◂— 0x1fa11
0x50: 0x651
0x60: 0x414098 —▸ 0x4140d8 ◂— 0x31/* '1' */
0x70: 0x4142a8 —▸ 0x4142e8 ◂— 0x31/* '1' */
0x80: 0x414578 —▸ 0x4145b8 ◂— 0x31/* '1' */
0x90: 0x414578 —▸ 0x4145b8 ◂— 0x31/* '1' */
0xa0: 0x414368 —▸ 0x4143a8 ◂— 0x31/* '1' */
0xb0: 0x414368 —▸ 0x4143a8 ◂— 0x31/* '1' */
unsortedbin
all [corrupted]
FD: 0x413e88 —▸ 0x413ec8 ◂— 0x31/* '1' */
BK: 0x4144b8 —▸ 0x414498 ◂— 0x4c320000dd80
smallbins
0x20 [corrupted]
FD: 0x414398 —▸ 0x4143d8 ◂— 0x31/* '1' */
BK: 0x414398 —▸ 0x414378 ◂— 0x24ff000076c5
0x30 [corrupted]
FD: 0x413330 —▸ 0x413340 —▸ 0x413eb8 —▸ 0x413ef8 ◂— 0x31/* '1' */
BK: 0x413330 —▸ 0x413340 —▸ 0x413eb8 —▸ 0x413e98 ◂— 0x989b00002650/* 'P&' */
Viewing Mappings
Similarly, GDB’s mappings have been optimized for better usability, as shown below:
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
Start End Perm Size Offset File
0x400000 0x401000 r-xp 1000 0 /root/malloc
0x410000 0x411000 r--p 1000 0 /root/malloc
0x411000 0x412000 rw-p 1000 1000 /root/malloc
0x412000 0x433000 rw-p 21000 0 [heap]
0x7ff7e40000 0x7ff7f9a000 r-xp 15a000 0 /usr/lib/aarch64-linux-gnu/libc-2.31.so
0x7ff7f9a000 0x7ff7fa9000 ---p f000 15a000 /usr/lib/aarch64-linux-gnu/libc-2.31.so
0x7ff7fa9000 0x7ff7fad000 r--p 4000159000 /usr/lib/aarch64-linux-gnu/libc-2.31.so
0x7ff7fad000 0x7ff7faf000 rw-p 200015d000 /usr/lib/aarch64-linux-gnu/libc-2.31.so
0x7ff7faf000 0x7ff7fb2000 rw-p 3000 0 [anon_7ff7faf]
0x7ff7fcc000 0x7ff7fed000 r-xp 21000 0 /usr/lib/aarch64-linux-gnu/ld-2.31.so
0x7ff7ff8000 0x7ff7ffa000 rw-p 2000 0 [anon_7ff7ff8]
0x7ff7ffa000 0x7ff7ffc000 r--p 2000 0 [vvar]
0x7ff7ffc000 0x7ff7ffd000 r-xp 1000 0 [vdso]
0x7ff7ffd000 0x7ff7ffe000 r--p 1000210000 /usr/lib/aarch64-linux-gnu/ld-2.31.so
0x7ff7ffe000 0x7ff8000000 rw-p 200022000 /usr/lib/aarch64-linux-gnu/ld-2.31.so
0x7ffffdf000 0x8000000000 rw-p 21000 0 [stack]
Parsing Memory Addresses
You can use xinfo to parse the information stored in memory, as shown below:
pwndbg> xinfo p
Extended information for virtual address 0x4122a0:
Containing mapping:
0x412000 0x433000 rw-p 21000 0 [heap]
Offset information:
Mapped Area 0x4122a0 = 0x412000 + 0x2a0
More Commands
Pwndbg is very powerful, but I often use it when debugging memory, focusing more on memory applications. The commands mentioned above fully meet my needs, and for more usage, you can refer to:
https://pwndbg.re/pwndbg/latest/commands/