debug musl

调试环境搭建 debug musl
可以源码调试 。
运行 setup.sh 将源码及相关动态链接库解压到根目录下 musl 文件夹下,用的时候只需要将对应版本的 libc.so 文件复制到目录下,然后利用运行如下命令修改可执行文件所依赖的 ld 为 libc.so 即可进行源码调试 。
patchelf --set-interpreter ./libc.so ./pwn
另外该项目中的 build.sh 可以自动下载和编译 musl 到根目录下的 musl 文件夹中,建议在 .04 下编译 。
还有一个 gdb 插件可以在使用调试版的 libc.so 时打印堆信息 。安装命令如下:
git clone https://github.com/xf1les/muslheap.gitecho "source /path/to/muslheap.py" >> ~/.gdbinit
插件支持如下命令:
源码阅读环境搭建
在阅读 musl 代码时可以借助 clion 进行代码分析,不过要想让 clion 正确分析 musl 代码需要进行如下配置:
首先最好将 musl 的源码解压到另一个目录下而不是复用前面调试环境用的源码,因为如果在阅读代码时改变了源码的格式会造成调试的时候代码对应错误 。
在用 clion 打开 musl 源码后首先在设置中配置如下命令,注意一定要点命令窗口左上角的箭头将窗口展开后再粘贴,否则格式会出现错误 。
#!/bin/sh## GNU Autotools template, feel free to customize.#which autoreconf >/dev/null && autoreconf --install --force --verbose "${PROJECT_DIR:-..}" 2>&1; /bin/sh "${PROJECT_DIR:-..}/configure"
在构建窗口右键点击重新加载项目 。
中间弹出的窗口不选择清理项目即可 。
此时 clion 虽然可以分析代码,但是分析的不完全,比如下图中的类型就找不到 。
将代码编译一下后就可以正常识别 。
此时 clion 已经可以正常分析代码,比如结构体中成员的大小和偏移都可以分析出来 。
musl heap (musl-1.2.0)
musl libc在内存分配上经历过一次大的改动(1.2.0->1.2.1),其余版本之间变化不大,这里以 1.2.0 版本为例进行分析 。
基本数据结构
mal
static struct {volatile uint64_t binmap;struct bin bins[64];volatile int free_lock[2];} mal;
mal 结构体类似于 glibc 中的 arena ,记录着堆的状态,有三个成员:64位无符号整数,链表头部数组 bins 和锁。
bin
struct bin {volatile int lock[2];struct chunk *head;struct chunk *tail;};
存放空闲 chunk 的双向链表,存放 chunk 从 tail 端放,取 chunk 从 head 端取 。
bin 中的 head 和 tail 初始为 0 ,但是在使用 bin 时一般会先调用,此时如果 bin 为空会将 head 和 tail 设为 &bin[i] - 0x10。
static inline void lock_bin(int i) {lock(mal.bins[i].lock);if (!mal.bins[i].head)mal.bins[i].head = mal.bins[i].tail = BIN_TO_CHUNK(i);}
chunk
struct chunk {size_t psize, csize;struct chunk *next, *prev;};
chunk 头部结构跟 glibc 差不多,不过没有指针,chunk 之间不重用 psize 字段 。
psize 和 csize 字段都有标志位(glibc 只有 size 字段有),但只有一种位于最低位的标志位 (glibc 最低三位都有标志位) 。若 csize 设置标志位(最低位为 1 ),表示 chunk 正在被使用;若没有设置标志位(最低位为 0 ),表示 chunk 已经被释放或者通过 mmap 分配的,需要通过 psize 的标志位来进一步判断 chunk 的状态 。若 psize 设置标志位表示前一个 chunk 正在被使用 。
另外,chunk 的大小关于 0x20 对齐 。