【问题标题】:Redirecting system() function call using LD_PRELOAD使用 LD_PRELOAD 重定向 system() 函数调用
【发布时间】:2015-04-07 10:07:59
【问题描述】:

我想替换我的程序使用 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 ****** ..."

【问题讨论】:

  • 也许你应该使用绝对路径,或者至少LD_PRELOAD="./libsyshook.so"
  • 使用strace 了解正在发生的事情
  • @Basile Starynkevitch 我已经将 libsyshook.so 的路径添加到 $LD_LIBRARY_PATH 的开头。实际上,问题仅针对 system(),我可以看到 getenv() 包装器调用成功。所以这不是由于路径问题。
  • 显示你的工作程序 - 通过编辑你的问题 - 或类似的小例子(对于那个问题)。给我们编译命令以及你是如何测试它的。
  • @BasileStarynkevitch 我已经编辑了我的帖子以包含测试代码和编译命令行。谢谢。

标签: c++ c linux ld-preload


【解决方案1】:

与 LD_PRELOAD 链接不良的最常见情况是 GCC 将您的函数替换为另一个函数,此时他认为它可以使您的代码更快地执行。

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

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

它会在编译前替换为这一行:

puts("4");

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

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

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

system("ls");

GCC 可能会将您的行替换为:

execlp("ls", "ls");

也可以这样做,但不那么重。它不知道您想使用自己的system 函数。尝试反汇编您的代码以检查是否是问题所在。

作为解决方案,我建议您尝试使用更“随机”的参数调用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));
}

【讨论】:

  • AFAIK,system 不会被优化GCC 所取代。如果是,则不能替换为execve,而应替换为fork 然后execve 然后waitpid
  • 你确定吗? execlp 只是一个例子,一些鲜为人知的函数,如 popen,与 system 做的事情几乎相同......特别是如果参数是单个二进制名称而不是复杂的命令行。
  • 是的,您可以通过strace 或浏览 GCC 的源代码进行检查。事实上printf 可以优化(通过__builtin_printf),但system&lt;stdlib.h&gt; 中被声明为一个函数(至少在我的Debian/Sid/amd64 上)并且没有__builtin_system
  • 好的...谢谢你的澄清。
  • @Arachor 是的!我编写了一个没有任何特定链接到 libpthread 的简单程序。现在我的 system() 包装器被调用了!!但是,对于原始代码,我对构建环境没有太多控制权,所以我需要让它工作。由于 libpthread 也在内部调用 libc 版本的 system(),所以我的包装器不应该被调用吗??
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-09
  • 1970-01-01
相关资源
最近更新 更多