我正在编写一些 C 代码来挂钩加载到内存中的 .so ELF(共享库)的某些功能。
我的 C 代码应该能够重定向另一个加载到应用程序/程序内存中的 .so 库的导出函数。
这里有一点详细说明:
Android 应用将加载多个 .so 文件。我的 C 代码必须查看属于另一个共享 .so 库(在本例中称为 target.so)的导出函数
这不是常规的 dlsym 方法,因为我不只是想要一个函数的地址,而是想用我自己的函数替换它;在那:当另一个库调用它自己的函数时,我的 hook_func 会被调用,然后我应该从我的 hook_func 调用 original_func。
对于导入功能,这可以工作。但是对于导出功能,我不知道该怎么做。导入函数具有符号表中的条目,这些条目在重定位表中具有相应的条目,最终给出全局偏移表(GOT)中的条目地址。但是对于导出函数,符号的 st_value 元素本身具有过程的地址而不是 GOT 地址(如果我错了,请纠正我)。
如何执行导出功能的挂钩?
从理论上讲,我应该得到导出函数st_value
的动态符号表条目()的元素的内存位置。Elf32_Sym
如果我得到那个位置,那么我应该能够用我的 hook_func 的地址替换那个位置的值。但是,到目前为止,我无法写入此位置。我必须假设动态符号表的内存是只读的。如果这是真的,那么在这种情况下解决方法是什么?
非常感谢您阅读并帮助我。
更新: LD_PRELOAD 只能用我自己的函数替换原来的函数,但是我不确定是否有任何方法可以调用原始函数。以我为例:
应用程序通过调用初始化音频引擎Audio_System_Create
并将AUDIO_SYSTEM
对象的引用传递给Audio_System_Create(AUDIO_SYSTEM **);
AUDIO API 分配此结构/对象并返回函数。现在,只要我可以访问该AUDIO_SYSTEM
对象,我就可以轻松地将回调附加到该对象并开始接收音频数据。因此,我的最终目标是获得对AUIOD_SYSTEM
对象的引用;在我的理解中,只有当我拦截该对象首先通过Audio_System_Create(AUIOD_SYSTEM **)
. 目前没有直接的方法来获取 android 的输出音频。(所有示例都只讨论录制来自麦克风的音频)
Update2: 正如 Basile 在他的回答中所建议的那样,我使用了 dladdr() 但奇怪的是它给了我与我传递给它的地址相同的地址。
void *pFunc=procedure_addr; //procedure address calculated from the st_value of symbol from symbol table in ELF file (not from loaded file)
int nRet;
// Lookup the name of the function given the function pointer
if ((nRet = dladdr(pFunc, &DlInfo)) != 0)
{
LOGE("Symbol Name is: %s", DlInfo.dli_sname);
if(DlInfo.dli_saddr==NULL)
LOGE("Symbol Address is: NULL");
else
LOGE("Symbol Address is: 0x%x", DlInfo.dli_saddr);
}
else
LOGE("dladdr failed");
这是我得到的结果:
entry_addr = 0x75a28cfc
entry_addr_through_dlysm =0x75a28cfc
符号名称为:AUDIO_System_Create
符号地址为:0x75a28cfc
这里通过dlysm得到或者通过ELF文件计算得到的地址就是程序的地址;而我需要这个地址本身所在的位置;这样我就可以用我的地址替换这个hook_func
地址。dladdr()
没有做我认为它会做的事。