system() 函数未从 LD_PRELOAD'ed 库中调用

system() function not called from LD_PRELOAD'ed library

我正在尝试在 linux 上使用 LD_PRELOAD 来包装对 system 函数的调用,以便为参数添加一些预处理。这是我的 system.cpp:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <string>
#include <iostream>

typedef int (*orig_system_type)(const char *command);

int system(const char *command)
{
    std::string new_cmd = std::string("set -f;") + command;
    // next line is for debuggin only
    std::cout << new_cmd << std::endl;

    orig_system_type orig_system;
    orig_system = (orig_system_type)dlsym(RTLD_NEXT,"system");
    return orig_system(new_cmd.c_str());
}

我用

构建它
g++ -shared -fPIC -ldl -o libsystem.so system.cpp

生成 .so 对象。然后我 运行 我的程序

$ LD_PRELOAD=/path/to/libsystem.so ./myprogram

我没有收到任何错误 - 但似乎我的 system 函数没有被调用。 运行 LD_DEBUG=libs,我可以看到我的 .so 正在加载,但是我的 system 函数没有被调用,而是调用了标准库中的函数。

我需要在 code/build 中更改什么才能使其正常工作?

你需要

extern "C" int system ...

因为它是由C函数调用的。 C++ 版本的名称已损坏,因此无法识别。

代码应该可以正常工作。假设驱动程序是这样的:

#include <cstdlib>

int main() {
    system("find -name *.cpp");
}

然后 env LD_PRELOAD=$PWD/libsystem.so ./a.out 给我这个输出:

set -f;find -name *.cpp
./system.cpp
./test.cpp

这表明不仅出现了您的调试语句,而且该命令也禁用了 glob。

您可能还想考虑保存 "orig_system" 指针,以避免每次都调用 dlsym。您可以在 constructor/init 函数中执行此操作,因此您会得到类似

的内容
extern "C" {

typedef int (*orig_system_type)(const char *command);

static orig_system_type orig_system;

static void myInit() __attribute__((constructor));

void myInit()
{
    orig_system = (orig_system_type)dlsym(RTLD_NEXT,"system");
}

int system(const char *command)
{
    std::string new_cmd = std::string("set -f;") + command;
    // next line is for debuggin only
    std::cout << new_cmd << std::endl;
    return orig_system(new_cmd.c_str());
}

}

(此代码未经测试,但我过去曾使用过此技术)。

另一种方法是使用 GNU ld 的 --wrap 选项。

如果你用

编译你的共享库

-Wl,--包装系统

然后在你的代码中编写

extern "C" {

void* __real_system(const char* command);
void* __wrap_system(const char* command)
{
    std::string new_cmd = std::string("set -f;") + command;
    // next line is for debuggin only
    std::cout << new_cmd << std::endl;
    return __real_system(new_cmd.c_str());
}

}

(请注意,我从未使用过它)。