简体   繁体   English

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

[英]Redirecting system() function call using LD_PRELOAD

I want to replace the calls to system() function made by my program using LD_PRELOAD. 我想使用LD_PRELOAD替换程序对system()函数的调用。

So I created the following wrapper functions in a shared library for testing. 因此,我在共享库中创建了以下包装器函数以进行测试。

// 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;
}

And compiled and linked to a shared object libsyshook.so with gcc. 并使用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

However, when I run the program with with LD_PRELOAD as shown below, my wrapper function for system() is not called, but the wrapper for getenv() called. 但是,当我使用LD_PRELOAD如下所示运行程序时,未调用我的system()包装函数,而是调用了getenv()包装函数。

LD_PRELOAD="libsyshook.so" myprog

When I attach the debugger, I can see that system() call, calls the implementation in libpthread.so. 当我连接调试器时,可以看到该system()调用在libpthread.so中调用实现。 So why is redirecting system() not working. 那么为什么重定向system()无法正常工作。 I don't think there is any limitation on that ?? 我认为对此没有任何限制?

Edit: My test program compiled to myprog above looks like this. 编辑:我的测试程序编译到上面的myprog看起来像这样。 Comments indicate my observations. 评论表明了我的看法。

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 ****** ..."

The most usual case of bad linking with LD_PRELOAD is when GCC replace your function by another one, when he think it can make your code faster to execute. 与LD_PRELOAD链接不良的最常见情况是,当GCC认为另一种函数可以使您的代码执行速度更快时,他用另一种函数替换了该函数。

For instance, if GCC read this line in your code : 例如,如果GCC在您的代码中读取了这一行:

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

It will replace with this line before compiling it : 它将在编译之前替换为此行:

puts("4");

Because it knows the printf and strlen functions, and think the output would be the same with puts function. 因为它知道printfstrlen函数,并认为输出与puts函数相同。

In this example, if you made your own printf or strlen function in a library loaded with LD_PRELOAD, your function won't be called after compilation, because GCC would have replaced function calls. 在此示例中,如果您在加载了LD_PRELOAD的库中创建了自己的printfstrlen函数,则编译后将不会调用该函数,因为GCC会替换掉函数调用。

I think your problem is for the same reason. 我认为您的问题是出于同样的原因。 system is a very heavy function, and GCC may replaced your function call by another. system是一个非常繁重的函数,GCC可能会用另一个函数代替您的函数调用。 For instance, if you tried : 例如,如果您尝试过:

system("ls");

GCC might replaced your line by : GCC可能会将您的行替换为:

execlp("ls", "ls");

That would do the same, but in less heavy. 可以这样做,但是不那么麻烦。 It couldn't know that you wanted to use your own system function. 它不知道您要使用自己的system功能。 Try to disassemble your code to check if this is the problem. 尝试反汇编您的代码以检查是否是问题所在。

As solution, I suggest you to try to call system with a more "random" parameter, to make GCC think it should not try to replace it. 作为解决方案,我建议您尝试使用更“随机”的参数调用system ,以使GCC认为不应尝试替换它。 Maybe something like : 也许像:

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));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM