2017-06-15 82 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()); 
} 

} 

(請注意,我從來沒有用過這個)。