一、源C代码&编译指令
//源C代码 cs1g.c
//gcc -g cs1g.c -o cs1g
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int i;
void *xy1,*xy2,*xy3,*xy4,*xy5,*xy6; //0之前vmmap指令查看不到heap堆
xy1 = malloc(0x30);
xy2 = malloc(0x60);
xy3 = malloc(0x30);
free(xy1);
*(long long *)((long long)xy2) = 0x112233445566778899121314151617181920;
*(long long *)((long long)xy3) = 0x55667788;
xy4 = malloc(0x30);
xy5 = malloc(0x30);
free(xy2);
xy6 = malloc(0x30);
free(xy3);
free(xy4);
free(xy5);
free(xy6);
return 0;
}
top chunk
地址最高的chunk
当所有的bin都无法满足时,若 top chunk 大于申请的空间,则分割,分割后剩余的部分作为新的 top chunk。
初始情况下,我们可以将 unsorted chunk 作为 top chunk。
名词:
chunk:块
arena:操作系统分配给程序的一块较大的(大于所申请的)内存区域
last remainder:在用户使用 malloc 请求分配内存时,ptmalloc2 找到的 chunk 可能并不和申请的内存大小一致,这时候就将分割之后的剩余部分称之为 last remainder chunk ,unsort bin 也会存这一块。top chunk 分割剩下的部分不会作为 last remainer.
堆操作:
-
malloc(size_t n)
返回对应大小字节的内存块的指针
当 n=0 时,返回当前系统允许的堆的最小内存块
当 n 为负数时,由于在大多数系统上,size_t 是无符号数(这一点非常重要),所以程序就会申请很大的内存空间,但通常来说都会失败,因为系统没有那么多的内存可以分配
使用brk申请的堆空间会挨着数据段,而使用mmap的堆空间在较高的地址
这些内存在释放之后一般不会返回系统而是在程序中等待申请
malloc()会使用两种系统调用:
1)brk()或者sbrk()函数
操作系统提供了 brk 函数,glibc 库提供了 sbrk 函数,sbrk会调用brk
初始时,堆的起始地址 start_brk 以及堆的当前末尾 brk 指向同一地址
brk(address) 直接将program break修改到address,返回值 0成功 -1 失败
sbrk(n) 修改program break向高地址增长n个字节,返回开辟之前的program break地址
sbrk(0)返回当前program break的地址
但是program break的增长不是无限制的,天花板是Memory Mapping Segment
2)mmap()
当申请的空间大于128k时,malloc()调用mmap()
二、调试过程
2.1 分配xy1、xy2、xy3,释放xy1,赋值xy2和xy3
2.2 分配xy1、xy2、xy3、xy4,释放xy1,赋值xy2和xy3
2.3 分配xy1、xy2、xy3、xy4、xy5,释放xy1,赋值xy2和xy3
2.4 分配xy1、xy2、xy3、xy4、xy5,释放xy1、xy2,赋值xy2和xy3
2.5 分配xy1、xy2、xy3、xy4、xy5、xy6,释放xy1、xy2,赋值xy2和xy3
2.6 分配xy1、xy2、xy3、xy4、xy5、xy6,释放xy1-xy5,赋值xy2和xy3
三、总结
PWN-堆的调试技巧包括:
list显示源码;
gcc -g参数可以添加调试信息;
next,step,start,break,x,vmmap,bin,heap:这是常见的gdb调试命令;
malloc和free是常见的堆分配函数,是以chunk为单位进行分配,由双向链表连接不同的chunk。
四、参考文献
http://www.manongjc.com/detail/29-tufsgqnbxnlmcod.html
原文始发于微信公众号(豆豆咨询):PWN-堆的调试malloc-free
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论