假设我有一个dynamic链接的ELF二进制文件,我想覆盖/redirect某些库调用。 我知道我可以用LD_PRELOAD
来做到这一点,但是我想要一个在二进制文件中永久存在的独立于环境的解决scheme,它可以用于setuid / setgid二进制文件,其中没有一个是LD_PRELOAD
可以实现的。
我想要做的就是从其他目标文件中添加代码(如有必要,可能在新的部分添加代码),并将这些目标文件中的符号添加到二进制文件的符号表中,这样就可以使用新添加的代码版本代替共享库代码。 我相信这应该是可能的,而不需要在现有的代码中进行实际的迁移。 即使它们在同一个文件中,它们应该能够在运行时以通常的PLT方式来parsing(因为我只关心函数,而不关心数据)。
请不要给我答复,“你不想这样做!” 或者“那不是便携的!” 我正在处理的是一种连接二进制文件与ABI不兼容的备用共享库实现的方式。 有问题的平台是i386-linux(即32位)。 除非我误解了什么是可能的,否则我可以编写一些工具来parsingELF文件并执行我的黑客攻击,但我怀疑有一种奇怪的方式来使用GNU链接器和其他工具来完成此操作,而无需编写新代码。
我建议elfsh
等人。 来自ERESI项目的工具,如果你想自己测试ELF文件。 与i386-linux的兼容性不是问题,因为我为了相同的目的而使用它。
相关的方法在这里 。
ld
有一个选项--wrap
,它可以让你使用一个符号来代替malloc
等给定的符号,这个符号可以叫做__wrap_malloc
。 有了这个,你可以为你感兴趣的功能写一些存根,并将其链接到相关的库。
我似乎不能仅仅为这个问题添加评论,所以把它作为“答案”发表。 对不起,这样做只是希望帮助其他搜索答案的人。
所以,我似乎有类似的用例,但我明确地发现任何修改现有的二进制文件是不可接受的(对我来说),所以我正在寻找独立的代理方法: 为ELF代理共享库(sharedlib,shlib,所以)?
你可以在程序中处理一些动态连接。 详细阅读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()而不是信任链接器以正确的顺序获取库。
编辑 :我怀疑如果重写的库内的不同函数调用重写的函数,原始函数被调用,而不是覆盖。 我不知道如果一个动态库调用另一个,会发生什么。