Link 带有 c 程序的 ELF 二进制文件

Link an ELF binary with a c program

如果只能访问独立的 ELF 程序,我希望能够从我自己的程序中调用程序中的函数。 假设下面的代码是 main.c

#include <stdio.h>

extern int mystery(int a,int b);

int main() {
        int a = 0;
        int b = 1;
        printf("mystery(a,b) = %d\n",mystery(a,b));
        return 0;
}

函数 mystery 存在于某个 elf 文件 not_my_program 中。 我想做的是

gcc main.c not_my_program

然而,这给了我一个未定义的引用错误 mystery 。我一直在寻找方法 在论坛上发现无法将此 elf 文件转换为共享对象文件。我还研究过使用

main.c 编译成可重定位的目标文件
gcc -c main.c

然后使用 ld 到 link 小精灵 main.o 但我不知道该怎么做。 elf 是 32 位的,但我省略了 -m32 标志。如果 ld 的标志不同,请告诉我。非常感谢任何帮助。

编辑: readelf -h not_my_program

的输出
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x10e0
  Start of program headers:          52 (bytes into file)
  Start of section headers:          15116 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         11
  Size of section headers:           40 (bytes)
  Number of section headers:         30
  Section header string table index: 29

Given only access to a standalone ELF program I want to be able to call a function within the program from my own program

听起来你有一个 XY problem

虽然你想要的在技术上是可行的,但这样做的难度大约是你目前尝试过的难度的 1000 倍。如果您不准备花一两个月的时间来完成这项工作,您应该寻找其他解决方案。

实际上你必须编写一个自定义的 ELF 加载器来将 not_my_program 加载到内存中并对其进行初始化,然后在其中调用 mystery 而不是 main

另请注意,mystery 可能依赖于全局数据,并且该数据可能在 main 中初始化,因此无法保证 mysterymain.

之前调用时完全可以工作

P.S。从调试器调用 mystery 就足够了吗?这可以在 30 秒内完成。

这种 hacky 方法适用于一个非常简单的案例。

[ aquila ~ ] $ cat 1.c
int func (int a) { return a * (a-1) ; }
int main(int argc) { return func (argc) ; }
[ aquila ~ ] $ cc 1.c
[ aquila ~ ] $ ./a.out ; echo $?
0
[ aquila ~ ] $ readelf -s a.out | grep func
    43: 0000000000400487    19 FUNC    GLOBAL DEFAULT   11 func
[ aquila ~ ] $ cat 2.c
#include <stdlib.h>
static __attribute__((constructor)) void main() {
  int (*func)() = (int (*)())0x0000000000400487;
  exit(func(3));
}
[ aquila ~ ] $ cc -fPIC -shared 2.c -o a.so
[ aquila ~ ] $ LD_PRELOAD=./a.so ./a.out ; echo $?
6

将2.c中的调用者做成带出口的构造函数,不调用主程序的main(),试图限制调用者以外的代码执行, func() 本身。 return 值为 6 而不是 0 表明调用有效并且主程序的 main() 没有被调用。