编辑
2025-09-05
记录知识
0

目录

telescope打印链表的条件
实践
如何打印next
总结

通常调试问题的时候,经常会遇到链表,而gdb调试链表的手动计算和填入,非常麻烦。但是pwndbg提供了一个非常好的命令telescope会帮我们自动解析链表。

telescope打印链表的条件

编程者在设计链表的时候结构各种各样,所以并不是每一种链表都是能够轻松打印的,但是一种简单的方式可以打印链表,那就是无限取值。下面介绍一下。

假设0xaaa地址的值是0xbbb,那么取到0xbbb之后,再读0xbbb的值0xccc,然后再读0xccc的值0xddd,依此类推。

这就是无限取值,它和打印链表有什么关系呢。

一个常用的双向链表如下

pwndbg> ptype list type = struct list_head { struct list_head *prev; struct list_head *next; } *

我们打印一下偏移值,如下

pwndbg> ptype /o list type = struct list_head { /* 0 | 8 */ struct list_head *prev; /* 8 | 8 */ struct list_head *next; /* total size (bytes): 16 */ } *

可以看到,list_head的prev永远是list_head的取值,也就意味着对list_head的无限取值就是获取list_head的prev链表的遍历。

实践

首先需要一个体现双向链表的示例代码,可以以之前写的lru算法为例

git clone https://github.com/tangfeng-648/lru.git

直接调试

gdb ./lru

为了方便调试,这里直接在list_add加上断点

pwndbg> b list_add Breakpoint 1 at 0x400814: file list.h, line 24.

此时断点触发情况如下

22 static inline void list_add(struct list_head *item, struct list_head *list) 23 { ► 24 item->prev = list; 25 item->next = list->next; 26 list->next->prev = item; 27 list->next = item; 28 }

利用list可以打印这个list_head,如下

pwndbg> telescope list 1 00:0000│ x1 0x4132b8 —▸ 0x413e38 —▸ 0x413e68 —▸ 0x413e98 —▸ 0x413ec8 ◂— ... pwndbg> telescope 0x413ec8 1 00:0000│ 0x413ec8 —▸ 0x413ef8 —▸ 0x413f28 —▸ 0x413f58 —▸ 0x413f88 ◂— ...

因为list_head的偏移0是struct list_head *prev,所以telescope实际上是对这个list的逆序查找。

下面验证一下是否正确,如下

pwndbg> p list $1 = (struct list_head *) 0x4132b8 pwndbg> p list->prev $2 = (struct list_head *) 0x413e38 pwndbg> p list->prev->prev $3 = (struct list_head *) 0x413e68 pwndbg> p list->prev->prev->prev $4 = (struct list_head *) 0x413e98 pwndbg> p list->prev->prev->prev->prev $5 = (struct list_head *) 0x413ec8 pwndbg> p list->prev->prev->prev->prev->prev $6 = (struct list_head *) 0x413ef8 pwndbg> p list->prev->prev->prev->prev->prev->prev $7 = (struct list_head *) 0x413f28 pwndbg> p list->prev->prev->prev->prev->prev->prev->prev $8 = (struct list_head *) 0x413f58 pwndbg> p list->prev->prev->prev->prev->prev->prev->prev->prev $9 = (struct list_head *) 0x413f88

可以看到,telescope相当于隐式的帮我们打印了这个链表。

如何打印next

实际上因为next相比于prev每次都要加上8的偏移,默认情况下pwndbg没有提供这样的命令,只能自行手动计算。

总结

本文分享了一个简单的方法来打印链表,实际上,是否能够打印链表,取决于自己对内存布局是否熟悉,如果很熟悉的情况下,可以借助这个命令简化自己的计算,如果不熟悉的情况下,建议还是手动计算吧。否则telescope给你的信息并不一定对你有用。