堆的一些基本思想
堆的一些基本思想
malloc,mmap
- 当想要创建的堆过大时,malloc会调用mmap来创建堆
- 这个堆的标识为2
- mmap有prev_size和size,但是没有fd和bk,因为不会进bin
- mmap创建的堆不会在heap那个空间里,而是在glibc中找一块位置进行创建(一般是在heap下面)
- 并且对于这个的free也不一样,会使用系统调用来进行free
- 释放它时size需要与页对齐
- 并且释放后的堆块将不能读写
堆的结构,bin,tcache
这个就不说了,打多了之后都知道了。
有个注意点,创建堆时产生的指针是指向空白位置的,而bin中得到指针是指向大小的。
tcache的特性
- 在glibc2.26之后引入了tcache技术
- tache是个单链表,并且最大值默认是7
- 在2.27高版本或者2.29版本中加入了key指针来防止double free
- 在从fast bin或者small bin中取chunk事,会尽可能把剩余的chunk放入tcache bin
神奇的操作
- unsorted bin在存进去第一个的时候会把它们的指针设为main_arena,而这个地址相对于libc的基址是不会变的
malloc_hook的劫持
- malloc_hook一般用来打one_gadget,因为它的参数是创建chunk的大小
free_hook的劫持
- 与malloc_hook不同的是,free_hook的参数是堆内容的地址,所以可以直接将它变成system函数运行。
IO_FILE
- 在fopen的时候会创建所谓文件流的东西,它会分配在堆中,并以链表的形式串联起来。
- 技巧:pwndbg的p /x命令可以查询一些存储的值
所有的file结构都是这样一个结构体:
struct _IO_FILE_plus
{
_IO_FILE file;
_IO_jump_t *vtable;
}
可以直接pwndbg调试的。抄一下别人博客的源码(侵权立删!):
struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
char* _IO_read_ptr; /* Current read pointer */
char* _IO_read_end; /* End of get area. */
char* _IO_read_base; /* Start of putback+get area. */
char* _IO_write_base; /* Start of put area. */
char* _IO_write_ptr; /* Current put pointer. */
char* _IO_write_end; /* End of put area. */
char* _IO_buf_base; /* Start of reserve area. */
char* _IO_buf_end; /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base; /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno;
#if 0
int _blksize;
#else
int _flags2;
#endif
_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
/* char* _save_gptr; char* _save_egptr; */
_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};
而vtable指针里面又有很多跳转函数:
void * funcs[] = {
1 NULL, // "extra word"
2 NULL, // DUMMY
3 exit, // finish <_IO_new_file_finish>
4 NULL, // overflow <_IO_new_file_overflow>
5 NULL, // underflow <_IO_new_file_underflow>
6 NULL, // uflow <__GI__IO_default_uflow>
7 NULL, // pbackfail <__GI__IO_default_pbackfail>
8 NULL, // xsputn #printf <_IO_new_file_xsputn>
9 NULL, // xsgetn <__GI__IO_file_xsgetn>
10 NULL, // seekoff <_IO_new_file_seekoff>
11 NULL, // seekpos <_IO_default_seekpos>
12 NULL, // setbuf <_IO_new_file_setbuf>
13 NULL, // sync <_IO_new_file_sync>
14 NULL, // doallocate <__GI__IO_file_doallocate>
15 NULL, // read <__GI__IO_file_read>
16 NULL, // write <_IO_new_file_write>
17 NULL, // seek <__GI__IO_file_seek>
18 pwn, // close <__GI__IO_file_close>
19 NULL, // stat <__GI__IO_file_stat>
20 NULL, // showmanyc <_IO_default_showmanyc>
21 NULL, // imbue <_IO_default_imbue>
};
神奇的是,puts函数居然也会调用这里面的xsputn,overflow