malloc源码调试(二)
字数 2654 2025-09-01 11:26:17

malloc源码调试与利用技术详解

1. unsorted bin处理机制

1.1 last_remainder处理

当malloc请求无法通过fastbin或small bin满足时,会进入unsorted bin处理流程:

  1. 首先检查last_remainder chunk:

    • 必须满足四个条件:
      • 请求大小在small bin范围内
      • last_remainder存在且足够大
      • last_remainder是unsorted bin中唯一的chunk
      • 切割后剩余部分足够形成新的chunk
  2. 切割过程:

    • 计算新的remainder chunk的size和地址
    • 更新unsorted bin链首
    • 为新remainder chunk设置fd和bk指针
    • 更新申请chunk和remainder chunk的size
    • 更新高地址相邻chunk的prev_size

利用点:切割后申请到的chunk上会残留main_arena地址,可用于泄漏libc基址(无UAF时常用技巧)

1.2 unsorted bin chunk移出处理

当不满足last_remainder条件时,会遍历unsorted bin中的chunk:

  1. 检查机制:

    • 双向链表完整性检查
    • prev_size与prev_inuse位一致性检查
  2. 利用技术(off_by_one):

    • 任意修改size值可导致overlapping
    • 示例步骤:
      • 构造堆布局,确保unsorted bin中的chunk被last_remainder标记
      • 伪造size改大,并设置适当的prev_size和chunksize
      • 申请相同size的chunk,造成overlapping
  3. 移出条件:

    • 当chunk size与请求大小完全匹配时:
      • 标记为已使用(设置高地址chunk的prev_inuse=1)
      • 若tcache未满则放入tcache
    • 不匹配时移入small bin或large bin

2. small bin与large bin处理

2.1 small bin处理

  1. 移入过程:

    • 从unsorted bin中取出chunk
    • 在main_arena中找到对应size的small bin链
    • 插入到small bin双向链表尾部
  2. 检查机制:

    • 双向链表完整性检查

2.2 large bin处理与large bin attack

large bin特性

  • 每个large bin链包含一定size范围的chunk
  • 使用fd/bk_nextsize维护跳表结构,保证有序性

large bin attack利用(glibc-2.30+)

  1. 准备条件:

    • 在large bin中放置一个大chunk
    • 在unsorted bin中放置一个较小chunk(同large bin范围)
  2. 攻击步骤(第三种情况利用):

    • 申请更大size触发unsorted bin chunk移入large bin
    • 绕过检查:
      • 高版本对第四种情况有跳表检查
      • 第三种情况无检查
    • 关键赋值:
      • victim->bk_nextsize = fwd->fd->bk_nextsize
      • fwd->fd->bk_nextsize = victim
    • 效果:
      • 可在target_addr+0x20处写入堆地址
      • 多次利用只需修改large bin中最大chunk的bk_nextsize

3. binmap机制与搜索算法

3.1 binmap结构

  • main_arena中bins数组:
    • 前2个为unsorted bin
    • 随后62×2个small bin
    • 最后63×2个large bin
  • binmap数组:
    • 4个无符号整型(128位)
    • 标记125个bin链是否非空

3.2 binmap维护

  • 当chunk从unsorted bin移入small/large bin时更新
  • 示例:
    • 0x20 small bin对应binmap[0]的第3位
    • 0xb0 small bin对应binmap[0]的更高位

3.3 bin搜索算法

  1. 计算起始index
  2. 获取binmap标记:
    • 按bit位从小到大搜索
    • 找到第一个满足size≥请求的bin链
  3. 检查bin链非空
  4. unlink取出chunk进行切割

4. top chunk处理与利用

4.1 常规top chunk切割

  • 当其他bin无法满足时使用top chunk
  • 检查机制:
    • size ≥ 请求大小 + MINSIZE
    • prev_inuse=1
    • 地址页对齐

4.2 House of Force(glibc-2.29前)

  1. 利用条件:
    • 可修改top chunk的size
    • size > av->system_mem检查
  2. 攻击步骤:
    • 改大top chunk size
    • 计算到目标地址的偏移
    • 申请特定大小使top延伸至目标地址
    • 下次分配即可在目标地址创建chunk

4.3 sysmalloc扩容机制

当top chunk不足时:

4.3.1 mmap分配

  • 条件:
    • 请求大小 > 0x2000
    • mmap计数 < 最大值
  • 特点:
    • 不与主分配区连续
    • 不受main_arena管理

4.3.2 brk扩展(主分配区)

  1. 计算扩展大小:
    • nb + top_pad(128K) + MINSIZE对齐
  2. 系统调用sbrk分配
  3. 处理连续性:
    • 若地址不连续可能二次扩容
    • 设置"栅栏"chunk防止合并
  4. 释放原top chunk到unsorted bin
  5. 从新top切割请求chunk

关键点

  • 伪造size可能导致非连续扩展
  • 栅栏设置防止free时错误合并

5. 关键检查与绕过总结

  1. unsorted bin检查

    • 双向链表完整性(fd/bk)
    • prev_size与prev_inuse一致性
  2. large bin检查

    • 跳表完整性(2.30+对部分情况)
    • 解链时对非跳表首项不检查fd_nextsize
  3. top chunk检查

    • size ≤ system_mem(2.29+)
    • prev_inuse=1
    • 地址页对齐
  4. 通用绕过策略

    • 精心构造fake size和prev_size
    • 利用不检查的代码路径(如large bin第三种情况)
    • 控制相邻chunk的元数据

