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());
}
}
(请注意,我从未使用过它)。
我正在尝试在 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());
}
}
(请注意,我从未使用过它)。