1. 为什么你需要学会快速适配glibc?
如果你在Linux上跑程序,大概率遇到过这个报错:/lib/x86_64-linux-gnu/libc.so.6: version 'GLIBC_2.34' not found。这感觉就像你拿着最新的iPhone充电线,却想插进一台十年前的安卓手机——接口对不上,电充不进去。这个“接口”就是glibc,全称GNU C Library,它是Linux系统上几乎所有程序运行的基础库。
我刚开始做安全研究那会儿,每次遇到这种问题都头疼。要么得重新编译整个程序,要么就得折腾着升级系统glibc。升级系统glibc风险有多大?这么说吧,我有个同事曾经手滑把Ubuntu 18.04的glibc从2.27升级到2.28,结果系统直接启动不了,最后只能重装。从那以后我就明白,直接动系统的glibc就像在心脏上动手术,一不小心就出人命。
后来做CTF比赛,这个问题更频繁了。远程靶机的glibc版本可能是2.23、2.27、2.31,五花八门。本地调试时如果glibc版本对不上,堆布局、函数偏移全都不一样,本地能打通的exp到了远程就是废纸。那时候我们团队的做法是装一堆虚拟机,Ubuntu 16.04、18.04、20.04各来一个,切换着用。直到我发现patchelf和glibc-all-in-one这个组合,才真正解决了这个痛点。
现在我做AI模型部署也经常用到这个技巧。客户的生产环境可能是CentOS 7,glibc版本2.17,但我们用Ubuntu 22.04开发的程序需要glibc 2.35。总不能要求客户升级系统吧?这时候patchelf就是救星。它能直接修改可执行文件的“基因”,让它适配不同的glibc环境,就像给程序换了个兼容性更强的“心脏”。
2. 环境准备:两个神器的安装与配置
2.1 patchelf:给程序“换心”的手术刀
patchelf是个专门修改ELF文件(Linux可执行文件格式)的工具。你可以把它想象成基因编辑工具,它能修改程序的“遗传信息”——动态链接器路径、库搜索路径等等。安装方法很简单,我推荐从源码编译,这样能确保是最新版本。
先装编译依赖:
sudo apt-get update
sudo apt-get install autoconf automake libtool make g++
然后下载编译patchelf:
git clone https://github.com/NixOS/patchelf
cd patchelf
./bootstrap.sh
./configure
make
sudo make install
编译过程中如果遇到autoreconf: not found,那就是缺了autoconf,按上面的命令安装就行。安装完成后验证一下:
patchelf --version
我这边显示的是patchelf 0.18.0,版本越高功能越全。
2.2 glibc-all-in-one:glibc版本库
如果说patchelf是手术刀,那glibc-all-in-one就是器官库。它帮你收集了各个版本的glibc,不用你自己去编译下载。这个项目维护了一个glibc版本列表,直接从Ubuntu官方源下载,速度很快。
克隆项目并初始化:
git clone https://github.com/matrix1001/glibc-all-in-one
cd glibc-all-in-one
chmod +x update_list download extract
./update_list
运行./update_list后,它会从清华镜像源拉取可用的glibc版本列表。清华源在国内访问速度很快,我实测下载一个glibc包大概就几十秒。查看有哪些版本可用:
cat list
你会看到类似这样的输出:
2.23-0ubuntu11.3_amd64
2.23-0ubuntu11.3_i386
2.27-3ubuntu1.6_amd64
2.27-3ubuntu1.6_i386
2.31-0ubuntu9.9_amd64
2.31-0ubuntu9.9_i386
2.35-0ubuntu3.4_amd64
2.35-0ubuntu3.4_i386
注意版本号后面的_amd64和_i386,这表示架构。现在大部分机器都是x86_64架构,选_amd64就行。如果你在做嵌入式或者老系统兼容,可能需要_i386。
3. 实战操作:三步搞定glibc适配
3.1 第一步:诊断问题,确认glibc版本
遇到程序跑不起来,先别急着动手。我习惯先用ldd和strings做个全面检查。比如有个程序叫myapp,运行时报错说需要GLIBC_2.34,但系统只有2.31。
先看系统当前的glibc版本:
ldd --version
输出可能是:
ldd (Ubuntu GLIBC 2.31-0ubuntu9.9) 2.31
Copyright (C) 2020 Free Software Foundation, Inc.
再用ldd看看程序依赖哪些库:
ldd myapp
输出会显示程序链接了哪些动态库。关键看这两行:
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8c12345000)
/lib64/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007f8c12789000)
这表示程序当前链接的是系统自带的glibc。如果程序自带了一个libc.so.6(比如CTF题目经常这样),你可以用strings查看它的具体版本:
strings ./libc.so.6 | grep "GNU C Library"
输出类似:
GNU C Library (Ubuntu GLIBC 2.34-0ubuntu3.2) stable release version 2.34.
这样就确定了目标版本是2.34。接下来去glibc-all-in-one里找对应的版本。
3.2 第二步:下载需要的glibc版本
回到glibc-all-in-one目录,先看看有没有我们需要的版本:
cd ~/glibc-all-in-one
grep "2.34" list
如果有就直接下载:
./download 2.34-0ubuntu3.2_amd64
下载过程你会看到这样的输出:
Getting 2.34-0ubuntu3.2_amd64
-> Location: https://mirror.tuna.tsinghua.edu.cn/ubuntu/pool/main/g/glibc/libc6_2.34-0ubuntu3.2_amd64.deb
-> Downloading libc binary packag


1245

被折叠的 条评论
为什么被折叠?



