news 2026/4/22 13:10:09

保姆级调试指南:用GDB+Pwndbg实战分析CTF Pwn堆题的第一个malloc与free

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
保姆级调试指南:用GDB+Pwndbg实战分析CTF Pwn堆题的第一个malloc与free

保姆级调试指南:用GDB+Pwndbg实战分析CTF Pwn堆题的第一个malloc与free

堆漏洞利用一直是CTF Pwn题中的难点与重点。许多初学者虽然掌握了堆管理的基本理论,但在实际调试时却无从下手——他们知道chunk应该长什么样,却不知道如何在内存中定位它;了解bins的工作原理,却不会在调试器中观察它们的实际状态。本文将带你用GDB+Pwndbg插件,从零开始跟踪一次完整的malloc(0x20)和free操作,用实战视角观察堆内存的微观变化。

1. 实验环境搭建与基础准备

在开始调试前,我们需要一个可复现的实验环境。创建一个简单的测试程序heap_test.c

#include <stdlib.h> int main() { void *p1 = malloc(0x20); free(p1); return 0; }

编译时务必添加调试信息并关闭ASLR(地址空间随机化)以便观察:

gcc -g -no-pie -o heap_test heap_test.c echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

启动GDB并加载Pwndbg插件:

gdb ./heap_test

Pwndbg会自动加载并显示其特色的彩色界面。如果尚未安装,可以通过以下命令获取:

pip install pwndbg

提示:调试堆问题时,建议始终在malloc调用前设置断点,而非在main函数开始时就查看堆状态。未初始化的堆内存往往包含随机数据,容易造成误解。

2. 初始堆状态分析

在GDB中运行start命令让程序暂停在main函数入口。此时堆尚未初始化,我们可以先观察几个关键地址:

pwndbg> heap Arena not found. Maybe the binary is not dynamically linked or the memory layout is unusual.

这个输出表明堆尚未初始化。通过vmmap命令查看内存布局:

pwndbg> vmmap LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA 0x555555554000 0x555555555000 r-xp 1000 0 /home/user/heap_test 0x555555754000 0x555555755000 r--p 1000 0 /home/user/heap_test 0x555555755000 0x555555756000 rw-p 1000 1000 /home/user/heap_test 0x7ffff7dd5000 0x7ffff7dfc000 r-xp 27000 0 /lib/x86_64-linux-gnu/ld-2.31.so ...

可以看到此时还没有堆段(HEAP)。接下来我们在malloc调用前设置断点:

pwndbg> break *main+14 # 假设malloc调用在main+14 pwndbg> continue

3. 第一次malloc(0x20)的详细跟踪

当程序停在malloc调用前时,我们单步执行(si)进入malloc函数内部。Pwndbg会自动高亮显示当前执行的汇编指令。继续执行直到完成malloc返回:

pwndbg> finish

现在再次检查堆状态:

pwndbg> heap Top chunk | PREV_INUSE Addr: 0x555555756000 Size: 0x21000 pwndbg> arenas [ Main arena ]

可以看到堆已经初始化,顶部chunk大小为0x21000。查看我们分配的0x20字节chunk:

pwndbg> x/4gx 0x555555756000 0x555555756000: 0x0000000000000000 0x0000000000000031 0x555555756010: 0x0000000000000000 0x0000000000000000

关键观察点:

  • 第一个qword(0x0000000000000000)是prev_size字段
  • 第二个qword(0x0000000000000031)是size字段,其中:
    • 低三位0x1表示PREV_INUSE标志位
    • 实际大小是0x30(包含头部),因为0x20用户请求+0x10头部=0x30

使用Pwndbg的vis_heap_chunks命令可以更直观地查看:

pwndbg> vis_heap_chunks 0x555555756000 0x0000000000000000 0x0000000000000031 ........1....... 0x555555756010 0x0000000000000000 0x0000000000000000 ................ 0x555555756020 0x0000000000000000 0x0000000000000000 ................ 0x555555756030 0x0000000000000000 0x0000000000020fd1 ................

4. free操作后的堆状态变化

继续执行到free调用并完成:

pwndbg> break *main+28 # 假设free调用在main+28 pwndbg> continue pwndbg> finish

现在观察free后的变化:

pwndbg> vis_heap_chunks 0x555555756000 0x0000000000000000 0x0000000000000031 ........1....... 0x555555756010 0x0000000000000000 0x0000000000000000 ................ 0x555555756020 0x0000000000000000 0x0000000000000000 ................ 0x555555756030 0x0000000000000000 0x0000000000020fd1 ................

