将代码/符号补丁插入动态链接的ELF二进制文件

9
假设我有一个动态链接的 ELF 二进制文件,我想要重定向/替换某些库调用。我知道可以使用 LD_PRELOAD 来实现,但是我希望得到一种更为永久的解决方案,独立于环境,并且适用于 setuid/setgid 二进制文件,这些都是 LD_PRELOAD 无法实现的。
我想做的是从其他对象文件中添加代码(如果需要,可能在新的部分中),并将这些对象文件的符号添加到二进制文件的符号表中,以便新添加的代码版本被用于代替共享库代码。我认为,即使它们在同一个文件中,这些代码也应该能够在运行时按照通常的 PLT 方式解析(值得一提的是,我只关心函数,不关心数据)。
请不要给我类似于“你不想这样做!”或“那不可移植!”的回答。我正在研究一种与略微不兼容的备用共享库实现进行交互的方法。涉及的平台是 i386-linux(即32位)。除非我对可能性的看法是错误的,否则我可以编写一些工具来解析 ELF 文件并执行我的黑客攻击,但我怀疑是否有一种花哨的方式可以使用 GNU 链接器和其他工具来实现这一目的,而无需编写新代码。

我不知道这对你是否有用,但是可以查看“nm”系统命令(你可能已经知道了)。它可以提供关于so文件的相当多的信息。 - Marm0t
哇,LD_PRELOAD技巧看起来很有趣!不过我也在寻找一种在二进制文件中实现它的方法。我的问题是我的二进制文件有一个符号,我的BeagleBone链接器无法解析。 - Chris Watts
3个回答

6
我建议使用ERESI备用链接)项目中的elfsh等工具,如果您想要对ELF文件本身进行工具化。与i386-linux的兼容性不是问题,因为我自己也用它来达到同样的目的。
相关的操作指南在这里

看起来需要一些阅读,但我认为这就是我正在寻找的工具。谢谢! - R.. GitHub STOP HELPING ICE
ERESI有没有任何文档?我找不到任何“入门指南”,示例等。 - R.. GitHub STOP HELPING ICE
仓库中的示例代码可以运行,但是似乎完全没有关于它们如何工作或如何从中学习的文档。我接受您的答案,因为它似乎是最好的选择,而不需要编写新的文档,但如果您找到任何相关文档,请发送给我。 - R.. GitHub STOP HELPING ICE
我觉得这篇教程非常有启发性:http://phrack.org/issues.html?issue=66&id=14&mode=txt - karlphillip
如果有人正在寻找之前的链接(现在已经失效):http://phrack.org/issues/66/14.html#article - anol

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()而不是相信链接器按正确顺序获取库。

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


我正在尝试修改二进制文件,而不是源代码。 - R.. GitHub STOP HELPING ICE

1

我似乎无法仅向此问题添加注释,因此将其发布为“答案”。 对此感到抱歉,只是希望能够帮助其他搜索答案的人。

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


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