CTF-PWN glibc源码阅读[1]: 寻找libc中堆结构的定义(2.31-0ubuntu9.16)

源代码在这里下载

来到malloc/malloc.c

在980行发现这段代码

// 定义最大 mmap 值为 -4
#define M_MMAP_MAX             -4// 如果没有定义 DEFAULT_MMAP_MAX,则将其定义为 65536
#ifndef DEFAULT_MMAP_MAX
#define DEFAULT_MMAP_MAX       (65536)
#endif// 引入 malloc.h 头文件,通常包含内存分配和释放相关的函数声明
#include <malloc.h>// 如果没有定义 RETURN_ADDRESS 宏,定义为一个空操作,返回 NULL
#ifndef RETURN_ADDRESS
#define RETURN_ADDRESS(X_) (NULL)
#endif/* 结构体和类型的前向声明 */// 定义 malloc_chunk 结构体(实际定义可能在代码的其他地方)
struct malloc_chunk;// 定义 mchunkptr 为指向 malloc_chunk 结构体的指针类型
typedef struct malloc_chunk* mchunkptr;/* 内部函数声明 */// 内部函数:分配内存
static void*  _int_malloc(mstate, size_t);// 内部函数:释放内存
static void     _int_free(mstate, mchunkptr, int);// 内部函数:调整内存块大小
static void*  _int_realloc(mstate, mchunkptr, INTERNAL_SIZE_T, INTERNAL_SIZE_T);// 内部函数:内存对齐分配
static void*  _int_memalign(mstate, size_t, size_t);// 内部函数:内存对齐分配的中间实现
static void*  _mid_memalign(size_t, size_t, void *);// 内部函数:打印内存分配错误信息,且该函数不会返回
static void malloc_printerr(const char *str) __attribute__ ((noreturn));// 内部函数:检查内存块的有效性
static void* mem2mem_check(void *p, size_t sz);// 内部函数:检查堆的顶端是否正常
static void top_check(void);// 内部函数:通过 munmap 释放内存块
static void munmap_chunk(mchunkptr p);// 如果系统支持 mremap,则声明 mremap_chunk 函数,用于调整内存映射
#if HAVE_MREMAP
static mchunkptr mremap_chunk(mchunkptr p, size_t new_size);
#endif// 内部函数:检查 malloc 操作的合法性
static void*   malloc_check(size_t sz, const void *caller);// 内部函数:检查 free 操作的合法性
static void      free_check(void* mem, const void *caller);// 内部函数:检查 realloc 操作的合法性
static void*   realloc_check(void* oldmem, size_t bytes, const void *caller);// 内部函数:检查内存对齐分配操作的合法性
static void*   memalign_check(size_t alignment, size_t bytes, const void *caller);

查看malloc_chunk结构体

