我可以骗libc (GLIBC_2.13)加载它没有的符号吗?

时间:2022-02-26 15:28:51

In my attempt to get "Steam for Linux" working on Debian, I've run into an issue. libcef (Chromium Embedded Framework) works fine with GLIBC_2.13 (which eglibc on Debian testing can provide), but requires one pesky little extra function from GLIBC_2.15 (which eglibc can't provide):

在我试图让“Steam for Linux”开发Debian时,我遇到了一个问题。libcef (Chromium嵌入式框架)适用于GLIBC_2.13(在Debian测试中可以提供),但是需要一个来自GLIBC_2.15 (eglibc无法提供)的额外的额外功能:

$ readelf -s libcef.so | grep -E "@GLIBC_2\.1[4567]"
1037: 00000000     0 FUNC    GLOBAL DEFAULT  UND __fdelt_chk@GLIBC_2.15 (49)
2733: 00000000     0 FUNC    GLOBAL DEFAULT  UND __fdelt_chk@@GLIBC_2.15

My plan of attack here was to LD_PRELOAD a shim library that provides just these functions. This doesn't seem to work. I really want to avoid installing GLIBC_2.17 (since it is in Debian experimental; even Debian sid still has GLIBC_2.13).

我在这里的攻击计划是LD_PRELOAD一个提供这些函数的shim库。这似乎行不通。我真的不想安装GLIBC_2.17(因为它在Debian experimental;甚至Debian sid也有GLIBC_2.13)。


This is what I've tried.

这是我试过的。

fdelt_chk.c is basically stolen from the GNU C library:

fdelt_chk。c基本上是从GNU c库偷来的:

#include <sys/select.h>

