pwndbg arenas 命令详解:在 GDB/LLDB 中枚举 glibc ptmalloc2 全部分配区(Arena)
2026/9/15 21:57:04 网站建设 项目流程

pwndbg arenas 命令详解:在 GDB/LLDB 中枚举 glibc ptmalloc2 全部分配区(Arena)

【免费下载链接】pwndbgExploit Development and Reverse Engineering with GDB & LLDB Made Easy项目地址: https://gitcode.com/GitHub_Trending/pw/pwndbg

导读

本文聚焦 pwndbg 的arenas命令——一条用于**枚举当前进程中 glibc ptmalloc2 全部内存分配区(malloc arena)**的调试命令。在漏洞利用(exploit development)与逆向工程中,多线程程序的堆布局远比单线程复杂:每个 arena 各自维护独立的 bins、fastbins 与 top chunk,而arenas命令能帮你一眼看清进程内到底存在哪些 arena、每个 arena 归属哪个堆映射。读完本文,你将掌握arenas与配套的arena命令的用法、输出字段含义,以及 pwndbg 从符号与启发式两条路径解析 arena 链表的底层原理。

arenas命令:快速定位进程内全部分配区

用法与参数

arenas是 pwndbg 内置的 glibc 堆调试命令之一,用法极其简洁:

usage: arenas [-h]

不接收任何位置参数,唯一的可选项是标准的帮助参数:

ShortLongHelp
-h--helpshow this help message and exit

命令的官方描述只有一句话:"List this process's arenas."(列出当前进程的所有分配区)。命令入口定义在 pwndbg/commands/glibc_malloc.py,通过@pwndbg.commands.Command(parser, category=CommandCategory.GLIBC_MALLOC)注册到GLIBC_MALLOC命令分类,并带有@OnlyForSaneHeap装饰器——这意味着当目标进程的堆状态异常(无法构建堆对象)时,命令会安全退出而不是崩溃。

适用前提arenas针对 glibc 的 ptmalloc2 分配器实现,适用于动态链接了标准 glibc 的目标进程。若目标使用 jemalloc、musl 或 mallocng 等其他分配器,arenas不会列出其内部结构(这些分配器由 pwndbg 的jemallocmuslmallocng等命令族负责)。

命令调用链

在 GDB 或 LLDB 会话中,当程序运行到断点处时直接执行:

pwndbg> arenas

命令内部的核心逻辑是:

allocator = pwndbg.aglib.heap.glibc.get_allocator() arenas = allocator.arenas

即通过get_allocator()获取当前进程对应的 glibc 分配器实例(详见 pwndbg/aglib/heap/glibc.py),再由分配器的arenas属性取得全部 arena 列表。

输出格式与字段解读

arenas的输出是一张右对齐的表格,表头包含 9 个字段:

