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

问题描述:

假设我有一个动态链接的ELF二进制文件,并且我想覆盖/重定向某些库调用。我知道我可以用LD_PRELOAD来做到这一点,但我想要一个在二进制文件中永久存在的独立于环境的解决方案,它适用于setuid/setgid二进制文件,其中没有一个可以实现。将代码/符号修补为动态链接的ELF二进制文件

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

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

+0

我不知道这是不是为你工作,但检查'nm'系统命令(你可能已经知道它)。给出了相当多的关于这样的信息。 – Marm0t 2010-10-27 04:32:36

+0

哇,LD_PRELOAD技巧看起来很有趣!我也在寻找一种在二进制文件中执行它的方法。我的问题是我的二进制文件有一个象征,表示我的BeagleBone的链接程序无法解析。 – CJxD 2015-09-28 00:22:10

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

相关的操作方法是here

+0

看起来它需要一些阅读,但我认为这是我正在寻找的工具。谢谢! – 2010-10-27 06:40:29

+0

ERESI有*任何*文件吗?我找不到任何“入门”,例子等。 – 2010-10-29 04:41:07

+0

嗯,看起来像没有(所有链接指向svn?)。 – 2010-10-29 07:43:21

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

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

+0

我想修改二进制文件,而不是源文件。 – 2010-10-27 05:48:26

ld可以选择--wrap,它可以让您用符号malloc代替给定的符号,您可以将其称为__wrap_malloc。因此,您可以为您感兴趣的功能编写一些存根,并将其链接到相关库。

+0

再次,这个问题是关于修补二进制文件,而不是在我编译的程序中包装库调用。 – 2010-10-27 06:38:45

+0

R .:我不明白为什么你不能在你提出的问题中问你提出的问题。 '__wrap_malloc'不需要调用旧的'malloc',它只是用另一个符号替换一个符号。 'ld'是处理我知道的二进制文件,便携式,灵活的所有你需要的最好的工具。但是你似乎在你的脑海中有某些类型的答案,这并不一定反映在你的问题中。 – 2010-10-27 06:54:32

+0

如果您的意思是有一种方法可以使用现有的可执行ELF文件并添加代码来定义一些符号,否则这些符号将被解析为共享库代码,只使用GNU'ld',我很想知道如何。但请注意,这需要应用的输入程序是可执行的ELF文件,而不是'.o'文件或源文件。 – 2010-10-27 08:23:19

我似乎不能仅仅为此问题添加评论,因此将其张贴为“答案”。很抱歉,这样做只是希望帮助其他搜索答案的人。

所以,我似乎也有类似的用例,但我明确地找到任何修改不能接受(对我来说)现有的二进制文件,所以我在寻找独立代理方式:Proxy shared library (sharedlib, shlib, so) for ELF?