我也遇到过同样的问题,不过不是在 Steam 上。我试图运行的东西2.15
for fdelt_chk
虽然我的系统有2.14
。我找到了一个针对像我们这样的简单情况的解决方案,我们可以轻松地为缺少的功能提供我们自己的实现。
我从您尝试实现功能的解决方案开始,LD_PRELOAD
荷兰国际集团它。使用LD_DEBUG=all
(如 osgx 所建议的)表明链接器仍在寻找2.15
,所以仅仅拥有正确的符号是不够的,并且在某处还有其他一些版本控制机制。我注意到objdump -p
and readelf -V
两者都显示了对2.15
,所以我查了一下ELF的文档,发现有关版本要求的信息 http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/symversion.html.
所以我的新目标是将引用转变为2.15
变成对其他东西的引用。我可以覆盖引用的结构似乎是合理的2.15
具有引用某些较低版本的结构,例如2.1
。最后,经过一番尝试和错误,我发现只需编辑正确的Elfxx_Vernaux
(是?) 在.gnu.version_r
已经足够了,但我想还是要注意黑客。
The .gnu.version_r
节是一个16字节的列表Elfxx_Verneed
s 和 16 字节Elfxx_Vernaux
es.每个Elfxx_Verneed
条目后面跟着相关的Elfxx_Vernaux
es.据我所知,vn_file
实际上是有多少关联的Elfxx_Vernaux
有,尽管文档说number of associated verneed array entries
。不过,这可能只是我的一个误会。
因此,为了开始进行编辑,让我们看一下来自的一些信息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
从这里我们看到该部分开始于0x21ac
。列出的每个文件都会有一个Elfxx_Verneed
随后是一个Elfxx_Vernaux
对于每个子条目(例如GLIBC_2.3
)。我假设输出中信息的顺序始终与文件中的顺序匹配,因为readelf
只是倾倒结构。这是我的entire .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
简单说一下这里的结构,首先是一个Elfxx_Verneed
。根据文档,我们可以看到会有 2Elfxx_Vernaux
es,一个偏移16字节,下一个Elfxx_Verneed
偏移量为 48 字节。这些偏移量是从当前结构的开始处开始的。技术上看起来像是相关的Elfxx_Vernaux
es 可能在当前之后不相邻Elfxx_Verneed
但在我翻阅的所有文件中实际上都是如此。
由此我们可以通过几种不同的方式找到我们想要的文件(libc.so.6)。交叉引用字符串(我不会涉及),找到Elfxx_Verneed
计数为0A 00
(10、匹配我们的readelf
上面的输出),或者找到最后一个Elfxx_Verneed
因为这是最后一篇readelf
输出。无论如何,适合我的文件的位置是0x226C
。它的第一个Elfxx_Vernaux
开始于0x227C
.
我们想要找到Elfxx_Vernaux
与一个版本0C 00
(12,再次匹配我们的readelf
输出如上)。我们看到Elfxx_Vernaux
匹配的是0x22CC
整个结构是95 91 96 06 00 00 0C 00 7C 0D 00 00 10 00 00 00
。我们将覆盖前 12 个字节,以便保留偏移量。毕竟,我们只是修改数据,而不是移动结构。
要选择要覆盖的数据,我们只需从不同的地方复制它Elfxx_Vernaux
对于glibc的一个版本我们可以满足。我选了一个2.1
,这是在0x22EC
在我的文件中,包含数据11 69 69 0D 00 00 09 00 32 0D 00 00 10 00 00 00
。因此,从中取出前 12 个字节并覆盖上面的前 12 个字节,这就是十六进制编辑。
当然,您可能有多个参考文献需要处理。您的程序可能有多个二进制文件需要编辑。
此时,我们的程序仍然无法运行。但不是被告知类似的事情GLIBC_2.15 not found
它应该抱怨失踪__fdelt_chk
。现在我们做垫片并LD_PRELOAD
问题中描述的,除了我们的实现版本化为2.15
,我们使用十六进制编辑时选择的版本。此时程序应该运行。
此方法取决于是否能够为缺失的内容提供实现。我们的__fdelt_chk
非常简单,但我毫不怀疑在某些情况下提供实现可能比仅仅升级系统的 libc 更困难。