// 定义内存块的元数据结构体,用于管理堆中的内存块
struct malloc_chunk {INTERNAL_SIZE_T mchunk_prev_size;  // 前一个内存块的大小(如果该块是空闲的)INTERNAL_SIZE_T mchunk_size;       // 当前内存块的大小,包括元数据的开销// 双向链表指针,用于空闲内存块的链表管理struct malloc_chunk* fd;           // 指向下一个空闲块的指针(free list 链表的正向指针)struct malloc_chunk* bk;           // 指向上一个空闲块的指针(free list 链表的反向指针)// 只用于较大的内存块,指向比当前内存块大的下一个内存块struct malloc_chunk* fd_nextsize;  // 双向链表指针,用于管理按大小排列的空闲块struct malloc_chunk* bk_nextsize;  // 双向链表指针,指向下一个比当前块大的空闲块};

在下面还能看到关于堆结构的注释

/*malloc_chunk details:(The following includes lightly edited explanations by Colin Plumb.)Chunks of memory are maintained using a `boundary tag' method asdescribed in e.g., Knuth or Standish.  (See the paper by PaulWilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for asurvey of such techniques.)  Sizes of free chunks are stored bothin the front of each chunk and at the end.  This makesconsolidating fragmented chunks into bigger chunks very fast.  Thesize fields also hold bits representing whether chunks are free orin use.An allocated chunk looks like this:chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|             Size of previous chunk, if unallocated (P clear)  |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|             Size of chunk, in bytes                     |A|M|P|mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|             User data starts here...                          ..                                                               ..             (malloc_usable_size() bytes)                      ..                                                               |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|             (size of chunk, but used for application data)    |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|             Size of next chunk, in bytes                |A|0|1|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+Where "chunk" is the front of the chunk for the purpose of most ofthe malloc code, but "mem" is the pointer that is returned to theuser.  "Nextchunk" is the beginning of the next contiguous chunk.Chunks always begin on even word boundaries, so the mem portion(which is returned to the user) is also on an even word boundary, andthus at least double-word aligned.Free chunks are stored in circular doubly-linked lists, and look like this:chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|             Size of previous chunk, if unallocated (P clear)  |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+`head:' |             Size of chunk, in bytes                     |A|0|P|mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|             Forward pointer to next chunk in list             |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|             Back pointer to previous chunk in list            |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|             Unused space (may be 0 bytes long)                ..                                                               ..                                                               |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+`foot:' |             Size of chunk, in bytes                           |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|             Size of next chunk, in bytes                |A|0|0|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+The P (PREV_INUSE) bit, stored in the unused low-order bit of thechunk size (which is always a multiple of two words), is an in-usebit for the *previous* chunk.  If that bit is *clear*, then theword before the current chunk size contains the previous chunksize, and can be used to find the front of the previous chunk.The very first chunk allocated always has this bit set,preventing access to non-existent (or non-owned) memory. Ifprev_inuse is set for any given chunk, then you CANNOT determinethe size of the previous chunk, and might even get a memoryaddressing fault when trying to do so.The A (NON_MAIN_ARENA) bit is cleared for chunks on the initial,main arena, described by the main_arena variable.  When additionalthreads are spawned, each thread receives its own arena (up to aconfigurable limit, after which arenas are reused for multiplethreads), and the chunks in these arenas have the A bit set.  Tofind the arena for a chunk on such a non-main arena, heap_for_ptrperforms a bit mask operation and indirection through the ar_ptrmember of the per-heap header heap_info (see arena.c).Note that the `foot' of the current chunk is actually representedas the prev_size of the NEXT chunk. This makes it easier todeal with alignments etc but can be very confusing when tryingto extend or adapt this code.The three exceptions to all this are:1. The special chunk `top' doesn't bother using thetrailing size field since there is no next contiguous chunkthat would have to index off it. After initialization, `top'is forced to always exist.  If it would become less thanMINSIZE bytes long, it is replenished.2. Chunks allocated via mmap, which have the second-lowest-orderbit M (IS_MMAPPED) set in their size fields.  Because they areallocated one-by-one, each must contain its own trailing sizefield.  If the M bit is set, the other bits are ignored(because mmapped chunks are neither in an arena, nor adjacentto a freed chunk).  The M bit is also used for chunks whichoriginally came from a dumped heap via malloc_set_state inhooks.c.3. Chunks in fastbins are treated as allocated chunks from thepoint of view of the chunk allocator.  They are consolidatedwith their neighbors only in bulk, in malloc_consolidate.
*/

翻译并整理后

malloc_chunk 详细信息

(以下内容包含由 Colin Plumb 轻微编辑的解释。)

内存块是通过一种 边界标签 方法来管理的,如 Knuth 或 Standish 所述。(有关此类技术的概述,请参见 Paul Wilson 的论文:ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps。)空闲块的大小会同时存储在每个块的前面和后面。这使得将碎片化的块合并为更大的块非常快速。大小字段还包含表示块是空闲还是正在使用的位。

分配的块结构

一个已分配的内存块如下所示:

以下是转换为中文Markdown表格的格式:

位置内容说明
chunk->前一个块的大小(当P标志清除时,表示未分配)
当前块的大小(字节数)|A|M|P|
mem->用户数据起始位置
(可用内存大小:malloc_usable_size()字节)
nextchunk->(块的大小,但用于应用程序数据)
下一个块的大小(字节数)|A|0|1|

其中,chunk 是块的前端,用于大部分 malloc 代码,但 mem 是返回给用户的指针。nextchunk 是下一个连续块的开始。块总是以偶数字边界开始,因此返回给用户的 mem 部分也会以偶数字边界开始,从而至少是双字对齐的。

空闲块结构

空闲块存储在循环双向链表中,结构如下:

以下是转换为中文Markdown表格的格式:

位置内容说明
chunk->前一个块的大小(当P标志清除时,表示未分配)
‘head:’当前块的大小(字节数)|A|0|P|
mem->指向列表中下一个块的前向指针
指向列表中前一个块的后向指针
未使用空间(可能长度为0字节)
nextchunk->
‘foot:’当前块的大小(字节数)
下一个块的大小(字节数)|A|0|0|

关键位说明

  • P(PREV_INUSE)位:存储在块大小的低位(总是一个双字的倍数),表示前一个块是否正在使用。如果该位清除,则当前块之前的字包含前一个块的大小,可用来找到前一个块的前端。分配的第一个块总是将此位设置为 1,防止访问不存在的(或未拥有的)内存。如果某个块的 prev_inuse 位设置,则无法确定前一个块的大小,甚至在尝试访问时可能会引发内存访问错误。

