堆基础


brk

系统调用

将进程的堆结束地址(prgram break)设置为指定的值,从而控制堆内存的大小。
可以扩展或收缩堆内存

1
2
#include <unistd.h>
int brk(void *addr);

addr:
指定新的堆结束地址

成功时,返回0
失败时,返回-1,设置errno为以下之一:

  • ENOMEN 内存不足,无法扩展到指定的地址
  • EINVAL 指定的地址无效

sbrk

Unix/Linux系统中的一个系统调用

通过增加或减少进程的堆结束地址(Program break)来分配或释放内存。

1
2
#include <unistd.h>
void *sbrk(intptr_t increment);

increment:堆内存的调整量,以字节为单位。可为正数、负数或零

  • 正值:增加堆的大小,向系统申请更多内存空间
  • 负值:减少堆的大小,释放之前分配的内存
  • 零:不改变堆的大小,此时函数返回当前堆的结束地址
    返回值:
  • 成功时,
    • 如果increment是负数,返回调整前堆顶地址
    • 如果increment是正值,则返回值指向新分配内存的堆顶地址
    • 如果increment是0,返回当前堆的结束地址(program break)
  • 失败时,返回(void *)-1,并设置errnoENOMEM,表示没有足够的内存

getpid

系统调用

返回当前进程的PID



常用调试命令
heap
vmmap
vis_heap_chunks
top_chunk
bin
arenas
arena

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
find_fake_fast <addr>
# 查找与addr重叠的候选假fast或tcache块

malloc_chunk <addr>
# 打印指定地址的chunk

heap_config
# 显示与堆相关的配置

try_free <addr>
# 检查用地址调用free会发生什么

mp
# 打印mp_结构的内容

tcache
# 打印线程的tcache内容

tcache

glibc从2.26版本开始引入的一种内存管理机制,旨在提高内存分配的性能。

tcache(thread cache)是一种线程本地缓存机制,每个线程都有自己的tcache结构,它类似于fastbin,但是优先级上高于fastbin

减少线程之间的互斥 和 锁的竞争

当程序进行malloc操作时,会优先检查tcache是否有可用的chunk,如果有,就直接返回;
当进行free操作时,如果chunk的大小符合要求,并且对应的tcache bin还未满(默认每个bin可以存放7个chunk),就会把chunk放入tcache。


了解堆

Top chunk:程序第一次进行malloc的时候,heap会被分为两块,一块给用户,剩下的那块就是top chunk,再次申请堆块要是没合适的空间便会使用top chunk的空间
你申请到的一块堆内存的起始地址 $\neq$ 你可以写入数据的起始地址,因为堆块头部会记录一些信息,在64位条件下会有0x10大小的差距
你申请的大小 $\neq$ 实际申请的大小,他会有一个取整的步骤


一般使用free()函数释放的堆块不会立刻被回收,它们会变成一种叫free chunk的东西并且加上了一种类似xxx bin的名字,一般这类堆块释放后如果挨着一个也被释放的堆块或者是top chunk会合并
fast bin是一个特例 – 它不会轻易合并


1
2
3
4
5
6
7
void* malloc(size_t size);

void* calloc(size_t n, size_t size)
# 和malloc的重要区别是会清0堆块中的内容

void* realloc(void* ptr, size_t size)
# 结合了mallocfree的功能 但是释放内存和free有所区别

Arena

在glibc的内存管理机制中,arena(分配区)是ptmalloc(glibc所用的内存分配器)用于管理进程内存的核心结构之一

它通过减少线程间的锁竞争来提升多线程环境下内存分配的性能

类型

  • 主分配区(main arena):只能由第一个线程创建和持有,可以使用sbrkmmap向操作系统申请内存
  • 非主分配区(Non-main Arena):由其它线程创建,只能通过mmap向操作系统申请内存

查看系统libc版本号

1
ldd --version

64位
以 0x10 <= userdata < 0x20为例
userdata: <= 0x18 共分配0x20
userdata: > 0x18 共分配0x30

这样分配和chunk间复用和size、PRE_INUSE字段有关


各ubunut版本常用的libc版本
Ubuntu18.04 2.27

更改pwn题libc

2.35的堆io


堆基础
http://example.com/2025/03/19/堆基础/
作者
yvyvSunlight
发布于
2025年3月19日
许可协议