malloc 结构体_二进制安全之堆溢出(系列)——堆基础 amp; 结构(二)

ef67c253d3707c0f5c988504b6bdfa98.png

哈喽啊

这里是二进制安全之堆溢出(系列)第二期“堆基础 & 结构”第二节!!

353e2acdcc064447898cd4910da948f6.png

话不多说,直接上干货!

微观结构

函数执行流程

void *malloc (size_t bytes)
void *__libc_malloc (size_t bytes) //对于_int_malloc做简单封装__malloc_hook  //类似于虚函数,派生接口,指定一个malloc的方式
_int_malloc(mstate av, size_t bytes) //申请内存块的核心

main_arena

  • 集中管理bins链的结构体,使用含fd和bk的bin头一对一管理各个free的chunk
  • 分释放配堆块是基于main_arena来寻址的,首先找的是fastbin,其次再找bins
  • main_arena存储在libc上,用以管理所有bins的头和尾,每个bins链头的fd和尾的b与之连接
struct malloc_state
{/* Serialize access. */__libc_lock_define (, mutex);//定义了一个0x4字节的lock/* Flags (formerly in max_fast). */int flags;//0x4/* Set if the fastbin chunks contain recently inserted free blocks. *//* Note this is a bool but not all targets support atomics on booleans. */int have_fastchunks;//0x4/* Fastbins */mfastbinptr fastbinsY[NFASTBINS]; //fastbin链的管理头,总共10个, 每个0x10字节/* Base of the topmost chunk -- not otherwise kept in a bin */mchunkptr top;//0x4 到此为止总共0x96字节/* The remainder from the most recent split of a small request */mchunkptr last_remainder;        //切割后剩下的chunk链接到last_remainder/* Normal bins packed as described above */mchunkptr bins[NBINS * 2 - 2];   // 每个bin头有fd和bk两个指针/* Bitmap of bins */unsigned int binmap[BINMAPSIZE];   //位图,用32bit来分别表示当前bin哪个链上有chunk,通过按位与的方式/* Linked list */struct malloc_state *next;/* Linked list for free arenas. Access to this field is serializedby free_list_lock in arena.c. */struct malloc_state *next_free;/* Number of threads attached to this arena. 0 if the arena is onthe free list. Access to this field is serialized byfree_list_lock in arena.c. */INTERNAL_SIZE_T attached_threads;/* Memory allocated from the system in this arena. */INTERNAL_SIZE_T system_mem;INTERNAL_SIZE_T max_system_mem;
}
  • main_arena:用来管理整个bin链的结构体,总共128个bin,10个fastbin
  • 每个bin头可以简化为fd和bk两个前后项指针
  • glibc ---> main_arena ---> 对应的bins头的fd和bk ---> 遍历找到对应free的chunk
  • main_arena存放在libc中,其中存放的是每一个bin链的头尾
tips:如果我们能打印一个非fastbin链中的fd,bk,那我们就可以计算出libc的基地址libc.addr = libc_on - libc.sysbols["main_arena"] - 88

main_chunk

  • 在程序的执行过程中,我们称malloc申请的内存为chunk。这块内存在ptmalloc内部用malloc_chunk结构体来表示。
  • 当程序申请的chunk被free后,会被加入到相应的空闲管理列表中。
  • 无论一个chunk的大小如何,处于分配状态还是释放状态,它们都使用一个统一的结构。但根据是否被释放,结构会有所更改。
