我试图在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
函数没有被调用,而是调用标准库中的函数。
我需要在代码/构建中进行哪些更改才能使其正常工作?
答案 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也被禁用。