  • A(NON_MAIN_ARENA)位:该位在初始的主 arena 中清除,在由 main_arena 变量描述的 arena 中的块中。如果分配了额外的线程,每个线程会获得自己的 arena(直到达到可配置的限制,之后多个线程共享相同的 arena)。这些 arena 中的块会将 A 位设置为 1。要查找这种非主 arena 中的块所在的 arena,heap_for_ptr 通过位掩码操作和 heap_info 中每个堆头部的 ar_ptr 成员进行间接访问(详见 arena.c)。

特殊情况

当前块的 foot 实际上表示的是下一个块的 prev_size。这种设计使得对齐处理更简便,但在尝试扩展或适应代码时可能会非常困惑。

三个特殊情况

  1. 特殊块 top:由于没有下一个连续块需要索引,因此 top 块不使用尾部的大小字段。在初始化后,top 块必须始终存在。如果它变得小于 MINSIZE 字节,它会被补充。

  2. 通过 mmap 分配的块:这些块在其大小字段中设置了次低位的 M(IS_MMAPPED)位。由于它们是逐一分配的,因此每个块必须包含自己的尾部大小字段。如果 M 位设置,则其他位会被忽略(因为 mmap 分配的块既不在 arena 中,也不与空闲块相邻)。M 位也用于那些最初来自转储堆并通过 malloc_set_state 恢复的块(见 hooks.c)。

