我的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手册页。然而,我仍然对我的大背景下的建议或帮助感兴趣,如果有更好的方法来解决这个问题
答案 0 :(得分: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来完成此操作,否则这不是修改客户端计算机上某些功能的好方法)
答案 1 :(得分:1)
您可以轻松掌握(C)的句柄;只是dlopen正确的文件。您已经知道要打开哪个文件(因为您需要符号“foo”),或者您在(A)上运行strace -e open,mmap,mmap2
并查看它碰巧打开的共享库。
当创建(C)时,对“bar”的任何引用(例如来自“foo”中的jmp指令)通常在创建时已经部分解析,因为(C)本身具有“bar”。因此,对bar的调用不会通过PLT,换句话说,通过简单的hack覆盖bar是无效的,并且需要像gdb那样的asm级别的惩罚。
所有这些听起来过于紧张,以至于它引出了一个问题,即它是否值得工作,或者是否抛弃闭源组件可能会更好。