以上内容涵盖了malloc源码调试中的核心处理流程和关键利用技术,包括各种bin的处理机制、安全检查及绕过方法,以及top chunk的特殊处理逻辑。

malloc源码调试与利用技术详解 1. unsorted bin处理机制 1.1 last_ remainder处理 当malloc请求无法通过fastbin或small bin满足时,会进入unsorted bin处理流程: 首先检查last_ remainder chunk: 必须满足四个条件: 请求大小在small bin范围内 last_ remainder存在且足够大 last_ remainder是unsorted bin中唯一的chunk 切割后剩余部分足够形成新的chunk 切割过程: 计算新的remainder chunk的size和地址 更新unsorted bin链首 为新remainder chunk设置fd和bk指针 更新申请chunk和remainder chunk的size 更新高地址相邻chunk的prev_ size 利用点 :切割后申请到的chunk上会残留main_ arena地址,可用于泄漏libc基址(无UAF时常用技巧) 1.2 unsorted bin chunk移出处理 当不满足last_ remainder条件时,会遍历unsorted bin中的chunk: 检查机制: 双向链表完整性检查 prev_ size与prev_ inuse位一致性检查 利用技术(off_ by_ one): 任意修改size值可导致overlapping 示例步骤: 构造堆布局,确保unsorted bin中的chunk被last_ remainder标记 伪造size改大,并设置适当的prev_ size和chunksize 申请相同size的chunk,造成overlapping 移出条件: 当chunk size与请求大小完全匹配时: 标记为已使用(设置高地址chunk的prev_ inuse=1) 若tcache未满则放入tcache 不匹配时移入small bin或large bin 2. small bin与large bin处理 2.1 small bin处理 移入过程: 从unsorted bin中取出chunk 在main_ arena中找到对应size的small bin链 插入到small bin双向链表尾部 检查机制: 双向链表完整性检查 2.2 large bin处理与large bin attack large bin特性 : 每个large bin链包含一定size范围的chunk 使用fd/bk_ nextsize维护跳表结构,保证有序性 large bin attack利用(glibc-2.30+) : 准备条件: 在large bin中放置一个大chunk 在unsorted bin中放置一个较小chunk(同large bin范围) 攻击步骤(第三种情况利用): 申请更大size触发unsorted bin chunk移入large bin 绕过检查: 高版本对第四种情况有跳表检查 第三种情况无检查 关键赋值: victim->bk_ nextsize = fwd->fd->bk_ nextsize fwd->fd->bk_ nextsize = victim 效果: 可在target_ addr+0x20处写入堆地址 多次利用只需修改large bin中最大chunk的bk_ nextsize 3. binmap机制与搜索算法 3.1 binmap结构 main_ arena中bins数组: 前2个为unsorted bin 随后62×2个small bin 最后63×2个large bin binmap数组: 4个无符号整型(128位) 标记125个bin链是否非空 3.2 binmap维护 当chunk从unsorted bin移入small/large bin时更新 示例: 0x20 small bin对应binmap[ 0 ]的第3位 0xb0 small bin对应binmap[ 0 ]的更高位 3.3 bin搜索算法 计算起始index 获取binmap标记: 按bit位从小到大搜索 找到第一个满足size≥请求的bin链 检查bin链非空 unlink取出chunk进行切割 4. top chunk处理与利用 4.1 常规top chunk切割 当其他bin无法满足时使用top chunk 检查机制: size ≥ 请求大小 + MINSIZE prev_ inuse=1 地址页对齐 4.2 House of Force(glibc-2.29前) 利用条件: 可修改top chunk的size 无 size > av->system_mem 检查 攻击步骤: 改大top chunk size 计算到目标地址的偏移 申请特定大小使top延伸至目标地址 下次分配即可在目标地址创建chunk 4.3 sysmalloc扩容机制 当top chunk不足时: 4.3.1 mmap分配 条件: 请求大小 > 0x2000 mmap计数 < 最大值 特点: 不与主分配区连续 不受main_ arena管理 4.3.2 brk扩展(主分配区) 计算扩展大小: nb + top_ pad(128K) + MINSIZE对齐 系统调用sbrk分配 处理连续性: 若地址不连续可能二次扩容 设置"栅栏"chunk防止合并 释放原top chunk到unsorted bin 从新top切割请求chunk 关键点 : 伪造size可能导致非连续扩展 栅栏设置防止free时错误合并 5. 关键检查与绕过总结 unsorted bin检查 : 双向链表完整性(fd/bk) prev_ size与prev_ inuse一致性 large bin检查 : 跳表完整性(2.30+对部分情况) 解链时对非跳表首项不检查fd_ nextsize top chunk检查 : size ≤ system_ mem(2.29+) prev_ inuse=1 地址页对齐 通用绕过策略 : 精心构造fake size和prev_ size 利用不检查的代码路径(如large bin第三种情况) 控制相邻chunk的元数据 以上内容涵盖了malloc源码调试中的核心处理流程和关键利用技术,包括各种bin的处理机制、安全检查及绕过方法,以及top chunk的特殊处理逻辑。