  3. 快速分配区的块:从块分配器的角度来看,快速分配区的块被视为已分配的块。它们只在 malloc_consolidate 中与相邻块进行合并,而不是逐块合并。


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

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

相关文章

【C++】深入优化计算题目分析与实现

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;第一题&#xff1a;圆的计算我的代码实现代码分析改进建议改进代码 老师的代码实现代码分析可以改进的地方改进代码 &#x1f4af;第二题&#xff1a;对齐输出我的代码实现…

Kafka配置SASL/PLAINTEXT安全认证

1、下载安装 Kafka下载地址&#xff1a;Apache Kafka 下载文件 wget https://downloads.apache.org/kafka/3.8.0/kafka_2.12-3.8.0.tgz 文件解压缩 tar -zxvf kafka_2.12-3.8.0.tgz 进入目录 cd kafka_2.12-3.8.0 2、Zookeeper 配置 2.1、修改 Zookeeper 配置文件 con…

go并发设计模式runner模式

go并发设计模式runner模式 真正运行的程序不可能是单线程运行的&#xff0c;go语言中最值得骄傲的就是CSP模型了&#xff0c;可以说go语言是CSP模型的实现。 假设现在有一个程序需要实现&#xff0c;这个程序有以下要求&#xff1a; 程序可以在分配的时间内完成工作&#xff0…

机器学习周志华学习笔记-第13章<半监督学习>

机器学习周志华学习笔记-第13章&#xff1c;半监督学习&#xff1e; 卷王&#xff0c;请看目录 13半监督学习13.1 生成式方法13.2 半监督SVM13.3 基于分歧的方法13.4 半监督聚类 13半监督学习 前面我们一直围绕的都是监督学习与无监督学习&#xff0c;监督学习指的是训练样本包…

DevOps工程技术价值流:GitLab源码管理与提交流水线实践

在当今快速迭代的软件开发环境中&#xff0c;DevOps&#xff08;开发运维一体化&#xff09;已经成为提升软件交付效率和质量的关键。而GitLab&#xff0c;作为一个全面的开源DevOps平台&#xff0c;不仅提供了强大的版本控制功能&#xff0c;还集成了持续集成/持续交付(CI/CD)…

Android笔记【12】脚手架Scaffold和导航Navigation

一、前言 学习课程时&#xff0c;对于自己不懂的点的记录。 对于cy老师第二节课总结。 二、内容 1、PPT介绍scaffold 2、开始代码实操 先新建一个screen包&#xff0c;写一个Homescreen函数&#xff0c;包括四个页面。 再新建一个compenent包&#xff0c;写一个displayText…

动态规划-----路径问题

动态规划-----路径问题 下降最小路径和1&#xff1a;状态表示2&#xff1a;状态转移方程3 初始化4 填表顺序5 返回值6 代码实现 总结&#xff1a; 下降最小路径和 1&#xff1a;状态表示 假设&#xff1a;用dp[i][j]表示&#xff1a;到达[i,j]的最小路径 2&#xff1a;状态转…

C_字符串的一些函数

1.字符串输入函数 scanf("%s",数组名)&#xff1b; gets(数组名)&#xff1b; 区别&#xff1a; scanf(“%s”,数组名); 把空格识别为输入结束 #include <stdio.h>int main() {char a[10];printf("输入&#xff1a;");scanf("%s",a)…

【数据事务】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…

Zookeeper集群数据是如何同步的?

大家好&#xff0c;我是锋哥。今天分享关于【Zookeeper集群数据是如何同步的?】面试题。希望对大家有帮助&#xff1b; Zookeeper集群数据是如何同步的? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Zookeeper集群中的数据同步是通过一种称为ZAB&#xff08;Zo…

MySQL需掌握到何种程度?才能胜任工作

大家好&#xff0c;我是袁庭新。星友问&#xff1a;MySQL需要学到什么程度&#xff1f;才能胜任日常的软件开发工作呢&#xff01;以下是一些建议的学习目标和程度&#xff0c;这些目标旨在帮助你在工作中高效地使用MySQL。 数据库的基本概念、MySQL的安装及配置、SQL的概念、S…

HTML 快速上手

目录 一. HTML概念 二. HTML标签 1. 标题标签 2. 段落标签 3. 换行标签 4. 图片标签 5. 超链接标签 6. 表格标签 7. 表单标签 7.1 form 标签 7.2 input 标签 (1) 文本框 (2) 单选框 (3) 密码框 (4) 复选框 (5) 普通按钮 (6) 提交按钮 8. select标签 9. 无语义…

Qt 2D绘图之三:绘制文字、路径、图像、复合模式

参考文章链接: Qt 2D绘图之三:绘制文字、路径、图像、复合模式 绘制文字 除了绘制图形以外,还可以使用QPainter::darwText()函数来绘制文字,也可以使用QPainter::setFont()设置文字所使用的字体,使用QPainter::fontInfo()函数可以获取字体的信息,它返回QFontInfo类对象…

java调用ai模型:使用国产通义千问完成基于知识库的问答

整体介绍&#xff1a; 基于RAG&#xff08;Retrieval-Augmented Generation&#xff09;技术&#xff0c;可以实现一个高效的Java智能问答客服机器人。核心思路是将预先准备的问答QA文档&#xff08;例如Word格式文件&#xff09;导入系统&#xff0c;通过数据清洗、向量化处理…

Java 基于Spring AI RAG组件做AI智能问答_rag检索增强_AI智能问答

基于RAG技术构建高效Java智能问答客服机器人 基于RAG&#xff08;Retrieval-Augmented Generation&#xff09;技术&#xff0c;可以构建高效的Java智能问答客服机器人。首先&#xff0c;通过向量化处理将Word格式的问答QA文档转换为机器可理解的形式&#xff0c;并存储于Vect…

顶刊算法 | 鱼鹰算法OOA-BiTCN-BiGRU-Attention多输入单输出回归预测(Maltab)

顶刊算法 | 鱼鹰算法OOA-BiTCN-BiGRU-Attention多输入单输出回归预测&#xff08;Maltab&#xff09; 目录 顶刊算法 | 鱼鹰算法OOA-BiTCN-BiGRU-Attention多输入单输出回归预测&#xff08;Maltab&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实…

Redis+Caffeine 多级缓存数据一致性解决方案

RedisCaffeine 多级缓存数据一致性解决方案 背景 之前写过一篇文章RedisCaffeine 实现两级缓存实战&#xff0c;文章提到了两级缓存RedisCaffeine可以解决缓存雪等问题也可以提高接口的性能&#xff0c;但是可能会出现缓存一致性问题。如果数据频繁的变更&#xff0c;可能会导…

单片机学习笔记 12. 定时/计数器_定时

更多单片机学习笔记&#xff1a;单片机学习笔记 1. 点亮一个LED灯单片机学习笔记 2. LED灯闪烁单片机学习笔记 3. LED灯流水灯单片机学习笔记 4. 蜂鸣器滴~滴~滴~单片机学习笔记 5. 数码管静态显示单片机学习笔记 6. 数码管动态显示单片机学习笔记 7. 独立键盘单片机学习笔记 8…

6.824/6.5840(2024)环境配置wsl2+vscode

本文是经过笔者实践得出的最速の环境配置 首先&#xff0c;安装wsl2和vscode 具体步骤参见Mit6.s081环境配置踩坑之旅WSL2VScode_mit6s081-CSDN博客 接下来开始为Ubuntu(笔者使用的版本依然是20.04)配置go的相关环境 1、更新Ubuntu的软件包 sudo apt-get install build-es…

【排序用法】.NET开源 ORM 框架 SqlSugar 系列

&#x1f4a5; .NET开源 ORM 框架 SqlSugar 系列 &#x1f389;&#x1f389;&#x1f389; 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列…