64位
目录
源码
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
sleep(0,1);
char *s0=malloc(0x10);
sleep(0,1);
char *s01=malloc(0x10);
sleep(0,1);
char *s02=malloc(0x10);
sleep(0,1);
char *s03=malloc(0x10);
sleep(0,1);
char *s1=malloc(0x100);
sleep(0,1);
char *s2=malloc(0x500);
sleep(0,1);
char *s3=malloc(0x1000);
sleep(0,1);
free(s0);
sleep(0,1);
free(s01);
sleep(0,1);
free(s02);
sleep(0,1);
free(s03);
sleep(0,1);
free(s2);
printf("OK exit");
return 0;
}//这里加sleep是因为直接b malloc不知道为什么不行,所以加sleep靠sleep来下断点2
gcc test.c
pwndbg调试堆
b sleep # 先下断点,再run
此时程序断在第一个malloc前,heap看一下堆,堆还没有初始化
vmmap看一下内存空间,此时还是没有heap的部分,因为heap还没初始化
continue
heap
x/4gx 0x602000 # 64位用gx,32位用wx
continue继续执行,然后再看堆,已经生成了一个chunk,这就是程序第一个malloc:char *s0=malloc(0x10);申请的chunk
heap后可以看到chunk头prev_size和size的值
这个时候再vmmap一下,就能看到heap相关的东西了,这里分配的堆内存空间比malloc申请的还大
size
上面我们看到这个chunk的size=33=0x21,而不是申请的0x10。实际上size=chunk头+分配的空间大小,chunk占0x10个byte,但是这样看应该size=0x10+0x10=0x20,还差一个1,这就要看chunk的结构了
这是一个属于fast bin的chunk,size内容占的是红框的部分,但是值只在前面一部分(绿框),后面有标志位。fast bin范围内chunk的inuse标志位始终被置为1,即它们不会和其他被释放的chunk合并,也就不会触发Unlink操作。这里的p就跟inuse位有关,p为1表示正在被使用中,为0则表示这个chunk不再被使用
《glibc内存管理ptmalloc源代码分析》:
以第 0 位作为 P 状态位,标记前一 chunk 块是否在使用中,为 1 表示使用,为 0 表示空 闲。
以第 1 位作为 M 状态位,标记本 chunk 块是否是使用 mmap()直接从进程的 mmap 映射 区域分配的,为 1 表示是,为 0 表示否。
以第 2 位作为 A 状态位,标记本 chunk 是否属于非主分配区,为 1 表示是,为 0 表示 否。
所以size值多了一个1是这里的p导致的,以此类推,可以把源码中第一行malloc换成0x1000再重新调试一下,看到size=4113=0x1011
fd和bk
chunk就相当于一个链表,fast bin中是单链表,其余的small bin等是双向链表。fd和bk就相当于双向链表的prev、next两个指针。注意,chunk空闲的时候才有用
继续分析
继续c、heap、x看chunk的情况
后面的malloc也逐渐分配到chunk
这次只分析了申请chunk的过程,free的过程还没有了解,后续再补充吧
pwn堆溢出系列第一讲_哔哩哔哩_bilibili这位师傅感觉讲的挺清晰的,比看文章更容易理解