拦截并转发C调用第三方库

时间:2015-12-28 20:27:33

标签: c++ c linux macos

我有一个应用程序(A)调用第三方共享库(C)。我想编写一个我自己的库(B)拦截从A到C的调用,在某些情况下用我自己的代码替换调用,在某些情况下做一些额外的处理,然后在C中调用匹配函数,然后在有些情况下直接将呼叫转发给C.

应用程序是开源的,所以我可以只更改每个调用站点以在B中调用类似命名的函数,然后在需要时调用C中的相应函数,但这将是一个很多工作并且会使应用程序中的上游变更难以合并。我没有第三方库的来源。如果它只是标题,那么我可以使用命名空间来实现这一点,但是当我的库和第三方库看起来需要完全相同的符号定义时,我不知道如何去做。

有没有办法让这项工作?我主要针对的是OS X,但希望它可以在Linux上运行,最后也可以在Windows上运行。

2 个答案:

答案 0 :(得分:4)

您可以使用LD_PRELOAD指向您自己的共享库。使用LD_PRELOAD将调用共享库中的所有函数,而不是其他库中具有相同名称的函数。

如果您希望注入代码然后调用原始函数,则需要调用dlsym以从第三方库获取原始函数。

这里有一些例子:https://rafalcieslak.wordpress.com/2013/04/02/dynamic-linker-tricks-using-ld_preload-to-cheat-inject-features-and-investigate-programs/

答案 1 :(得分:2)

一种解决方案如下。

在头文件中,#define所有要拦截到包装函数的函数。

#define foo wrap_foo
#define bar wrap_bar

将其添加到包含在任何位置的某个头文件中,以便所有代码都包含此标头。此标头应包含在之前您要拦截的库的标头。 gcc还有一个-include选项,可以将头文件包含在所有来源中。

这里的目标是通过调用包装函数来替换对实际函数的所有调用。

现在在某处定义您的包装函数,并根据需要拦截调用。此文件应包含您之前创建的包装器标头。

int wrap_foo() {
    return foo();
}

int wrap_bar() {
    return bar();
}

将它们连接在一起。

请注意,这样您就可以拦截对包含封面头的编译代码中foo()bar()的调用。任何预编译的代码(在库或对象中)都将直接链接到foo()bar()等。