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

时间:2017-06-15 07:24:01

标签: c++ linux ld-preload

我试图在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函数没有被调用,而是调用标准库中的函数。

我需要在代码/构建中进行哪些更改才能使其正常工作?

3 个答案:

答案 0 :(得分:2)

你需要

extern "C" int system ...

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

答案 1 :(得分:1)

您可能还需要考虑保存“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, - wrap系统

然后在你的代码中编写

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

}

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

答案 2 :(得分:0)

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

#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也被禁用。