【问题标题】:How to link a program with a "handmade compiled" version of glibc?如何将程序与“手工编译”版本的 glibc 链接?
【发布时间】:2017-06-04 17:36:27
【问题描述】:

首先,由于这是我在 StackOverflow 上提出的第一个问题,因此我没有足够的声誉来包含超过 2 个链接。但是,我需要包含超过 2 个链接才能使我的问题完整且易于理解。这就是为什么我在下面的Gist 中写下所有有问题的参考资料。后来每次看到[XXX],都是指前面提到的Gist中对应的链接。

让我们自己解决这个问题:我面临一个涉及 glibc 的编译问题。

总之,作为我课程的一部分,我有机会学习计算机安全。值得注意的是,我必须深入研究一些 CVE。我选择研究 [GHOST - CVE-2015-0235]:GetHOSTbyxxx 函数中允许远程代码执行的缓冲区溢出。

为此,我想尝试重现 [Qualys 漏洞利用]。 这就是为什么我基于最新的 LTS Ubuntu 发行版 (16.04) 建立一个 Docker 环境,我想在其中编译 [glibc] (2.17) 的易受攻击版本和 [Exim 邮件服务器] 的易受攻击版本(4.77) - 这是 Qualys 漏洞利用中利用的软件。

第一步是下载、编译和安装(在 /usr/local/lib 中)glibc。到目前为止,一切顺利。

为了验证我可以用 gcc 编译一些链接到这个版本的 glibc 的代码,我编译了 Qualys 提供的 [GHOST 漏洞检查],这要归功于以下命令(灵感来自 StackOverflow 的这两个答案:[ 1]和[2]):

gcc vulnerability_check.c -o vulnerability_check \
    -Wl,--rpath=/usr/local/lib \
    -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2

完全没有问题。因此,我尝试编译链接到易受攻击的 glibc 版本的 Exim 邮件服务器。根据与 Exim 邮件服务器相关的文档,可以通过将以下行附加到 Local/Makefile(必须由用户从 src/EDITME 创建)来添加编译标志:

CFLAGS="-Wl,--rpath=/usr/local/lib -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2"

但是,我面临一些“未定义的引用”错误:

/usr/local/lib/libpthread.so.0: undefined reference to `h_errno@GLIBC_PRIVATE'
/usr/local/lib/libpthread.so.0: undefined reference to `__vdso_clock_gettime@GLIBC_PRIVATE'
collect2: error: ld returned 1 exit status
Makefile:517: recipe for target 'eximon.bin' failed

据我了解,这意味着“eximon”源代码中使用的一些符号(h_errno 和clock_gettime),通常定义在共享静态库中,在我编译的glibc 版本中找不到。为了确保它们确实没有被定义,我在 [GHOST 漏洞检查] 代码中添加了对这两个符号的虚拟调用,并对其进行了编译。完全没问题。

我不确定下一步该做什么来跟踪问题的根源。我一直在寻找方法来分析沿 glibc 编译的静态库的内容(nm 似乎可以解决问题)。我尝试深入研究编译工具链的文档,从 gcc 到 ld。我也找到了关于 PatchELF,但我认为这不是我需要的(没有第三方库可以修改)。但是,我既找不到解决方案,也找不到解决方法。

因此,我将不胜感激有关如何将 Exim 与已编译的 glibc 链接、使用编译工具链的正确方法、解决此类编译问题的正确方法的任何建议;或者任何你认为会让我成为更好的程序员的建议。

非常感谢您。

【问题讨论】:

标签: c gcc ld glibc


【解决方案1】:

为了验证我是否可以用 gcc 编译一些链接到这个版本的 glibc 的代码,

没有使用此版本的 glibc 编译和链接代码。

感谢以下命令(灵感来自 StackOverflow 的两个答案:[1] 和 [2]),我编译了 Qualys 提供的 [GHOST 漏洞检查]:

您似乎丢失了参考文献 [1] 和 [2]。

