3

我的 Linux 应用程序 (A) 链接到我没有源代码的第三方共享库 (B)。这个库使用了另一个我没有源代码的第三方共享库(C)。我相信 (B) 使用 dlopen 来访问 (C) 而不是直接链接。我的理由是 (B) 上的 'ldd' 不显示 (C) 并且 objdump -X (B) 显示对 dlopen/dlclose/dlsym 的引用。

我的要求是我需要在我的 (A) 代码中获取一个指向位于 (C) 中的函数 foo() 的函数指针。通常我会为此使用 dlsym ,但我需要传递从 dlopen 返回的句柄,因为 (B) 没有公开这个句柄。

-

对于更大的上下文:我需要修改 (C) 中的函数,以便每次调用其辅助函数 bar()(也位于 (C) 中)时,它还调用具有位于 (A) 中的相同签名的函数相同的参数(基本上将我的代码注入 (C) foo()->bar() 的代码路径。我相信我已经找到了一种使用 gdb 完成此任务的方法,但是为了移植我的 gdb 命令列表,但我'我停留在获取函数指针的步骤上。我也对完成相同任务的替代方案持开放态度,而不是如上所述的确切问题

编辑:写完这篇文章后,我意识到我可以在我的代码中对文件执行另一个 dlopen,并且通过该句柄上的 dlsym 返回的符号应该与通过原始 dlopen 接收到的符号相同,如果我正在阅读 dlopen 手册页正确. 但是,我仍然对更大背景下的建议或帮助感兴趣,如果有更好的方法来解决这个问题

4

2 回答 2

2

如果您知道函数foo和的原型bar,您可以在您的应用程序环境中使用 LD_PRELOAD(您创建的库)并调用下一个可用函数(foo或者bar在完成所需任务之后)。

/*
 * gcc -shared -fPIC my_lib.c -ldl -Wl,-init,init_lib -o lib_my_name.so
 *
 * LD_PRELOAD this library in the environment of the target executable
 *
 */

#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>

#ifndef RTLD_NEXT
#define RTLD_NEXT ((void *)-1)
#endif

int init_lib(void)
{
    return 0;
}

void *foo (params here...)
{
    /* your required task here */

    return ((void* (*)(size_t))(dlsym(RTLD_NEXT, "foo")))(params here);
}

(我假设您这样做是出于某种调试目的,因为您已使用 gdb 来完成此操作,否则这不是在客户端机器上修改某些功能的好方法)

于 2011-01-05T07:47:57.413 回答
1

您可以轻松掌握 (C) 的句柄;只需 dlopen 正确的文件。要么您已经知道要 dlopen 哪个文件(因为您想要符号“foo”),或者您strace -e open,mmap,mmap2在 (A) 上运行并查看它碰巧打开了哪些共享库。

在创建 (C) 时,对“bar”的任何引用(例如来自“foo”中的 jmp 指令)通常在创建时已经部分解析,因为 (C) 本身确实有一个“bar”。因此,对 bar 的调用不会通过 PLT,换句话说,通过简单的 hack 覆盖 bar 是无效的,并且需要像 gdb 一样的 asm 级别的双关语。

所有这些听起来都过于繁重,以至于它引出了一个问题是否值得工作,或者抛弃闭源组件是否会更好。

于 2011-01-05T00:14:31.410 回答