堆的系统调用
实例代码
/* sbrk and brk example */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
void *curr_brk, *tmp_brk = NULL;
printf("Welcome to sbrk example:%d\n", getpid());
/* sbrk(0) gives current program break location */
tmp_brk = curr_brk = sbrk(0);
printf("Program Break Location1:%p\n", curr_brk);
getchar();
/* brk(addr) increments/decrements program break location */
brk(curr_brk+4096);
curr_brk = sbrk(0);
printf("Program break Location2:%p\n", curr_brk);
getchar();
brk(tmp_brk);
curr_brk = sbrk(0);
printf("Program Break Location3:%p\n", curr_brk);
getchar();
return 0;
}
编译运行之后, 在第一次调用brk之前
查看内存映射
堆的分析
这是每个chunk的布局
prev_size: 如果当前chunk的相邻前一chunk未被使用,prev_size为此前一chunk的大小
size: 当前chunk的大小。由于chunk大小是8的整数倍,所以此size的后3 bit被用于存储其他信息。我们需要记住的便是最低bit,即图中P的位置,用于指示前一chunk是否已被使用(PREV_INUSE)。
如果当前chunk未被使用, 则
fd: 下一个未被使用的chunk的地址
bk: 上一个未被使用的chunk的地址
所以我们可以通过当前的chunk去定位前一个chunk和后一个chunk
也就是拿当前chunk的地址减去前一个chunk的大小
或者拿当前chunk的地址加上当前chunk的大小
那些未被使用的chunks通过fd, bk组成了链表。事实上,malloc确实维护了一系列链表用于内存的分配和回收,这些链表被成为"bins"。
bin分为fastbin, unsorted bin, small bin, large bin。我们这里要研究的就是fastbin。
看了这篇文章之后觉得fastbin似乎也不是很难, 当然最难的地方在于如何构造payload浅析Linux堆溢出之fastbin
再好好分析一下malloc()这个神奇的函数
在glibc中,malloc_chunk以 2*sizeof(size_t)对齐,在32位系统中以8字节对齐,在64位系统中一般以16字节对齐。Malloc_chunk的定义如下:
既然malloc_chunk以2sizeof(size_t)对齐,那么malloc返回给用户的指针数值也是以2sizeof(size_t)对齐。
最小的chunk是多大呢
最小的chunk需要保证能放下prev_size、size、fd以及bk字段并保证对齐。在32位系统中,即16字节,在64位系统中,一般为32字节。在64位系统中也可能定义INTERNAL_SIZE_T也即size_t为4字节,这种情况下最小的chunk位24字节
fastbin中有10个bin
在32位系统中,fastbin里相邻的两个bin大小差距8个字节;在64位系统中,则是差距16个字节。
32位系统中,fastbin里chunk的大小范围从16到64;
怎么根据p=malloc(m)里的m来判断分配多大的chunk呢?
将申请的内存大小加上每个chunk的overhead,也就是chunk结构体里的size字段。然后对齐,就是需要分配的chunk的大小。
在实战之前先把wp好好看一下
接下来就是实战了
貌似不能在32位平台上运行
脚本执行报错怎么办。。
这个错误貌似是struct这个包在pack的时候出的问题?
struct.pack
在stackoverflow上找到了这样一个例子, 说是把q改成Q就行了
和我想的相差不多, 就是那个libc_case的地址小于0x3a55ed