gcc vulnerability_check.c -o vulnerability_check \ -Wl,--rpath=/usr/local/lib \ -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2

上述命令使 GCC 使用 标准 位置来表示 include(即 /usr/include)和 lib(即 /usr/lib),但会安排 GLIBC 的替代版本(来自/usr/local) 将在运行时使用

也就是说,有 3 个不同的步骤:

  1. 使用一些头文件编译源代码
  2. 使用一些.o.so 文件执行(静态)链接和
  3. 在将控制权传递给应用程序之前执行运行时链接/加载。

您只安排了第 3 步来使用您新建的 GLIBC。

要使用新建的 GLIBC(假设它已配置安装到 /usr/local),您应该使用类似:

gcc -o t -nostdlib -nostartfiles -I/usr/local/include \
  /usr/local/lib/crt1.o \
  /usr/local/lib/crti.o \
  $(gcc --print-file-name=crtbegin.o) \
  t.c \
  /usr/local/lib/libc.so.6 \
  /usr/local/lib/libc_nonshared.a \
  /usr/local/lib/ld-linux-x86-64.so.2 \
  $(gcc  --print-file-name=crtend.o) \
  /usr/local/lib/crtn.o \
  -Wl,--rpath=/usr/local/lib \
  -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2`

CFLAGS="-Wl,--rpath=/usr/local/lib -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2"

上面的命令又是错误的:它在静态链接时使用了不匹配的ld-linux.solibc.so.6,并且失败了。

TL;DR:与非标准 GLIBC 的链接很复杂。使用 chroot 环境或虚拟机会更好。

更新:

CFLAGS="-I/usr/local/include -Wl,--rpath=/usr/local/lib -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2"

以上设置意义不大:-Wl,...linker 标志,它们属于 LDFLAGS

LDFLAGS="-nostdlib -nostartfiles /usr/local/lib/crt1.o /usr/local/lib/crti.o $(gcc --print-file-name=crtbegin.o) /usr/local/lib/libc.so.6 /usr/local/lib/libc_nonshared.a /usr/local/lib/ld-linux-x86-64.so.2 $(gcc --print-file-name=crtend.o) /usr/local/lib/crtn.o"
... 哪里不对了 ?

是的。请注意,crti.o、您的对象/来源、libc.so.6crtn.o 的顺序很重要,并且必须完全按照我显示的顺序。

我不相信有任何方法可以通过在LDFLAGS 中指定来实现这种顺序。您需要手动执行命令行,或者为您正在构建的程序大量修改Makefile

真的最好在 chroot 或 VM 中执行此操作。

【讨论】:

  • 首先,感谢您提供如此清晰而详细的回答。我仍然在编译 Exim 时遇到麻烦。我已经修改了相关 Makefile 中的 CFLAGS 和 LDFLAGS 定义如下:CFLAGS="-I/usr/local/include -Wl,--rpath=/usr/local/lib -Wl,--dynamic-linker=/usr/local/lib/ld-linux-x86-64.so.2" LDFLAGS="-nostdlib -nostartfiles /usr/local/lib/crt1.o /usr/local/lib/crti.o $(gcc --print-file-name=crtbegin.o) /usr/local/lib/libc.so.6 /usr/local/lib/libc_nonshared.a /usr/local/lib/ld-linux-x86-64.so.2 $(gcc --print-file-name=crtend.o) /usr/local/lib/crtn.o"...有什么问题吗?
  • 感谢您的更新。我对 -Wl 标志实际上非常愚蠢(在两门课程之间匆忙完成,抱歉)。顺便说一句,我已经开始研究不同的库以链接到您在答案中提到的链接(您有关于 C 编译的参考吗?)。修改 Makefile 绝对不是个人的收获,因此我可能会转向 VM。再次感谢!
猜你喜欢
  • 2013-02-02
  • 2015-09-17
  • 1970-01-01
  • 2014-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-13
相关资源
最近更新 更多