struct malloc_chunk {INTERNAL_SIZE_T      mchunk_prev_size;  // 如果前面一个堆块是空闲的则表示前一个堆块的大小,否则无意义INTERNAL_SIZE_T      mchunk_size;       //当前chunk的大小,由于对齐的原因所以低三位作为flag,意义如下:/*A:倒数第三位表示当前chunk属于主分配区(0)还是非主分配区(1)M:倒数第二位表示当前chunk是从mmap(1)[多线程]分配的,还是从brk(0)[子线程]分配的P:最低为表示前一块是否在使用中*//*1.真正的内存从这里开始分配2.malloc之后这些指针没有用,这时存放的是数据3.只有在free之后才有效。*/struct malloc_chunk* fd;       //当chunk空闲时才有意义,记录后一个空闲chunk的地址struct malloc_chunk* bk;   //同上,记录前一个空闲chunk的地址/* Only used for large blocks: pointer to next larger size. */struct malloc_chunk* fd_nextsize; //当前chunk为largebin时才有意义,指向比当前chunk大的第一个空闲chunkstruct malloc_chunk* bk_nextsize; //指向比当前chunk小的第一个空闲堆块
};
  • prev_size
    • malloc(0x18)会分配0x20的内存
    • malloc(0x19)分会配0x30的内存
    • 如果该chunk的物理相邻的前一地址chunk(两个指针的地址差值为前一个chunk大小)是空闲的话,那该字段记录的是前一个chunk的大小
    • 否则用来存储物理相邻的前一个chunk的数据,这里前一个chunk指的是较低地址的chunk。
    • prev_size位可以被共享,当前的chunk, 如果不够用就会占用下一块chunk的prev_size
  • size
    • chunk1的数据有效区域覆盖到chunk2的prev_size位,并且chunk2的size位的prev_inuse被覆盖为0。系统认为chunk2之前的chunk1已经未在使用了。
    • 当free(chunk2)的时候,系统会将chunk2与chunk2中prev_size大小的空间合并到bins。
    • 我们可以通过改变chunk2的prev_size的内容,操纵向前合并的大小。
    • 造成的问题:overlap(堆块重叠),chunk1被释放了,但是我们可以操纵修改它(堆利用的核心思想),从而修改bins链的内容,泄露其中的地址。
    • 形成的攻击:fastbin ---> fd ---> main_arena ---> 分配新的堆块,我们通过修改chunk1的fd内容,达到分配任意内存的目的,造成fastbin attack。
    • 记录前一个chunk是否被分配。
    • 一般来说,堆中第一个被分配的内存块的size字段的P位都会被设置为1,以便于防止访问前面的非法内存。
    • 当一个chunk的size位的P位为0时,我们能通过prev_size获取上一个chunk的大小及地址,方便进行空闲堆块的合并。
    • 对于fastbin的堆块,不管前面还有没有被分配的chunk,PREV_INUSE都为1。
    • 64位chunk的size必须是16字节对齐
    • 32位chunk的size必须是8 字节对齐
    • 64位 低4位没用 11110000
    • 32位 低3位没用 11111000
    • define chunksize(p) (chunk_nomask (p) & ~(SIZE_BITS))
    • define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
    • NON_MAIN_ARENA记录当前chunk是否是main_arena管理的堆块,1表示不属于,0表示属于
    • IS_MAPPED记录当前的chunk是否是由mmap分配的。
    • PREV_INUSE
    • 最小堆原则 : malloc(0)会分配0x20的空间,prev_size + size + 数据对齐的0x10字节
    • prev_inuse 漏洞利用

2c6e0485e84aeeeced23e52ed8a00566.png
  • fd / bk
    • 释放到bins链有效
    • fd指向下一个(非物理相邻)空闲的chunk
    • bk指向上一个(非物理相邻)空闲的chunk
    • 通过fd和bk可以将空闲的chunk块加入到空闲的chunk链表进行统一管理。
  • fd_nextsize / bk_nextsize
    • 释放到bins链有效,不过其用于较大的chunk(large chunk)
    • fd_nextsize指向前一个与当前chunk大小不同的第一个空闲块,不包含bin的头指针
    • bk_nextsize指向后一个与当前chunk大小不同的第一个空闲块,不包含bin的头指针
    • 一般空闲的largechunk在fd的遍历顺序中,按照从大到小的顺序排列,可以避免在寻找合适的chunk时挨个遍历。

__libc_malloc

