使用LD_PRELOAD重定向system()函数调用

时间:2015-04-07 10:08:00

标签: c++ c linux ld-preload

我想用LD_PRELOAD替换我的程序对system()函数的调用。

因此,我在共享库中创建了以下包装函数以进行测试。

// syshook.c

int system(const char * command)
{
    printf("system() called for %s ************************************\n", command);
    return 55;
}

char * getenv (const char* name)
{
    printf("my getenv() *********************");
    return 0;
}

使用gcc编译并链接到共享对象libsyshook.so。

gcc -Wall -fPIC -c *.c
gcc -shared -Wl,-soname,libsyshook.so -o libsyshook.so.1.0
ln -s libsyshook.so libsyshook.so.1.0

但是,当我使用LD_PRELOAD运行程序时,如下所示,我没有调用system()的包装函数,而是调用了getenv()的包装器。

LD_PRELOAD="libsyshook.so" myprog

当我附加调试器时,我可以看到system()调用,调用libpthread.so中的实现。那么为什么重定向system()不起作用呢?我不认为对此有任何限制吗?

编辑: 编译到myprog上面的测试程序看起来像这样。评论表明了我的观察。

void TestClass::testMethod()
{
    string cmdLine = "date";
    if (!mainWin) cmdLine = "time";

    int retFromSys = system(cmdLine.c_str());   // goes into libpthread when stepped in.
    cout << "return from system " << retFromSys << endl; // prints 0, not 55  
    getenv("DEBUG_SYS");  // Wrapper function called for this. Prints "my getenv ****** ..."

1 个答案:

答案 0 :(得分:0)

最常见的与LD_PRELOAD链接错误的情况是当GCC用另一个替换你的函数时,他认为它可以让你的代码更快地执行。

例如,如果GCC在您的代码中读取此行:

printf("%d", strlen("toto"));

在编译之前它将替换为此行:

puts("4");

因为它知道printfstrlen函数,并认为输出与puts函数相同。

在此示例中,如果您在加载了LD_PRELOAD的库中创建了自己的printfstrlen函数,则在编译后不会调用您的函数,因为GCC会替换函数调用

我认为你的问题是出于同样的原因。 system是一个非常繁重的函数,GCC可能会被另一个函数替换。例如,如果您尝试过:

system("ls");

海湾合作委员会可能会用以下方式替换你的行:

execlp("ls", "ls");

那会做同样的事,但不会那么沉重。它无法知道您想要使用自己的system函数。尝试反汇编代码以检查这是否是问题。

作为解决方案,我建议您尝试使用更多&#34;随机&#34;来呼叫system。参数,让GCC认为它不应该试图替换它。也许是这样的:

int main(int argc, char** argv)
{
    char* line = NULL;

    // Useless condition to make GCC think the parameter is variable
    if (argc == 1)
        line = "ls";

    return (system(line));
}