表面看起来似乎没变化?这是因为小chunk被放入了fastbin。检查fastbins:

pwndbg> fastbins fastbins [0x20] 0x555555756000 -> 0x0 [0x30] 0x0 [0x40] 0x0 ...

可以看到我们的chunk(0x555555756000)被链入了0x20大小的fastbin。虽然vis_heap_chunks显示没变,但实际chunk内部已经存储了fastbin的链表指针:

pwndbg> x/4gx 0x555555756000 0x555555756000: 0x0000000000000000 0x0000000000000031 0x555555756010: 0x0000000000000000 0x0000000000000000

这里似乎没有看到指针?这是因为fastbin是单链表,且当前只有一个chunk,所以fd指针为NULL。如果我们再分配并释放一个0x20的chunk,就能看到链表形成:

void *p1 = malloc(0x20); void *p2 = malloc(0x20); free(p1); free(p2);

调试时可以看到:

pwndbg> fastbins fastbins [0x20] 0x555555756040 -> 0x555555756000 -> 0x0

5. 关键调试技巧与常见误区

在实际调试堆问题时,有几个关键技巧和常见误区需要注意:

  1. 内存对齐观察

    • 64位系统下chunk大小总是16字节对齐
    • 使用p/x ((size_t)ptr & ~0xF)可以快速计算chunk头地址
  2. 标志位解读

    # Pwndbg中的size解析 def parse_size(size): return size & ~0x7, size & 0x7
  3. 常见调试误区

    • 忘记在malloc/free后查看状态
    • 误读size字段(忘记包含头部大小)
    • 忽略fastbin的LIFO特性
    • 在多线程环境下未注意arena变化
  4. 实用Pwndbg命令

    heap -v # 详细堆信息 bins # 查看所有bins parseheap # 解析堆布局 telescope [addr] # 查看内存内容

6. 进阶:从调试到漏洞利用

理解了基础的内存分配与释放后,我们可以进一步探索如何利用堆漏洞。以简单的Use-after-Free为例:

void *p = malloc(0x20); free(p); malloc(0x20); // 可能重新获得p指向的内存

调试时可以观察到:

# 第一次malloc后 pwndbg> p p $1 = (void *) 0x555555756010 # free后 pwndbg> fastbins [0x20] 0x555555756000 -> 0x0 # 第二次malloc后 pwndbg> p p2 $2 = (void *) 0x555555756010 # 与p相同

这种内存重用特性是许多堆漏洞利用的基础。通过GDB+Pwndbg的实时观察,可以更直观地理解攻击者如何操纵堆内存布局来实现任意地址读写等操作。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/22 13:10:04

Windows系统激活终极指南:3分钟免费一键激活完整教程

Windows系统激活终极指南&#xff1a;3分钟免费一键激活完整教程 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 还在为Windows激活问题烦恼吗&#xff1f;KMS_VL_ALL_AIO智能激活脚本为您提供免…

作者头像 李华
网站建设 2026/4/22 13:08:17

JSXBIN反编译终极指南:Jsxer如何解密Adobe脚本的加密屏障

JSXBIN反编译终极指南&#xff1a;Jsxer如何解密Adobe脚本的加密屏障 【免费下载链接】jsxer A fast and accurate JSXBIN decompiler. 项目地址: https://gitcode.com/gh_mirrors/js/jsxer 当你面对一个加密的Adobe ExtendScript二进制文件&#xff08;JSXBIN&#xff…

作者头像 李华
网站建设 2026/4/22 13:06:43

3分钟极速获取:百度网盘提取码智能解析工具终极指南

3分钟极速获取&#xff1a;百度网盘提取码智能解析工具终极指南 【免费下载链接】baidupankey 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 还在为百度网盘分享链接的提取码而四处搜索吗&#xff1f;每次遇到心仪的学习资料、实用软件或精彩影音&#xf…

作者头像 李华
网站建设 2026/4/22 13:06:42

VSCode玩转STC15:Keil工程无缝迁移指南与Keil Assistant new插件深度体验

VSCode高效开发STC15&#xff1a;Keil工程迁移与智能插件实战 1. 开发环境迁移的必要性 对于长期使用Keil进行STC15系列单片机开发的工程师来说&#xff0c;传统开发环境存在几个明显痛点&#xff1a;臃肿的IDE界面、有限的代码管理功能、缺乏现代化的智能提示。而VSCode作为轻…

作者头像 李华