C 如何从elf调用和编译函数到我的二进制文件?

C 如何从elf调用和编译函数到我的二进制文件?,c,gcc,elf,disassembly,C,Gcc,Elf,Disassembly,我有一个我不写的二进制文件(ELF),但我想使用这个二进制文件中的一个函数(我知道函数的地址/偏移量),这个函数不是从二进制文件导出的 我的目标是从我的C代码中调用这个函数,我用二进制代码静态地编写和编译这个函数(我用gcc编译) 我该怎么做呢?我要回答这个问题 从我编写的c代码调用此函数 部分 以下内容在某些假设下工作,如动态链接和位置独立代码。我没有考虑太久,如果它们坏了会发生什么(如果有兴趣,让我们进行实验/讨论) gcc-fpic-shared lib.c-o lib.so $ nm l

我有一个我不写的二进制文件(ELF),但我想使用这个二进制文件中的一个函数(我知道函数的地址/偏移量),这个函数不是从二进制文件导出的

我的目标是从我的C代码中调用这个函数,我用二进制代码静态地编写和编译这个函数(我用gcc编译)


我该怎么做呢?

我要回答这个问题

从我编写的c代码调用此函数

部分

以下内容在某些假设下工作,如动态链接和位置独立代码。我没有考虑太久,如果它们坏了会发生什么(如果有兴趣,让我们进行实验/讨论)

gcc-fpic-shared lib.c-o lib.so

$ nm lib.so  | grep foo
00000000000010e9 t foo
上面的复制品有你知道的地址。我们现在知道的地址是
0x10e9
。它是重新定位之前
foo
的虚拟地址。我们将通过简单地添加
lib.so
加载时的基址来模拟动态加载程序手动执行的重新定位

$ cat 1.c
#define _GNU_SOURCE
#include <stdio.h>
#include <link.h>
#include <string.h>
#include <elf.h>

#define FOO_VADDR 0x10e9

typedef int(*func_t)();

int callback(struct dl_phdr_info *info, size_t size, void *data)
{
    if (!(strstr(info->dlpi_name, "lib.so")))
        return 0;
    Elf64_Addr addr = info->dlpi_addr + FOO_VADDR;
    func_t f = (func_t)addr;
    int res = f();
    printf("res = %d\n", res);
    return 0;
}

int main()
{
    void *handle = dlopen("./lib.so", RTLD_LAZY);
    if (!handle) {
        puts("failed to load");
        return 1;
    }
    dl_iterate_phdr(&callback, NULL);
    dlclose(handle);
    return 0;
}
瞧,成功了!那很有趣

信贷:很有帮助

如果你有问题,请随意阅读该男子并在评论中提问

至于

在二进制文件中静态编译此函数


我一点也不知道。这将更加棘手。你为什么要那样?另外,您是否知道该函数是否依赖于原始ELF文件中的某些数据(或者它调用其他函数),如上面的示例所示

此ELF文件包含的代码是否与位置无关?在这个二进制文件上,
file
命令的输出是什么?但是
1.c
使用
lib.c
作为dinamic。我想静态地编译这个函数,在一般情况下这是一项困难的任务,特别是因为这个函数可以通过
rip
-相对寻址引用数据,并调用其他函数,等等,所以您需要提取所有依赖项。我想你需要拆开这个东西,用符号值替换所有的相对和绝对跳转和引用,然后像往常一样组装和链接。如果这个函数是在
lib.c
中导出的,那么tgat调用起来容易吗?当我编译它时,它是静态的?@Keystone它会稍微容易一些,但并不容易。有更多关于库中导出符号的信息:地址、大小和重新定位将非常有用。不过,您将面临同样的基本问题:您需要提取已经编译的代码并重新编译(实际上是重新编译),而不需要库的其余部分。这很难,因为工具链并不是为这个目的而设计的。在你的例子中,你展示了如何从二进制文件中调用函数,这个二进制文件是你编写的“共享的”。有没有办法调用我知道偏移量的二进制函数,但是这个二进制文件没有编译为共享的??
$ cat 1.c
#define _GNU_SOURCE
#include <stdio.h>
#include <link.h>
#include <string.h>
#include <elf.h>

#define FOO_VADDR 0x10e9

typedef int(*func_t)();

int callback(struct dl_phdr_info *info, size_t size, void *data)
{
    if (!(strstr(info->dlpi_name, "lib.so")))
        return 0;
    Elf64_Addr addr = info->dlpi_addr + FOO_VADDR;
    func_t f = (func_t)addr;
    int res = f();
    printf("res = %d\n", res);
    return 0;
}

int main()
{
    void *handle = dlopen("./lib.so", RTLD_LAZY);
    if (!handle) {
        puts("failed to load");
        return 1;
    }
    dl_iterate_phdr(&callback, NULL);
    dlclose(handle);
    return 0;
}
$ gcc 1.c -ldl  && ./a.out
res = 42