void *__libc_malloc (size_t bytes)
{mstate ar_ptr;void *victim;void *(*hook) (size_t, const void *)= atomic_forced_read (__malloc_hook);if (__builtin_expect (hook != NULL, 0))return (*hook)(bytes, RETURN_ADDRESS (0));
#if USE_TCACHE/* int_free also calls request2size, be careful to not pad twice. */size_t tbytes;checked_request2size (bytes, tbytes);   //注意:用户申请的字节一旦进入申请内存函数被转化为了无符号整数size_t tc_idx = csize2tidx (tbytes);MAYBE_INIT_TCACHE ();DIAG_PUSH_NEEDS_COMMENT;if (tc_idx < mp_.tcache_bins/*&& tc_idx < TCACHE_MAX_BINS*/ /* to appease gcc */&& tcache&& tcache->entries[tc_idx] != NULL){return tcache_get (tc_idx);}DIAG_POP_NEEDS_COMMENT;
#endifif (SINGLE_THREAD_P){victim = _int_malloc (&main_arena, bytes);assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||&main_arena == arena_for_chunk (mem2chunk (victim)));return victim;}arena_get (ar_ptr, bytes);victim = _int_malloc (ar_ptr, bytes);/* Retry with another arena only if we were able to find a usable arenabefore. */if (!victim && ar_ptr != NULL){LIBC_PROBE (memory_malloc_retry, 1, bytes);ar_ptr = arena_get_retry (ar_ptr, bytes);victim = _int_malloc (ar_ptr, bytes);}if (ar_ptr != NULL)__libc_lock_unlock (ar_ptr->mutex);assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||ar_ptr == arena_for_chunk (mem2chunk (victim)));return victim;
}
  1. 该函数会首先检查是否有内存分配函数的钩子函数(__malloc_hook),这个主要用于用户自定义的堆分配函数。
这就造成了一个利用点:将__malloc_hook指针指向的内容改为one_gadget的地址,再次malloc的时候就会直接启动shell。__malloc_hook -> one_gadget(直接起shell的地址)这时不能将其修改为system的地址,因为system的参数为字符型,而malloc_hook的参数为无符号整数。
  1. 接着会寻找一个arena来试图分配内存,然后调用__int_malloc函数去申请对应的内存
如果分配失败的话,ptmalloc会试图再去寻找一个可用的arena,并分配内存如果申请到了arena,那么在退出之前还得解锁(__libc_lock_lock)
  1. 判断目前的状态是否满足以下条件
  • 要么没有申请到内存
  • 要么是mmap的内存
  • 要么申请的的内存必须在其所分配的arena中
  • assert
最后返回内存,进入__int_malloc

__int_malloc

__int_malloc是内存分配的核心函数,其核心思路为:

它根据用户申请的内存块大小以及相应大小chunk通常使用的频度,依次实现了不同的分配方法它由小大到大依次检查不同的bin中是否有相应的空闲块可以满足用户请求的内存当所有空闲的chunk都无法满足时,他会考虑top_chunk当top_chunk也无法满足时,堆分配器才会进行内存块申请

1. 定义变量

788402c03199939b9811d6ac50d57eec.png

2. 判断有没有可用的arena

如果没有可用的arena,则返回系统调用mmap去申请一块内存

de9065811441f47d1d6081df1405fd4e.png

3. 判断是否在fastbin范围

如果申请的chunk的大小正好位于fastbin的范围,则从fastbin的头节点开始取chunk。需要注意的是,这里比较的是无符号整数调用remove_fb取出,并返回得到的fastbin的头

bd8f2cd9104585b9c8d0130093ffc376.png

4. 判断是否在smallbin

如果获取的内存块的范围为smallbin的范围,执行以下流程找到其大小对应的下标,判断其链表是否为空,不为空则取最后一个

0263135b44105d2124a4c57387217200.png

注意,为了防止一个堆块能够正常free且不前向后并,需要修改当前堆块的物理相邻的紧接着的2个堆块的inuse位为1。

5.调用consolidate

当fastbin,small bin中的chunk都不能满足要求时,就会考虑是不是largebin,在此之前先调用malloc_consolidate处理fastbin中的chunk

b44fc811937ab9f2edf781e5dcbc4dd9.png

将有可能合并的chunk先进行合并后放到unsorted bin中,不能合并的就直接放到unsorted bin中,然后再进入大循环,以减少堆中的碎片。只有在分配一个size在largebin范围内的堆块,才能触发malloc_consolidate

6. 小总结

在fastbin范围内,先判断对应链表是否为空,不为空则取刚放入的chunk在smallbin范围内,先判断对应链表是否为空,不为空则取第一个放入的chunk这两者都无法匹配用户申请的chunk时,就会进入大循环