# define strong_alias(name, aliasname) _strong_alias(name, aliasname)
# define _strong_alias(name, aliasname) \
  extern __typeof (name) aliasname __attribute__ ((alias (#name)));

unsigned long int
__fdelt_chk (unsigned long int d)
{
  if (d >= FD_SETSIZE)
    __chk_fail ();

  return d / __NFDBITS;
}
strong_alias (__fdelt_chk, __fdelt_warn)

My Versions script looks as follows:

我的版本脚本如下:

GLIBC_2.15 {
    __fdelt_chk; __fdelt_warn;
};

I then build the library as follows:

然后,我构建了以下的库:

$ gcc -m32 -c -fPIC fdelt_chk.c -o fdelt_chk.o
$ gcc -m32 -shared -nostartfiles -Wl,-s -Wl,--version-script Versions -o fdelt_chk.so fdelt_chk.o

However, if I then run Steam (with a bunch of extra stuff to get it working in the first place), the loader still refuses to find the symbol:

但是,如果我运行Steam(一开始有很多额外的东西让它工作),加载程序仍然拒绝找到符号:

% LD_LIBRARY_PATH="/home/tinctorius/.local/share/Steam/ubuntu12_32" LD_PRELOAD=./fdelt_chk.so:./steamui.so ./steam 
./steam: /lib/i386-linux-gnu/i686/cmov/libc.so.6: version `GLIBC_2.15' not found (required by /home/tinctorius/.local/share/Steam/ubuntu12_32/libcef.so)    

However, the version symbol is also provided by the .so I just built:

但是版本符号也是由the提供的,所以我刚建了:

% readelf -s fdelt_chk.so

Symbol table '.dynsym' contains 8 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FUNC    GLOBAL DEFAULT  UND __chk_fail@GLIBC_2.3.4 (3)
     2: 0000146c     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
     3: 0000146c     0 NOTYPE  GLOBAL DEFAULT  ABS _end
     4: 00000310    44 FUNC    GLOBAL DEFAULT   11 __fdelt_warn@@GLIBC_2.15
     5: 00000310    44 FUNC    GLOBAL DEFAULT   11 __fdelt_chk@@GLIBC_2.15
     6: 00000000     0 OBJECT  GLOBAL DEFAULT  ABS GLIBC_2.15
     7: 0000146c     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start

At this point, I don't know what I can do to trick the loader (who?) into choosing my symbols. Am I going in the right direction at all?

在这一点上,我不知道我能做什么来欺骗加载程序(谁?)选择我的符号。我的方向是正确的吗?

2 个解决方案

#1


9  

I ran into this same problem, though not with Steam. What I was trying to run wanted 2.15 for fdelt_chk while my system had 2.14. I found a solution for simple cases like ours where we can easily provide our own implementation for the missing functionality.

我遇到了同样的问题,虽然不是用蒸汽。我要运行的是fdelt_chk的2.15,而我的系统是2.14。我为像我们这样的简单案例找到了一个解决方案,我们可以很容易地为丢失的功能提供我们自己的实现。

I started out from your attempted solution of implementing the functionality and LD_PRELOADing it. Using LD_DEBUG=all (as suggested by osgx) showed that the linker was still looking for 2.15, so just having the right symbol wasn't enough and there was some other versioning mechanism somewhere. I noticed that objdump -p and readelf -V both showed references to 2.15, so I looked up documentation on ELF and found information on version requirements.

我从您尝试的实现功能和LD_PRELOADing解决方案开始。使用LD_DEBUG=all(如osgx建议的那样)表明链接器仍在寻找2.15,因此仅拥有正确的符号是不够的,而且还存在其他版本控制机制。我注意到objdump -p和readelf -V都显示了对2.15的引用,所以我查找了ELF文档并找到了关于版本需求的信息。

So my new goal was to transform references to 2.15 into references to something else. It seemed reasonable that I could just overwrite structures that referred to 2.15 with the structures that referred to some lower version, like 2.1. In the end, after some trial and error, I found just editing the right Elfxx_Vernaux(es?) in .gnu.version_r was sufficient, but caveat hacker, I guess.

所以我的新目标是将2。15的引用转换为其他引用。似乎合理的是,我可以用引用较低版本(如2.1)的结构来覆盖引用了2.15的结构。最后,在经过一些尝试和错误之后,我发现在.gnu中编辑右Elfxx_Vernaux(es?)version_r已经足够了,但是我猜是hacker得到了告诫。

The .gnu.version_r section is a list of 16-byte Elfxx_Verneeds and 16-byte Elfxx_Vernauxes. Each Elfxx_Verneed entry is followed by the associated Elfxx_Vernauxes. As far as I could tell, vn_file is actually how many associated Elfxx_Vernauxes there are, even though the docs say number of associated verneed array entries. It might just be a misunderstanding on my part, though.

.gnu。version_r部分是16字节的Elfxx_Verneeds和16字节的Elfxx_Vernauxes的一个列表。每个Elfxx_Verneed条目后面跟着关联的Elfxx_Vernauxes。据我所知,vn_file实际上是有多少关联的Elfxx_Vernauxes,尽管文档中说有多少关联的verneed数组条目。不过,这可能只是我的一个误解。

So, to start off making the edits, let's look at some of the info from readelf -V. I snipped out parts we don't care about.

那么,为了开始编辑,让我们看看一些来自readelf -V的信息。我剪掉了我们不关心的部分。

$ readelf -V mybinary
<snip stuff before .gnu.version_r>
Version needs section '.gnu.version_r' contains 5 entries:
 Addr: 0x00000000000021ac  Offset: 0x0021ac  Link: 4 (.dynstr)
<snip libraries that don't refer to GLIBC_2.15>
  0x00c0: Version: 1  File: libc.so.6  Cnt: 10
  0x00d0:   Name: GLIBC_2.3  Flags: none  Version: 19
  0x00e0:   Name: GLIBC_2.7  Flags: none  Version: 16
  0x00f0:   Name: GLIBC_2.2  Flags: none  Version: 15
  0x0100:   Name: GLIBC_2.2.4  Flags: none  Version: 14
  0x0110:   Name: GLIBC_2.1.3  Flags: none  Version: 13
  0x0120:   Name: GLIBC_2.15  Flags: none  Version: 12
  0x0130:   Name: GLIBC_2.4  Flags: none  Version: 10
  0x0140:   Name: GLIBC_2.1  Flags: none  Version: 9
  0x0150:   Name: GLIBC_2.3.4  Flags: none  Version: 4
  0x0160:   Name: GLIBC_2.0  Flags: none  Version: 2

From this we see that the section starts at 0x21ac. Each file listed will have a Elfxx_Verneed followed by an Elfxx_Vernaux for each of the subentries (like GLIBC_2.3). I assume the order of the info in the output will always match the order in the file since readelf is just dumping the structures. Here's my entire .gnu.version_r section.

从这里我们看到,这个部分从0x21ac开始。列出的每个文件都有一个Elfxx_Verneed,每个子条目后面都有一个Elfxx_Vernaux(如GLIBC_2.3)。我假设输出中的信息的顺序总是与文件中的顺序匹配,因为readelf只是转储结构。这是我整个.gnu。version_r部分。

000021A0                                          01 00 02 00
000021B0   A3 0C 00 00  10 00 00 00  30 00 00 00  11 69 69 0D
000021C0   00 00 11 00  32 0D 00 00  10 00 00 00  10 69 69 0D
000021D0   00 00 0B 00  3C 0D 00 00  00 00 00 00  01 00 02 00
000021E0   BE 0C 00 00  10 00 00 00  30 00 00 00  13 69 69 0D
000021F0   00 00 08 00  46 0D 00 00  10 00 00 00  10 69 69 0D
00002200   00 00 07 00  3C 0D 00 00  00 00 00 00  01 00 02 00
00002210   99 0C 00 00  10 00 00 00  30 00 00 00  11 69 69 0D
00002220   00 00 06 00  32 0D 00 00  10 00 00 00  10 69 69 0D
00002230   00 00 05 00  3C 0D 00 00  00 00 00 00  01 00 02 00
00002240   AE 0C 00 00  10 00 00 00  30 00 00 00  11 69 69 0D
00002250   00 00 12 00  32 0D 00 00  10 00 00 00  10 69 69 0D
00002260   00 00 03 00  3C 0D 00 00  00 00 00 00  01 00 0A 00
00002270   FF 0C 00 00  10 00 00 00  00 00 00 00  13 69 69 0D
00002280   00 00 13 00  46 0D 00 00  10 00 00 00  17 69 69 0D
00002290   00 00 10 00  50 0D 00 00  10 00 00 00  12 69 69 0D
000022A0   00 00 0F 00  5A 0D 00 00  10 00 00 00  74 1A 69 09
000022B0   00 00 0E 00  64 0D 00 00  10 00 00 00  73 1F 69 09
000022C0   00 00 0D 00  70 0D 00 00  10 00 00 00  95 91 96 06
000022D0   00 00 0C 00  7C 0D 00 00  10 00 00 00  14 69 69 0D
000022E0   00 00 0A 00  87 0D 00 00  10 00 00 00  11 69 69 0D
000022F0   00 00 09 00  32 0D 00 00  10 00 00 00  74 19 69 09
00002300   00 00 04 00  91 0D 00 00  10 00 00 00  10 69 69 0D
00002310   00 00 02 00  3C 0D 00 00  00 00 00 00

To briefly talk about the structure here, it starts out with an Elfxx_Verneed. As per the docs, we can see there will be 2 Elfxx_Vernauxes, one offset 16 bytes, and the next Elfxx_Verneed is offset 48 bytes. These offsets are from the start of the current structure. It looks like technically the associated Elfxx_Vernauxes might not be adjacent after the current Elfxx_Verneed but it was actually so in all the files I poked around in.

简单地说一下这里的结构,它以Elfxx_Verneed开始。根据文档,我们可以看到有两个Elfxx_Vernauxes,一个偏移量为16字节,下一个Elfxx_Verneed偏移量为48字节。这些偏移量是从当前结构开始的。从技术上看,在当前的Elfxx_Verneed之后,关联的elfxx_vernaux可能不相邻,但实际上它在我所有的文件中都是如此。

From this we can find the file we want (libc.so.6) in a few different ways. Cross reference the string (which I won't get into), find the Elfxx_Verneed with a count of 0A 00 (10, matching our readelf output above), or find the last Elfxx_Verneed since it's the last one readelf output. In any case, the right one for my file is at 0x226C. Its first Elfxx_Vernaux starts at 0x227C.

从这里,我们可以以几种不同的方式找到我们想要的文件(libc.so.6)。交叉引用该字符串(我将不会进入),找到Elfxx_Verneed,计数为0A 00(10,匹配我们的readelf输出),或者找到最后一个Elfxx_Verneed,因为它是最后一个readelf输出。无论如何,我的文件的正确位置是0x226C。它的第一个Elfxx_Vernaux从0x227C开始。

We want to find the Elfxx_Vernaux with a version of 0C 00 (12, again matching our readelf output above). We see the Elfxx_Vernaux that matches is at 0x22CC and the entire structure is 95 91 96 06 00 00 0C 00 7C 0D 00 00 10 00 00 00. We'll be overwriting the first 12 bytes so as to leave the offset alone. We're only modifying the data, not moving around the structures, after all.

我们希望找到Elfxx_Vernaux的0C 00版本(12,再次匹配上面的readelf输出)。我们看到匹配的Elfxx_Vernaux在0x22CC,整个结构是95 91 96 06 00 00 0C 00 7C 0D 00 10 00。为了不影响偏移量,我们将覆盖前12个字节。我们只是在修改数据,而不是在结构中移动。

To pick the data to overwrite with, we just copy it from a different Elfxx_Vernaux for a version of glibc we can satisfy. I picked one for 2.1, which is at 0x22EC in my file, with the data 11 69 69 0D 00 00 09 00 32 0D 00 00 10 00 00 00. So take the first 12 bytes from this and overwrite the first 12 bytes above, and that's it for the hex editing.

要选择要覆盖的数据,我们只需将其从不同的Elfxx_Vernaux中复制到glibc的版本中即可。我为2.1选择了一个,在我的文件中是0x22EC,数据是11 69 69 69 0D 00 00 09 32 0D 00 10 00。从这里取前12个字节,覆盖上面的前12个字节,这就是十六进制编辑。

Of course, you might have multiple references to deal with. Your program might have multiple binaries to edit.

当然,您可能需要处理多个引用。您的程序可能有多个二进制文件需要编辑。

At this point, our program still won't run. But instead of being told something like GLIBC_2.15 not found it should complain about missing __fdelt_chk. Now we do the shim and LD_PRELOADing described in the question, except instead of versioning our implementation as 2.15, we use the version we picked while hex editing. At this point the program should run.

在这一点上,我们的程序仍然不会运行。但是,与其被告知GLIBC_2.15没有找到它,还不如抱怨缺少__fdelt_chk。现在我们执行问题中描述的shim和LD_PRELOADing,除了不将实现版本设置为2.15之外,我们使用十六进制编辑时选择的版本。此时程序应该运行。

This method depends on being able to provide an implementation for whatever's missing. Our __fdelt_chk is extremely simple but I don't doubt that in some cases providing an implementation could be more difficult than just upgrading the system's libc instead.

此方法依赖于能够为所缺少的内容提供实现。我们的__fdelt_chk非常简单,但是我不怀疑在某些情况下提供实现可能比仅仅升级系统的libc要困难。

#2


7  

For what it's worth, the __fdelt_chk function is related to the FORTIFY_SOURCE feature which was added in glibc 2.15. It enables compile-time and run-time checking for buffer overflows.

值得注意的是,__fdelt_chk函数与在glibc 2.15中添加的FORTIFY_SOURCE特性有关。它支持编译时和运行时检查缓冲区溢出。

If you were able to recompile with the following CFLAGS added, it would build a backwards compatible binary without the extra checking:

如果您能够重新编译添加了以下CFLAGS,它将构建一个向后兼容的二进制文件,而不需要额外的检查:

-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0

#1


9  

I ran into this same problem, though not with Steam. What I was trying to run wanted 2.15 for fdelt_chk while my system had 2.14. I found a solution for simple cases like ours where we can easily provide our own implementation for the missing functionality.

我遇到了同样的问题,虽然不是用蒸汽。我要运行的是fdelt_chk的2.15,而我的系统是2.14。我为像我们这样的简单案例找到了一个解决方案,我们可以很容易地为丢失的功能提供我们自己的实现。

I started out from your attempted solution of implementing the functionality and LD_PRELOADing it. Using LD_DEBUG=all (as suggested by osgx) showed that the linker was still looking for 2.15, so just having the right symbol wasn't enough and there was some other versioning mechanism somewhere. I noticed that objdump -p and readelf -V both showed references to 2.15, so I looked up documentation on ELF and found information on version requirements.

我从您尝试的实现功能和LD_PRELOADing解决方案开始。使用LD_DEBUG=all(如osgx建议的那样)表明链接器仍在寻找2.15,因此仅拥有正确的符号是不够的,而且还存在其他版本控制机制。我注意到objdump -p和readelf -V都显示了对2.15的引用,所以我查找了ELF文档并找到了关于版本需求的信息。

So my new goal was to transform references to 2.15 into references to something else. It seemed reasonable that I could just overwrite structures that referred to 2.15 with the structures that referred to some lower version, like 2.1. In the end, after some trial and error, I found just editing the right Elfxx_Vernaux(es?) in .gnu.version_r was sufficient, but caveat hacker, I guess.

所以我的新目标是将2。15的引用转换为其他引用。似乎合理的是,我可以用引用较低版本(如2.1)的结构来覆盖引用了2.15的结构。最后,在经过一些尝试和错误之后,我发现在.gnu中编辑右Elfxx_Vernaux(es?)version_r已经足够了,但是我猜是hacker得到了告诫。

The .gnu.version_r section is a list of 16-byte Elfxx_Verneeds and 16-byte Elfxx_Vernauxes. Each Elfxx_Verneed entry is followed by the associated Elfxx_Vernauxes. As far as I could tell, vn_file is actually how many associated Elfxx_Vernauxes there are, even though the docs say number of associated verneed array entries. It might just be a misunderstanding on my part, though.

.gnu。version_r部分是16字节的Elfxx_Verneeds和16字节的Elfxx_Vernauxes的一个列表。每个Elfxx_Verneed条目后面跟着关联的Elfxx_Vernauxes。据我所知,vn_file实际上是有多少关联的Elfxx_Vernauxes,尽管文档中说有多少关联的verneed数组条目。不过,这可能只是我的一个误解。

So, to start off making the edits, let's look at some of the info from readelf -V. I snipped out parts we don't care about.

那么,为了开始编辑,让我们看看一些来自readelf -V的信息。我剪掉了我们不关心的部分。

$ readelf -V mybinary
<snip stuff before .gnu.version_r>
Version needs section '.gnu.version_r' contains 5 entries:
 Addr: 0x00000000000021ac  Offset: 0x0021ac  Link: 4 (.dynstr)
<snip libraries that don't refer to GLIBC_2.15>
  0x00c0: Version: 1  File: libc.so.6  Cnt: 10
  0x00d0:   Name: GLIBC_2.3  Flags: none  Version: 19
  0x00e0:   Name: GLIBC_2.7  Flags: none  Version: 16
  0x00f0:   Name: GLIBC_2.2  Flags: none  Version: 15
  0x0100:   Name: GLIBC_2.2.4  Flags: none  Version: 14
  0x0110:   Name: GLIBC_2.1.3  Flags: none  Version: 13
  0x0120:   Name: GLIBC_2.15  Flags: none  Version: 12
  0x0130:   Name: GLIBC_2.4  Flags: none  Version: 10
  0x0140:   Name: GLIBC_2.1  Flags: none  Version: 9
  0x0150:   Name: GLIBC_2.3.4  Flags: none  Version: 4
  0x0160:   Name: GLIBC_2.0  Flags: none  Version: 2

From this we see that the section starts at 0x21ac. Each file listed will have a Elfxx_Verneed followed by an Elfxx_Vernaux for each of the subentries (like GLIBC_2.3). I assume the order of the info in the output will always match the order in the file since readelf is just dumping the structures. Here's my entire .gnu.version_r section.

从这里我们看到,这个部分从0x21ac开始。列出的每个文件都有一个Elfxx_Verneed,每个子条目后面都有一个Elfxx_Vernaux(如GLIBC_2.3)。我假设输出中的信息的顺序总是与文件中的顺序匹配,因为readelf只是转储结构。这是我整个.gnu。version_r部分。

000021A0                                          01 00 02 00
000021B0   A3 0C 00 00  10 00 00 00  30 00 00 00  11 69 69 0D
000021C0   00 00 11 00  32 0D 00 00  10 00 00 00  10 69 69 0D
000021D0   00 00 0B 00  3C 0D 00 00  00 00 00 00  01 00 02 00
000021E0   BE 0C 00 00  10 00 00 00  30 00 00 00  13 69 69 0D
000021F0   00 00 08 00  46 0D 00 00  10 00 00 00  10 69 69 0D
00002200   00 00 07 00  3C 0D 00 00  00 00 00 00  01 00 02 00
00002210   99 0C 00 00  10 00 00 00  30 00 00 00  11 69 69 0D
00002220   00 00 06 00  32 0D 00 00  10 00 00 00  10 69 69 0D
00002230   00 00 05 00  3C 0D 00 00  00 00 00 00  01 00 02 00
00002240   AE 0C 00 00  10 00 00 00  30 00 00 00  11 69 69 0D
00002250   00 00 12 00  32 0D 00 00  10 00 00 00  10 69 69 0D
00002260   00 00 03 00  3C 0D 00 00  00 00 00 00  01 00 0A 00
00002270   FF 0C 00 00  10 00 00 00  00 00 00 00  13 69 69 0D
00002280   00 00 13 00  46 0D 00 00  10 00 00 00  17 69 69 0D
00002290   00 00 10 00  50 0D 00 00  10 00 00 00  12 69 69 0D
000022A0   00 00 0F 00  5A 0D 00 00  10 00 00 00  74 1A 69 09
000022B0   00 00 0E 00  64 0D 00 00  10 00 00 00  73 1F 69 09
000022C0   00 00 0D 00  70 0D 00 00  10 00 00 00  95 91 96 06
000022D0   00 00 0C 00  7C 0D 00 00  10 00 00 00  14 69 69 0D
000022E0   00 00 0A 00  87 0D 00 00  10 00 00 00  11 69 69 0D
000022F0   00 00 09 00  32 0D 00 00  10 00 00 00  74 19 69 09
00002300   00 00 04 00  91 0D 00 00  10 00 00 00  10 69 69 0D
00002310   00 00 02 00  3C 0D 00 00  00 00 00 00

To briefly talk about the structure here, it starts out with an Elfxx_Verneed. As per the docs, we can see there will be 2 Elfxx_Vernauxes, one offset 16 bytes, and the next Elfxx_Verneed is offset 48 bytes. These offsets are from the start of the current structure. It looks like technically the associated Elfxx_Vernauxes might not be adjacent after the current Elfxx_Verneed but it was actually so in all the files I poked around in.

简单地说一下这里的结构,它以Elfxx_Verneed开始。根据文档,我们可以看到有两个Elfxx_Vernauxes,一个偏移量为16字节,下一个Elfxx_Verneed偏移量为48字节。这些偏移量是从当前结构开始的。从技术上看,在当前的Elfxx_Verneed之后,关联的elfxx_vernaux可能不相邻,但实际上它在我所有的文件中都是如此。

From this we can find the file we want (libc.so.6) in a few different ways. Cross reference the string (which I won't get into), find the Elfxx_Verneed with a count of 0A 00 (10, matching our readelf output above), or find the last Elfxx_Verneed since it's the last one readelf output. In any case, the right one for my file is at 0x226C. Its first Elfxx_Vernaux starts at 0x227C.

从这里,我们可以以几种不同的方式找到我们想要的文件(libc.so.6)。交叉引用该字符串(我将不会进入),找到Elfxx_Verneed,计数为0A 00(10,匹配我们的readelf输出),或者找到最后一个Elfxx_Verneed,因为它是最后一个readelf输出。无论如何,我的文件的正确位置是0x226C。它的第一个Elfxx_Vernaux从0x227C开始。

We want to find the Elfxx_Vernaux with a version of 0C 00 (12, again matching our readelf output above). We see the Elfxx_Vernaux that matches is at 0x22CC and the entire structure is 95 91 96 06 00 00 0C 00 7C 0D 00 00 10 00 00 00. We'll be overwriting the first 12 bytes so as to leave the offset alone. We're only modifying the data, not moving around the structures, after all.

我们希望找到Elfxx_Vernaux的0C 00版本(12,再次匹配上面的readelf输出)。我们看到匹配的Elfxx_Vernaux在0x22CC,整个结构是95 91 96 06 00 00 0C 00 7C 0D 00 10 00。为了不影响偏移量,我们将覆盖前12个字节。我们只是在修改数据,而不是在结构中移动。

To pick the data to overwrite with, we just copy it from a different Elfxx_Vernaux for a version of glibc we can satisfy. I picked one for 2.1, which is at 0x22EC in my file, with the data 11 69 69 0D 00 00 09 00 32 0D 00 00 10 00 00 00. So take the first 12 bytes from this and overwrite the first 12 bytes above, and that's it for the hex editing.

要选择要覆盖的数据,我们只需将其从不同的Elfxx_Vernaux中复制到glibc的版本中即可。我为2.1选择了一个,在我的文件中是0x22EC,数据是11 69 69 69 0D 00 00 09 32 0D 00 10 00。从这里取前12个字节,覆盖上面的前12个字节,这就是十六进制编辑。

Of course, you might have multiple references to deal with. Your program might have multiple binaries to edit.

当然,您可能需要处理多个引用。您的程序可能有多个二进制文件需要编辑。

At this point, our program still won't run. But instead of being told something like GLIBC_2.15 not found it should complain about missing __fdelt_chk. Now we do the shim and LD_PRELOADing described in the question, except instead of versioning our implementation as 2.15, we use the version we picked while hex editing. At this point the program should run.

在这一点上,我们的程序仍然不会运行。但是,与其被告知GLIBC_2.15没有找到它,还不如抱怨缺少__fdelt_chk。现在我们执行问题中描述的shim和LD_PRELOADing,除了不将实现版本设置为2.15之外,我们使用十六进制编辑时选择的版本。此时程序应该运行。

This method depends on being able to provide an implementation for whatever's missing. Our __fdelt_chk is extremely simple but I don't doubt that in some cases providing an implementation could be more difficult than just upgrading the system's libc instead.

此方法依赖于能够为所缺少的内容提供实现。我们的__fdelt_chk非常简单,但是我不怀疑在某些情况下提供实现可能比仅仅升级系统的libc要困难。

#2


7  

For what it's worth, the __fdelt_chk function is related to the FORTIFY_SOURCE feature which was added in glibc 2.15. It enables compile-time and run-time checking for buffer overflows.

值得注意的是,__fdelt_chk函数与在glibc 2.15中添加的FORTIFY_SOURCE特性有关。它支持编译时和运行时检查缓冲区溢出。

If you were able to recompile with the following CFLAGS added, it would build a backwards compatible binary without the extra checking:

如果您能够重新编译添加了以下CFLAGS,它将构建一个向后兼容的二进制文件,而不需要额外的检查:

-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0