arena type arena address heap address map start map end perm size offset file
字段含义
arena typemain_arena(主分配区)或non-main arena(非主分配区)
arena addressmalloc_state结构体在内存中的地址
heap address该 arena 关联的堆段起始地址
map start / map end堆内存映射区间的起止地址
perm映射区权限(如rw-p
size映射区间大小
offset映射相对文件偏移
file映射来源文件

关键实现细节(见 pwndbg/commands/glibc_malloc.py):

  • arena type 着色区分:主分配区main_arena用成功色(绿色)标注,非主分配区non-main arena用提示色(黄色)标注,便于一眼区分。
  • heap 地址取第一个堆段first_heap = arena.heaps[0],展示该 arena 的heaps列表中的第一个堆段起始地址。
  • vmmap 信息联查pwndbg.aglib.vmmap.find(first_heap.start)会去查询该堆地址所属的内存映射,返回的映射文本按空格拆分后逐列填入map start / map end / perm / size / offset / file,与 pwndbg 的vmmap命令共用同一套映射信息。
  • 多堆段折叠展示:如果一个非主 arena 拥有多个堆段(例如堆通过mmap扩展出第二个 segment),则后续堆段以空 arena type 单元格加 Unicode 箭头的子行展示,箭头指示该堆段归属于上方同一 arena。

这一输出设计让你在多线程 + 堆溢出场景中,能快速判断:当前进程有几个分配区、哪个是主 arena、各 arena 的堆在哪里、堆映射的权限与大小是否异常(例如权限位被篡改、堆越界扩展)。

arena命令的分工:看单个 vs 看全部

arenas展示全局,而配套命令arena展示单个分配区的完整内部状态,两者共同构成 arena 调试的完整闭环。

arena的用法为:

usage: arena [-h] [addr]
  • 不带参数时,默认打印当前线程所属的 arena,并先输出提示信息:
Arena for thread <tid> is located at: 0x7ffff7fa2c80
  • 带地址参数时,直接打印该地址处malloc_state结构体的完整内容:
pwndbg> arena 0x7ffff7fa2c80

其完整字段输出包括mutexflagshave_fastchunksfastbinsYtopbinsbinmapnextnext_freesystem_mem等 glibcmalloc_state的全部字段(字段解析见 pwndbg/aglib/heap/glibc.py 的Arena类)。

两者的典型配合用法:

  1. 先用arenas看到进程内全部 arena 及其堆位置;
  2. 再用arena <address>深入某个目标分配区,检查其fastbinsY/bins/top/system_mem等内部状态;
  3. 结合 vis-heap-chunks.md、bins.md、top-chunk.md 等命令完成堆布局的进一步可视化。

底层原理:pwndbg 如何枚举全部 arena

arenas命令只是视图层,真正的枚举逻辑位于分配器的arenas属性(pwndbg/aglib/heap/glibc.py):

@property @pwndbg.lib.cache.cache_until("stop") def arenas(self) -> tuple[Arena, ...]: """Return a tuple of all current arenas.""" arenas: list[Arena] = [] main_arena = self.main_arena if main_arena: arenas.append(main_arena) arena = main_arena addr = arena.next while addr is not None and addr != main_arena.address: arena = Arena(addr) arenas.append(arena) addr = arena.next self._arenas = tuple(arenas) return self._arenas

枚举算法清晰地复刻了 glibc 的 arena 链表结构:

  1. 先取main_arena:主分配区是链表头;
  2. 沿next指针遍历:glibc 中每个非主 arena 的malloc_state.next指向下一个 arena,直到回到main_arena自身(环形链表);
  3. 缓存到 "stop" 事件@pwndbg.lib.cache.cache_until("stop")表示结果缓存在程序停止(stop)事件上,程序继续运行后缓存自动失效,避免陈旧堆信息。

两条解析路径:DebugSymsHeap 与 HeuristicHeap

pwndbg 的 glibc 分配器分为两种实现,main_arenathread_arena的解析方式也因此不同:

路径一:DebugSymsHeap(libc 带调试符号)

当 libc 带有调试符号时(pwndbg.libc.has_debug_info()为真),直接通过符号表定位:

@property def main_arena(self) -> Arena | None: self._main_arena_addr = pwndbg.aglib.symbol.lookup_symbol_addr( "main_arena", prefer_static=True ) ... return self._main_arena

即从符号main_arena得到其地址(prefer_static=True优先取静态符号,避免被 GOT/PLT 干扰),再以该地址构建Arena对象。thread_arena同理,通过thread_arena符号读取指针值(可能为 NULL,表示该线程尚未分配任何内存,见 pwndbg/aglib/heap/glibc.py)。

路径二:HeuristicHeap(无调试符号,启发式)

当 libc 没有调试符号但能确定版本时,pwndbg 使用运行时生成的 C 结构体(glibc_structs)做启发式解析。main_arena的定位策略是:

  • 优先用符号main_arena(静态链接或已 unstrip 的场景);
  • 找不到符号时,在.data段中按 glibc 默认main_arena的初始化模式做模式匹配——glibc 中main_arena初始为{ .mutex = _LIBC_LOCK_INITIALIZER, .next = &main_arena, .attached_threads = 1 },pwndbg 按此特征(next自指 +attached_threads = 1)在数据段中搜索匹配的malloc_state结构(见 pwndbg/aglib/heap/glibc.py)。

此外,Arena.is_main_arena的判断也很直接:self.address == _allocator.main_arena.address(pwndbg/aglib/heap/glibc.py),这与命令输出中arena type列的着色逻辑一一对应。

多堆段的heaps组织

Arena.heaps(pwndbg/aglib/heap/glibc.py)负责收集一个 arena 关联的全部堆段:

  • 主 arena 优先用 sbrk 堆区(get_sbrk_heap_region()),若top不在 sbrk 区域内则额外补一个堆段;
  • 非主 arena 沿Heap.prev指针向前回溯,把各历史 mmap 堆段全部收进列表;
  • 列表最后反转,保证堆段按地址/时间顺序排列,heaps[0]即最早建立的堆段。

这解释了arenas输出中第一行取arena.heaps[0]、后续堆段用子行展示的行为。

实战场景与使用建议

场景一:多线程程序堆布局侦察

对一个多线程二进制,程序运行一段时间后执行:

pwndbg> arenas

如果看到多个non-main arena行,说明进程已为多个线程创建了独立分配区(glibc 默认 arena 数量上限约为核数的 8 倍)。此时配合thread apply all bt可把"哪些线程持有哪些 arena"对应起来,定位堆风水(heap feng shui)布局的目标 arena。

场景二:堆溢出后定位被破坏的 arena

在堆利用(如 fastbin attack、unsorted bin attack)中,常需要篡改某个 arena 的topbinsfastbinsY。先arenas拿到目标 arena 地址,再arena <addr>查看字段,最后用 xinfo 或 search 反向验证篡改效果。

场景三:堆映射权限检查

arenas输出的perm列直接来自 vmmap 映射信息。若发现堆段权限异常(如堆被 mprotect 成r-x),可快速定位是哪一段堆映射被改,再结合 vmmap 的详细映射列表交叉验证。

注意事项

  • arenas依赖@OnlyForSaneHeap,当堆结构损坏到无法构建堆对象时命令会静默返回,此时应先修复堆状态或用heap命令诊断(见 heap.md);
  • 结果缓存在 stop 事件上:若你在一次停止中反复调用malloc(例如通过gdb.execute('call malloc(...)')执行 inferior call),堆可能因brk/mmap扩展而超出缓存的内存映射范围。pwndbg 已通过监听inferior_call事件在 inferior 函数调用完成后清理 stop 缓存来解决此问题,对应回归测试见 tests/library/gdb/tests/heap/test_inferior_call_cache.py(该测试正是验证thread_arena在多次 inferiormalloc后仍可访问);
  • arenas列出的是 arena 的malloc_state结构,而非单个 chunk;chunk 级视图请使用 malloc-chunk.md 与 vis-heap-chunks.md。

小结

arenas命令以一张 9 列表格,把 glibc ptmalloc2 中散落在各处的 arena 及其堆映射汇总到眼前,是分析多线程堆布局的第一站。其背后是对 glibc arena 环形链表、malloc_state结构、vmmap 映射信息的系统解析,并同时支持带调试符号的DebugSymsHeap路径与无符号的HeuristicHeap启发式路径。配合单分配区查看命令arena(见 arena.md)以及 bins.md、fastbins.md、unsortedbin.md 等命令,即可在 GDB/LLDB 中完成从"进程有几个堆分配区"到"某个 bins 里挂着哪些 chunk"的全链路堆调试。

【免费下载链接】pwndbgExploit Development and Reverse Engineering with GDB & LLDB Made Easy项目地址: https://gitcode.com/GitHub_Trending/pw/pwndbg

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询