本文主要是linux下堆的数据结构及堆调试、堆溢出利用的一些基础知识

首先,linux下堆的数据结构如下

/*
This struct declaration is misleading (but accurate and necessary).
It declares a "view" into memory allowing access to necessary
fields at known offsets from a given base. See explanation below.
*/
struct malloc_chunk { INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */ struct malloc_chunk* fd; /* double links -- used only if free. */
struct malloc_chunk* bk; /* Only used for large blocks: pointer to next larger size. */
struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
struct malloc_chunk* bk_nextsize;
};
  • prev_size, 如果该 chunk 的物理相邻的前一地址chunk(两个指针的地址差值为前一chunk大小)是空闲的话,那该字段记录的是前一个 chunk 的大小(包括 chunk 头)。否则,该字段可以用来存储物理相邻的前一个chunk 的数据。这里的前一 chunk 指的是较低地址的 chunk
  • size ,该 chunk 的大小,大小必须是 2 * SIZE_SZ 的整数倍。如果申请的内存大小不是 2 * SIZE_SZ 的整数倍,会被转换满足大小的最小的 2 * SIZE_SZ 的倍数。32 位系统中,SIZE_SZ 是 4;64 位系统中,SIZE_SZ 是 8。 该字段的低三个比特位对 chunk 的大小没有影响,它们从高到低分别表示
    • NON_MAIN_ARENA,记录当前 chunk 是否不属于主线程,1表示不属于,0表示属于。
    • IS_MAPPED,记录当前 chunk 是否是由 mmap 分配的。
    • PREV_INUSE,记录前一个 chunk 块是否被分配。一般来说,堆中第一个被分配的内存块的 size 字段的P位都会被设置为1,以便于防止访问前面的非法内存。当一个 chunk 的 size 的 P 位为 0 时,我们能通过 prev_size 字段来获取上一个 chunk 的大小以及地址。这也方便进行空闲chunk之间的合并。
  • fd,bk。 chunk 处于分配状态时,从 fd 字段开始是用户的数据。chunk 空闲时,会被添加到对应的空闲管理链表中,其字段的含义如下
    • fd 指向下一个(非物理相邻)空闲的 chunk
    • bk 指向上一个(非物理相邻)空闲的 chunk
    • 通过 fd 和 bk 可以将空闲的 chunk 块加入到空闲的 chunk 块链表进行统一管理
  • fd_nextsize, bk_nextsize,也是只有 chunk 空闲的时候才使用,不过其用于较大的 chunk(large chunk)。
    • fd_nextsize 指向前一个与当前 chunk 大小不同的第一个空闲块,不包含 bin 的头指针。
    • bk_nextsize 指向后一个与当前 chunk 大小不同的第一个空闲块,不包含 bin 的头指针。
    • 一般空闲的 large chunk 在 fd 的遍历顺序中,按照由大到小的顺序排列。这样做可以避免在寻找合适chunk 时挨个遍历。

以上内容摘自CTF-WIKI https://ctf-wiki.github.io/ctf-wiki/pwn/heap/heap_structure/#top-chunk

给出一个简单堆溢出的例子

#include <stdio.h>

int main(void)
{
char *chunk;
chunk=malloc();
puts("Get input:");
gets(chunk);
return ;
}

gcc -no-pie -p example1 example1.c编译程序

objdump -d example1查看main函数地址,然后gdb在main函数起始位置下断点。

当执行到0x400589时查看rax内容即为malloc分配堆的起始地址。

执行完0x405a5时 x/10xg 0x602250用‘A'*100覆盖堆查看堆溢出情况(Gdb指令查看手册https://darkdust.net/files/GDB%20Cheat%20Sheet.pdf)

这里查看0x602250的原因是INTERNAL_SIZE_T默认和size_t一致,32位系统下size_t 4字节,64位系统下size_t 8字节。malloc返回的堆地址指针实际是 struct malloc_chunk* fd的fd,所以64位系统下查看堆首需要用返回的堆地址减去16字节的堆头。

我们在重新看一下堆覆盖之前的堆内容

size部分的最后三个字节分别表示特定含义(见上数据结构),用户真正可用的堆地址是0X602260-0X60226F,共16字节。申请24字节分配16字节的原因是32位系统8字节对齐,64位16位对齐;而分配的16字节能够存储24字节的原因是借用了下一块的pre_size域,16+8=24

关于申请内存到实际分配内存的转换

