将代码/符号修补为动态链接的ELF二进制文件

时间:2010-10-27 04:19:04

标签: c linux elf dynamic-linking binutils

假设我有一个动态链接的ELF二进制文件,我想覆盖/重定向某些库调用。我知道我可以使用LD_PRELOAD执行此操作,但我想要一个在二进制文件中永久存在的解决方案,独立于环境,并且适用于setuid / setgid二进制文件,其中LD_PRELOAD都无法实现。< / p>

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

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

4 个答案:

答案 0 :(得分:5)

我建议elfsh等人。 ERESI项目中的工具,如果您想自己检测ELF文件。与i386-linux的兼容性不是问题,因为我自己也出于同样的目的使用它。

相关的方法是here

答案 1 :(得分:2)

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

答案 2 :(得分:1)

我似乎无法在此问题上添加评论,因此将其发布为&#34;答案&#34;。对此感到抱歉,这样做只是为了帮助其他搜索答案的人。

所以,我似乎有类似的用例,但我明确地发现对现有二进制文件的任何修改都是不可接受的(对我而言),所以我正在寻找独立的代理方法:Proxy shared library (sharedlib, shlib, so) for ELF?

答案 3 :(得分:0)

您可以在程序中处理一些动态链接。特别是阅读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()而不是信任链接器以正确的顺序获取库。

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