7. 进入大循环

a. 尝试从unsorted bin中分配用户需要的内存b. 尝试从large bin中分配用户需要的内存b. 尝试从top_chunk中分配用户需要的内存

8. 从unsorted bin中分配nb

如果申请的size小于unsorted bin中符合要求的chunk的size,会对其进行切割,剩下的进入last_remainder(由unsorted bin管理)如果unsorted bin中没有满足要求的chunk时,会先place in order整理,然后再去large bin中寻找

9. 从large bin中分配nb

注意,large bin中的堆块不会split,不满足的话就从top_chunk中切割

10. 大循环之对于unsorted bin的check

对于size的check:检查当前size是否满足对齐的 要求对于fd和bk的check:bck -> fd != victim对于double free的check:next->prev_inuse = 0

11. 大循环之切割unsorted bin

如果用户请求为small bin chunk,那么我们首先考虑last_remainder如果last_remainder分割后还够可以作为一个chunk,则使用set_head,set_foot设置标志位,将last_remainder放入原来unsorted bin的位置

b37f8db938648b5b19ea5859f8557c8c.png

12. 大循环之取出unsorted bin

首先将unsorted bin取出,如果其size和我们的nb(need bytes)一样则直接放回这个unsorted bin

13. 大循环之放入对应的bin

根据取出的size来判断应该放入哪个bin,放入small bin的时候则双向链表插入在else if中处理large bin的逻辑,包括大小排序以及fd_nextsize和bk_nextsize

dd0126b6d0a4e63d6c01f40a3fff6648.png

14. 大循环总结

整个过程迭代了10000次

ae563ab9429e815a4f83a9992f0c0d63.png

__int_malloc的大循环主要用来处理unsorted bin如果整个循环没有找到合适的bin,说明所有的unsorted bin的大小都不满足要求如果经过了10000次的循环,所有的unsorted bin中的bin都被放入了对应的bin中,即small bin放入对应的index中,large bin排好序后放入对应的index中

15. 大循环之large bin

如果请求的chunk在large bin范围内,就在对应的bin中从小到大依次扫描,直到找到第一个合适的,并不一定精确

0ea41ae3199c3cb4420f600f6547d70a.png


切割后的remainder会被放入到unsorted bin中,同时设置标志位等信息

422c1b2edae84b9c6bc708408fcdb9ca.png

16. 寻找较大的chunk

2494b3aff17da3eb56a85f0c69d8486d.png

如果走到了这里,说明对于用户所需的chunk,不能直接从其对应的合适的bin中获取chunk,需要扫描所有的bin,查找比当前bin更大的fast bin或small bin 以及large bin

17. 找到一个合适的map

ce68beef6d346ba7959b14d6e095413e.png

18. 取出chunk

切割之后还是一样,放入到unsorted bin

7eeca965d2f2cdb06bba5734b53d6279.png

19. 使用top_chunk

如果所有的bin中的chunk都没有办法直接满足要求(即不合并),或者没有空闲的chunk时,就只能使用top_chunk了

5e4cf64b9524d6a7fed27d1f74812c53.png

20. top_chunk不够用

