2017-06-15 79 views
1

我试图在Linux上使用LD_PRELOAD来包装调用system函数来添加一些预处理的参数。这里是我的system.cpp系统()函数不从LD_PRELOAD'ed库调用

#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 

产生的。所以对象建立它。然后,我

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

运行我的程序我没有得到任何错误 - 但似乎我的system功能不被调用。使用LD_DEBUG=libs运行,我可以看到我的.so正在加载,但是我的system函数未被调用,而是从标准库调用函数。

我需要更改代码/构建才能使其运行?

回答

2

你需要

extern "C" int system ... 

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

+0

是的!就是这样。我确实想知道名称改写,因为'strings libsystem.so | grep系统'有一些围绕'system'函数名称的问题。使用'extern“C”'它现在可以正常工作! –

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 

这表明,不仅是你的调试语句出现,但水珠是该命令禁止。

+0

请参阅@rici答案 - 您是对的,如果驱动程序使用C语言,则会正确;但在我的情况下,它是C++,并且名称混乱妨碍了您的工作。 –

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选项。

如果编译

轮候册您的共享库, - 包装系统

然后在代码编写

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

} 

(请注意,我从来没有用过这个)。