9

假设我有一个动态链接的 ELF 二进制文件,并且我想覆盖/重定向某些库调用。LD_PRELOAD我知道我可以用LD_PRELOAD.

我想做的是从其他目标文件中添加代码(如果需要,可能在新的部分中)并将这些目标文件中的符号添加到二进制的符号表中,以便使用新添加的代码版本代替共享库代码。我相信这应该是可能的,而无需在现有代码中实际执行任何重定位;即使它们在同一个文件中,它们也应该能够在运行时以通常的 PLT 方式解决(值得我只关心函数,而不关心数据)。

请不要给我“你不想这样做!”这样的回答。或“那不是便携式的!” 我正在研究的是一种将二进制文件与稍微 ABI 不兼容的备用共享库实现连接的方法。如果重要的话,有问题的平台是 i386-linux(即 32 位)。除非我弄错了什么是可能的,否则我可以编写一些工具来解析 ELF 文件并执行我的 hack,但我怀疑有一种奇特的方法可以使用 GNU 链接器和其他工具来完成此任务而无需编写新代码。

4

4 回答 4

5

I suggest the elfsh et al. tools from the ERESI project, if you want to instrument the ELF files themselves. Compatibility with i386-linux is not a problem, as I've used it myself for the same purpose.

The relevant how-tos are here.

于 2010-10-27T06:36:35.170 回答
2

ld具有--wrap允许您将给定符号替换为malloc您调用的符号的选项__wrap_malloc。有了它,您可以为您感兴趣的函数编写一些存根,并将其链接到相关库。

于 2010-10-27T06:30:13.600 回答
1

您可以处理程序本身中的一些动态链接。阅读 dlsym(3) 的手册页,并阅读 dlopen(3)、dlerror(3) 和 dlclose(3) 以了解其余的动态链接接口。

一个简单的例子——假设我想从 libc 覆盖 dup2(2)。我可以使用以下代码(我们称之为“dltest.c”):

#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dlfcn.h>

int (*prev_dup2)(int oldfd, int newfd);

int dup2(int oldfd, int newfd) {
    printf("DUP2: %d --> %d\n", oldfd, newfd);
    return prev_dup2(oldfd, newfd);
}

int main(void) {
    int i;

    prev_dup2 = dlsym(RTLD_NEXT, "dup2");
    if (!prev_dup2) {
        printf("dlsym failed to find 'dup2' function!\n");
        return 1;
    }
    if (prev_dup2 == dup2) {
        printf("dlsym found our own 'dup2' function!\n");
        return 1;
    }

    i = dup2(1,3);
    if (i == -1) {
        perror("dup2() failed");
    }

    return 0;
}

编译:

gcc -o dltest dltest.c -ldl

静态链接的 dup2() 函数会覆盖库中的 dup2()。即使该函数位于另一个 .c 文件中(并且被编译为单独的 .o),这仍然有效。

如果您的覆盖函数本身是动态链接的,您可能希望使用 dlopen() 而不是信任链接器以正确的顺序获取库。

编辑:我怀疑如果重写库中的不同函数调用重写函数,则调用原始函数而不是重写。我不知道如果一个动态库调用另一个动态库会发生什么。

于 2010-10-27T05:37:02.570 回答
1

我似乎无法对这个问题添加评论,因此将其发布为“答案”。很抱歉,这样做只是希望能帮助其他搜索答案的人。

所以,我似乎有类似的用例,但我明确发现对现有二进制文件的任何修改(对我来说)都是不可接受的,所以我正在寻找独立代理方法:ELF 的代理共享库(sharedlib、shlib、so)?

于 2012-01-20T02:42:44.653 回答