You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于GLIBC 2.25的嵌入式设备堆内存匿名区块分析求助

针对GLIBC 2.25堆内存的离线解析方法

GLIBC 2.25的堆内存以chunk为单位管理,new底层调用malloc分配的缓冲区本质是chunk的用户数据区。要判断缓冲区的分配状态和大小,核心是解析chunk的头部结构,步骤如下:

1. 定位目标缓冲区对应的chunk头部

用户拿到的缓冲区地址是chunk的数据区起始地址,需要往前偏移找到chunk的头部:

  • 64位系统:chunk头部由两个8字节字段(prev_size和size)组成,头部起始地址 = 缓冲区地址 - 16字节
  • 32位系统:chunk头部由两个4字节字段组成,头部起始地址 = 缓冲区地址 - 8字节

如果是从/proc/PID/maps转储的匿名区块文件,先计算缓冲区在dump文件中的偏移:

假设maps中区块起始地址为start_addr,缓冲区地址为buf_addr,则dump文件内的偏移为:offset = buf_addr - start_addr
对应chunk头部在dump文件中的偏移为:header_offset = offset - 16(64位)或header_offset = offset -8(32位)

2. 解析chunk的大小

用十六进制工具读取chunk头部的size字段(第二个字段),该字段低3位是标志位,需剥离后得到实际chunk总大小:

  • 标志位定义:
    • 第0位(P):前一个chunk的分配状态(1=已分配,0=空闲)
    • 第1位(M):当前chunk是否为mmap分配(1=是,0=堆内chunk)
    • 第2位(A):是否属于主分配区(1=是,0=非主分配区)
  • 实际chunk总大小 = size字段值 & ~0x7(忽略低3位)
  • 用户缓冲区大小 = 实际chunk总大小 - 头部长度(64位减16,32位减8)

示例(64位小端序):

从dump文件读取头部的16字节为:00 00 00 00 00 00 00 00 21 00 00 00 00 00 00 00

  • 第二个8字节是size字段,小端序解析为0x21
  • 实际chunk总大小 = 0x21 & ~0x7 = 0x20(32字节)
  • 缓冲区大小 = 0x20 - 16 = 0x10(16字节)

3. 判断缓冲区的分配状态

通过chunk的结构和标志位判断:

  • 已分配状态:
    1. size字段的P位(第0位)通常为1(前一个chunk已分配,避免合并)
    2. 缓冲区起始地址后的内存不是有效的堆内链表指针(即没有fd/bk这类指向其他chunk的地址)
  • 已释放状态:
    1. size字段的P位可能为0(允许和前一个空闲chunk合并)
    2. 缓冲区起始地址后的8字节(64位)或4字节(32位)会有fd指针,指向同空闲链表中的下一个chunk;再往后的对应长度是bk指针,指向链表中的上一个chunk
    3. 若chunk属于tcache(GLIBC 2.23+默认启用的小型空闲缓存),fd指针会指向tcache链表中的下一个空闲chunk

注意事项

  • 先确认设备是32位还是64位:可从/proc/PID/maps的地址长度判断(8位十六进制为32位,12位为64位)
  • 注意字节序:嵌入式设备多为小端序,解析十六进制数据时需反转字节顺序
  • 大内存块(size字段M位为1)是mmap分配的,结构略有差异,空闲时会通过fd_nextsize/bk_nextsize链接

内容的提问来源于stack exchange,提问作者Kokomelom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 07:01:03