如何本地编译将malloc/free静态链接至二进制(适配Protostar heap3)
从你提供的汇编代码能看出来,malloc和free被直接嵌入到二进制内部(没有通过PLT跳转),而strcpy/puts则保留动态链接的方式。要复现这种环境,同时匹配Protostar使用的旧版dlmalloc(来自早期glibc),可以按以下步骤操作:
方法1:用GCC实现部分静态链接
如果你已经拿到了符合要求的旧版libc静态库,可以通过GCC的链接器参数,强制把malloc/free所在的libc静态链接,同时让其他函数保持动态链接:
gcc your_heap3_source.c -o heap3 -Wl,-Bstatic -lc -Wl,-Bdynamic
参数说明:
-Wl,-Bstatic:告诉链接器,接下来指定的库采用静态链接方式-lc:指定链接包含malloc/free的libc库-Wl,-Bdynamic:恢复默认的动态链接行为,确保后续依赖的库还是保持动态链接
这个命令会把整个libc静态链接,对于复现Protostar的内存布局来说,已经足够匹配挑战要求。
方法2:手动指定旧版静态libc文件
Protostar基于Debian Lenny(使用glibc 2.7左右,内置dlmalloc),你需要获取对应版本的静态libc库(libc.a):
- 可以从Debian归档仓库下载对应版本的
libc6-dev包,提取出libc.a文件 - 更省心的方式是用Docker运行Debian Lenny容器,直接在容器内编译,环境会完全匹配
拿到旧版libc.a后,编译时直接指定这个静态库:
gcc your_heap3_source.c -o heap3 /path/to/old_libc.a -Wl,-Bdynamic
这样链接器会优先使用你指定的旧版静态libc中的malloc/free,其他函数仍保持动态链接。如果你想完全静态编译,加上-static参数即可。
方法3:完全静态编译(最简便的复现方式)
如果不需要区分静态/动态函数,直接用-static参数编译,会把所有依赖(包括libc)都静态嵌入到二进制里,malloc/free自然会被静态包含:
gcc your_heap3_source.c -o heap3 -static
注意:必须在旧版glibc环境(比如Debian Lenny容器)内编译,否则静态链接的malloc/free版本还是和Protostar的dlmalloc不匹配,无法触发目标漏洞。
验证链接效果
编译完成后,用objdump检查汇编代码,确认malloc/free是否静态链接成功:
objdump -d heap3 | grep -E "<malloc>|<free>"
如果输出是直接的内存地址(比如0x08048ff2 <malloc>)而非malloc@plt,就说明静态链接成功了。
内容的提问来源于stack exchange,提问作者pret3nti0u5