> 如果top_chunk不够用的时候并不是直接申请内存,而是先调用consolidate合并空闲的fastbin
>
> 然后等待下次循环再去判断是否够用,不够用才会调用sysmalloc申请内存
>
> ![](https://ws1.sinaimg.cn/large/006nFhrCly1g47vckz6b7j30gn0cmgnb.jpg)

_int_malloc总结

  • malloc寻找堆块的顺序
  1. 在fastbin中寻找有没有对应的chunk
  2. 请求大小为small bin范围,在small bin中寻找有没有对应的chunk
  3. 请求大小为large bin范围,仅调用malloc_consolidate合并fastbin
  4. 在unsorted bin中寻找有没有合适的chunk
  5. 在large bin中寻找有没有合适的chunk
  6. 寻找较大的bin链中有没有合适的chunk
  7. 寻找top_chunk
  8. top_chunk不够用,调用malloc_consolidate合并fastbin
  9. top_chunk不够用,系统调用再次申请内存

096eeab1ea392f6067f78f325d46a099.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/501896.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

drbd实现mysql地热备_Mysql+DRBD+Heartbeat 实现mysql高可用的双机热备(mysql+heartbeat篇)...

*************************************部署MYSQL*******************************************yum -y install gcc gcc-c gcc-g77 autoconf automake zlib* fiex* libxml* ncurses-devel libmcrypt* libtool-ltdl-devel* make cmake bison*useradd mysql -d /usr/local/mysql…

深入理解计算机系统第四版_深入理解计算机系统之存储器层次结构

我的计算机模型是这样的&#xff1a;CPU执行指令&#xff0c;内存犹如一个巨大的字节数组&#xff0c;存储着指令和数据&#xff0c;硬盘保存着各种程序与程序用到的数据。I/O完成输入输出的功能。在本文中我们抛开I/O&#xff0c;谈一谈关于CPU&#xff0c;内存&#xff0c;硬…

mysql8支持myISAM_mysql8 参考手册--优化MyISAM表

MyISAM存储引擎在以读为主的数据或低并发操作中表现最好&#xff0c;因为表锁限制了同时执行更新的能力。在MySQL中&#xff0c;InnoDB是默认的存储引擎&#xff0c;而不是MyISAM。优化MyISAM查询一些加快MyISAM表查询的一般技巧 &#xff1a;为了帮助MySQL更好地优化查询&…

python的模块提供了许多文件处理方法_详解使用Python处理文件目录的相关方法

所有文件都包含在各个不同的目录下&#xff0c;不过Python也能轻松处理。os模块有许多方法能帮你创建&#xff0c;删除和更改目录。mkdir()方法可以使用os模块的mkdir()方法在当前目录下创建新的目录们。你需要提供一个包含了要创建的目录名称的参数。语法&#xff1a;os.mkdir…

mysql替换json的key_mysql中json_replace函数的使用?通过json_replace对json对象的值进行替换...

需求描述:在看mysql中关于json的内容,通过json_replace函数可以实现对json值的替换,在此记录下.操作过程:1.查看带有json数据类型的表mysql> select * from tab_json;-------------------------------------------------------------------------------------------| id | d…

python中的array函数作用_Python中的Array | 数组2(简介和功能)

相关文章&#xff1a;Python中的数组Array | 1(简介和功能)以下是更多函数。1. typecode&#xff1a;此函数返回初始化数组所用的数据类型。2. itemsize&#xff1a;此函数返回单个数组元素的大小(以字节为单位)。3. buffer_info()&#xff1a;返回一个元组&#xff0c;表示存储…

java生成pdf_JAVA 生成PDF 并导出

/***首先啥也不干&#xff0c;先写一个转换中文的方法&#xff0c;话说谁要整一个全英文数字的就不* 要写这个方法了....*str :要转换的内容 c:字体大小*/private static Paragraph getChinese(String str,int c) throws DocumentException, IOException{ BaseFont …

python爬取今日头条的文章_Python3爬取今日头条有关《人民的名义》文章

Python3爬取今日头条有关《人民的名义》文章最近一直在看Python的基础语法知识&#xff0c;五一假期手痒痒想练练&#xff0c;正好《人民的名义》刚结束&#xff0c;于是决定扒一下头条上面的人名的名义文章&#xff0c;试试技术同时可以集中看一下大家的脑洞也是极好的。首先&…

java jmeter_使用Jmeter中的Java Request进行性能测试

在使用jmeter进行性能测试的时候&#xff0c;有可能会需要通过一些脚本去测试性能&#xff0c;(比如通过sokeeper的api去测试sokeeper的读写性能)。这时&#xff0c;我们可以通过Java Request实现&#xff0c;以下是操作步骤。首先创建一个maven project。因Jmeter的Java Reque…

python虚拟环境 pyenv_Python 虚拟环境 pyenv、venv(pyvenv)、virtualenv之间的区别

请参考连接 https://blog.zengrong.net/post/2167.htmlhttps://blog.csdn.net/lanonjj/article/details/51050212为避免链接失效&#xff0c;把原文做了复制黏贴另外在python3.6中&#xff0c;虚拟应该用如下命令创建python3 -m venv /path/to/new/virtual/environment直接用py…

java resources 目录_[Java] 在 jar 文件中读取 resources 目录下的文件

注意两点&#xff1a;1. 将资源目录添加到 build path&#xff0c;确保该目录下的文件被拷贝到 jar 文件中。2. jar 内部的东西&#xff0c;可以当作 stream 来读取&#xff0c;但不应该当作 file 来读取。例子新建一个 maven 目录App.java 用于读取 resources 中的 a.txt 内容…

m.2接口和nvme区别_m.2 nvme和m.2有区别吗?

m2接口有两种&#xff0c;一种走sata的&#xff0c;另外一种走pcie(就是nvme)的。走sata的速度跟传统sata接口的没区别&#xff0c;就是接口变成了m2的了。走pcie的&#xff0c;就是我们说的nvme接口是m2的&#xff0c;性能也强了。M.2接口有SATA也有NVMe PCIe协议。这个是同一…

python编程软件排行榜_Python编程开发工具:这10个对Web开发者最有用的Python包

Python编程一时间成为了开发人员最喜欢的语言之一。无论是专业的&#xff0c;业余的&#xff0c;还是作为一个Python初学者&#xff0c;都可以从Python编程语言及其程序包中受益。Python已经被证明是当今最具活力的面向对象的编程语言之一。这就是为什么即使是一些很优秀的公司…

java excel 字体大小_Java将数据按列写入Excel并设置格式(字体、背景色、自动列宽、对齐方式等)...

/*** 按列写入Excel并设置格式**paramoutputUrl* 输出路径*paramsheetName* 工作薄名称*paramtitles* 表头*paramarrayList* 表头数据*throwsIOException*throwsRowsExceededException*throwsWriteException*/public static voidwriteExcel(String outputUrl, String sheetName…

如何查看cplex的help文档_word查看技巧:如何快速找到文档的修改痕迹

不知道大家在工作中有没有遇到过这类的工作场景&#xff1a;当初步拟好一份合作协议或是项目策划书后&#xff0c;发给老板或其他同事审阅和修订&#xff0c;通常会不断地来回修改文档。此时&#xff0c;如果你想要查看文档哪里被修改过&#xff1f;你会怎么操作&#xff1f;很…

java将数字替换为空_将数字替换为java中正确位置的单词

实际上我正试图用用户给出的句子中的数字替换为单词.本案例日期格式;例如&#xff1a;我的生日是在16/6/2000,我是java的新手 – >成为—>我的生日是七月十六日,我是java的新手这是代码&#xff1a;Scanner reader new Scanner(System.in);System.out.println("Ent…

java重载this_Java的this关键字的使用与方法的重载相关知识

Java this关键字详解this 关键字用来表示当前对象本身&#xff0c;或当前类的一个实例&#xff0c;通过 this 可以调用本对象的所有方法和属性。例如&#xff1a;public class Demo{public int x 10;public int y 15;public void sum(){// 通过 this 点取成员变量int z this…

python 类和对象 经常用吗_python基础教程之对象和类的实际运用

我们熟悉了对象和类的基本概念。我们将进一步拓展&#xff0c;以便能实际运用对象和类。调用类的其它信息中提到&#xff0c;在定义方法时&#xff0c;必须有self这一参数。这个参数表示某个对象。对象拥有类的所有性质&#xff0c;那么我们可以通过self&#xff0c;调用类属性…

java get properties_Java.lang.System之getProperties()方法

Environmentjava.vm.version——>25.60-b23java.vm.vendor——>Oracle Corporationjava.vendor.url——>http://java.oracle.com/idea.launcher.port——>7533java.vm.name——>Java HotSpot(TM) 64-Bit Server VMfile.encoding.pkg——>sun.iouser.country—…

mysql set语句_MySQL Prepared语句简介

之前的MySQL版本4.1&#xff0c;查询以文本格式发送到MySQL服务器。 之后&#xff0c;MySQL服务器使用文本协议将数据返回给客户端。MySQL必须完全解析查询&#xff0c;并将结果集转换为字符串&#xff0c;然后再将其返回给客户端。 文本协议具有严重的性能问题。为了解决这个问…