如何将程序与"手工编译" glibc的版本?

时间:2017-01-19 21:02:06

标签: c gcc ld glibc

首先,由于这是我在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 Mail Server。根据与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链接起来的方法,使用编译工具链的正确方法,解决此类编译问题的正确方法,我将不胜感激。或者你认为会让我成为更好的程序员的任何建议。

我非常感谢你。

1 个答案:

答案 0 :(得分:3)

  

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

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

  

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

您似乎丢失了参考文献[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. 执行(静态)链接
  4. 在将控制权传递给应用程序之前执行运行时链接/加载。
  5. 您只安排了第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(在上面的第2步),并且失败了。

    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,...链接器标志,它们属于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 的顺序非常重要,并且必须完全符合我展示的顺序。< / p>

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

    真的最好在chroot或VM中这样做。