/* pad request bytes into a usable size -- internal version */
//MALLOC_ALIGN_MASK = 2 * SIZE_SZ -1
#define request2size(req) \
(((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) \
? MINSIZE \
: ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)

当申请内存+堆头大于MINSIZE时,返回((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)这个结果。这个结果的意思是(用户申请内存大小+堆头)&~MALLOC_ALIGN_MASK。以64位系统申请24字节堆块为例,24+堆头=40 (101000);MALLOC_ALIGN_MASK 01111取反10000,按位与的结果就是100000了,即32。

这样做可以满足用户申请内存需求的原因是,~(2*SIZE_SZ-1)其实就是操作系统的双字长,比如64位系统就是10000,这样按位与就能保证分配的内存最低4位为0,也就保证了分配堆块的字节对齐。

0X602270是top chunk的内容,top chunk是在第一次执行malloc时heap 会被分为两块,一块给用户,剩下的那块就是 top chunk。top chunk就是当前堆的物理地址最高chunk,这个chunk不属于任何bin。

堆溢出学习笔记(linux)的更多相关文章

  1. Linux学习笔记-Linux系统简介

    Linux学习笔记-Linux系统简介 UNIX与Linux发展史 UNIX是父亲,Linux是儿子. UNIX发行版本 操作系统 公司 硬件平台 AIX IBM PowerPC HP-UX HP P ...

  2. Linux内核分析第七周学习笔记——Linux内核如何装载和启动一个可执行程序

    Linux内核分析第七周学习笔记--Linux内核如何装载和启动一个可执行程序 zl + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study. ...

  3. 大数据学习笔记——Linux基本知识及指令(理论部分)

    Linux学习笔记整理 上一篇博客中,我们详细地整理了如何从0部署一套Linux操作系统,那么这一篇就承接上篇文章,我们仔细地把Linux的一些基础知识以及常用指令(包括一小部分高级命令)做一个梳理, ...

  4. MongoDB学习笔记—Linux下搭建MongoDB环境

    1.MongoDB简单说明 a MongoDB是由C++语言编写的一个基于分布式文件存储的开源数据库系统,它的目的在于为WEB应用提供可扩展的高性能数据存储解决方案. b MongoDB是一个介于关系 ...

  5. shell入门之函数应用 分类: 学习笔记 linux ubuntu 2015-07-10 21:48 77人阅读 评论(0) 收藏

    最近在学习shell编程,文中若有错误的地方还望各位批评指正. 先来看一个简单的求和函数 #!/bin/bash #a test about function f_sum 7 8 function f ...

  6. Linux菜鸟学习笔记--Linux系统结构

      什么是Linux? Linux是一种自由和开放源码的类Unix操作系统,存在着许多不同的Linux版本,但它们都使用了Linux内核.严格来讲,Linux这个词本身只表示Linux内核,但实际上人 ...

  7. 《马哥出品高薪linux运维教程》wingkeung学习笔记-linux基础入门课程

    计算机原理概念: 1.CPU和内存中的存储单元通信线路称为总线(BUS),总线是被指令和数据复用的,所以也称为前端总线. 2.计算机中计算频率的时间标准即晶体振荡器原理,精确计算时间长度,根据相同的时 ...

  8. 大数据学习笔记——Linux完整部署篇(实操部分)

    Linux环境搭建完整操作流程(包含mysql的安装步骤) 从现在开始,就正式进入到大数据学习的前置工作了,即Linux的学习以及安装,作为运行大数据框架的基础环境,Linux操作系统的重要性自然不言 ...

  9. [马哥学习笔记]Linux系统裁剪之制作带网络功能的可启动linux

    知识基础: 系统启动流程:POST-->BIOS(boot sequence)-->GRUB(bootloder(stage1:MBR;stage2:grub目录中))-->kern ...

随机推荐

  1. 迷茫<第三篇:再到北京>

    这是2016年初春,三月的北京仍带着丝丝的冷意,我再次来到了这座熟悉又陌生的城市.我是早上6点钟到的北京西站,坐火车过来的,一夜未眠,眼睛很疲劳.这次过来和上次回长沙一样,下了火车先把行李寄存在朋友家 ...

  2. UE、UI、UCD、UED?职责划分?

    UE.UI.UCD.UED?你知道你是干啥的吗 名词 UE (User Experience) : 用户体验 UI (User Interface) : 用户界面 UCD (User-Centered ...

  3. 《Effective C++》模板与泛型编程:条款32-条款40

    条款41:了解隐式接口和编译期多态 class支持显示接口和运行期多态 class的显示接口由函数的名签式构成(函数名称.参数类型.返回类型) class的多态通过virtual函数发生在运行期 te ...

  4. SQL Server没有足够的内存继续执行程序 (mscorlib)的解决办法

    在Microsoft SQL Server Management Studio 中执行较大的sql脚本时,会报没有足够的内存继续执行程序(mscorlib)的错误.如下图所示 解决方法: 使用sqlc ...

  5. const 本质

    const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动.对于简单类型的数据(数值.字符串.布尔值),值就保存在变量指向的那个内存地址,因此等同于常量.但对于复合类型的数据( ...

  6. [LOJ2310][APIO2017]斑斓之地——可持久化线段树

    题目链接: [APIO2017]斑斓之地 将不是河流的格子染成白色,是河流的格子染成黑色,那么连通块数就是白色格子数$-1*2$的联通白色格子数$-2*1$的联通白色格子数$+2*2$的联通白色格子数 ...

  7. 后缀自动机(SAM)学习笔记

    目录 定义 SAM 的状态集 一些性质 SAM 的后缀链接 SAM 的转移函数 一些性质 算法构造 构造方法 时间复杂度证明 状态的数量 转移的数量 代码实现 实际应用 统计本质不同的子串个数 计算任 ...

  8. 【转】Esp8266学习之旅① 搭建开发环境,开始一个“hellow world”串口打印。

    @2019-02-28 [小记] Esp8266学习之旅① 搭建开发环境,开始一个“hellow world”串口打印.

  9. OpenLayers学习笔记(八)— 类似比例尺的距离环(二)

    openlayers 3 地图上创建一个距离环,始终以地图中心为中心,每个环之间的距离类似比例尺,随地图缩放而变化. 添加具有覆盖整个范围的特征的虚拟层,其可以被设置为围绕地图中心的环. 这篇是上一篇 ...

  10. 时间序列分析模型——ARIMA模型

    时间序列分析模型——ARIMA模型 一.研究目的 传统的经济计量方法是以经济理论为基础来描述变量关系的模型.但经济理论通常不足以对变量之间的动态联系提供一个严密的说明,而且内生变量既可以出现在方程的左 ...