有没有一种方法可以将Linux共享库加载到特定的内存位置?

3
我有一个Linux应用程序,运行时加载一些非常小的共享库(几个小函数)。因为各种重要的原因,我需要将共享库加载到特定的虚拟内存范围中。然而,dlopen()不提供任何方法(我所知道的)来告诉它或提示它将加载的内容放在哪里。
是否有一种方法可以告诉 dlopen() 应该放置它加载的库的位置?
是否有一些替代 dlopen() 的方式,可以提供这个功能?

1
我不这么认为,如果真的有这样的函数,那么它将对用户模式应用程序造成巨大的安全影响。假设确实存在这样的函数,你将如何在特定内存位置调用库中的函数? - Elliott Frisch
1
@ElliottFrisch 如果设计合理并检查了调用者是否已经使用了地址空间,那么“巨大的安全影响”会是什么?mmap允许调用者指定所需的地址,并且这并没有引起任何灾难。Windows允许共享库指定自己的首选基址(不保证),而没有“巨大的安全影响”(ASLR的有效性在Windows中有所降低,因为Windows倾向于在每个进程中加载所有DLL时使用相同的地址,但这是为了操作系统可以节省内存,而不是因为DLL可以具有首选映像基址)。 - nobody
2
如果攻击者可以覆盖您的内存,他们已经获胜了。在特定地址加载库不会产生任何实质性差异。是的,这使事情变得稍微容易一些,但我不会称之为“巨大”。我会将该标签保留给允许内存覆盖的问题。 - nobody
-1,因为您还没有编辑您的问题以改善它,并解释真正的动机和目标。 - Basile Starynkevitch
1
如果真正的问题是例如模拟现有库或覆盖现有函数,那么有其他方法可以做到这一点,而不是在现有代码之上加载库。 - nos
显示剩余6条评论
3个回答

2

您需要明确实际要解决的问题。

由于各种重要原因,我只能理解这个声明是被请求给您的,而且您无法对此进行任何争议。

关于您的问题:
加载地址已经被指定,所以您不能通过这些库来更改它。实际上,您需要了解关于PIC的知识。
我认为你想做的唯一方法就是“黑客”这些库并修改文本段。
请查看specify-preferred-load-address

老实说,您应该在这里解释您要解决的问题,这样您就可以得到帮助您以各种方式解决问题的答案。也就是说,您可以获得另一个选项作为解决方案。


2
我认为,如果您愿意修改库文件,prelink程序实际上可能展示了一种方法来实现这一点。目标是修改库文件,使其具有首选地址。 prelink的意图是为了提高性能,但我的怀疑是它可以被修改以适用于您的用例。 请注意,您永远无法保证在一般情况下会发生这种情况,但在受控情况下,您可能能够保证它会发生。 当然,检查prelink将使您了解elf涉及的部分,并更加明智地确定是否可能。 http://en.wikipedia.org/wiki/Prelink# 或者请参阅Debian中源代码的http://packages.qa.debian.org/prelink

0

你不能这样做,并且在最新的Linux系统上,dlopen(甚至任何没有MAP_FIXEDmmap)都受到ASLR的影响。

因此,即使您成功地在某个固定地址执行等效的dlopen,除非您在整个系统范围内禁用ASLR,否则您的方法将失败。

特别地,在 Linux 上,同一程序进行相同的dlopen的两次“相同”运行将进入(即dlopen的共享库将进入)可能不同的地址。

此外,在 Linux 上,您可以dlopen大量(至少数十万个)的共享对象。请参见我的 manydl.c 作为一个示例。

正如我评论中所说,你的问题看起来像一个XY 问题。你应该解释一下你想要这样做的原因。真正的动机和总体目标是什么?

你可以通过处理 ELF 共享对象文件并自行进行重定位,重新实现已修改的 dlopen。你还需要编译和链接你的共享对象。

如果函数简单且小(并且如果您接受与使用gcc -fPIC -O2 -shared -Wall编译的小型共享库相比性能略有下降),您可以考虑使用一些JIT编译库,例如libjitGNU lightingasmjitLLVM等,在某个固定地址生成机器代码(或者仅生成对真实共享库函数的调用或跳转)

顺便说一下,您可以使用并根据自己的需求适应musl-libc(它包括一个dlopen函数,您可以将其移植到自己的需求中)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接