2014-07-25 35 views
1

我試圖通過掛鉤fopen()函數和使用LD_PRELOAD來記錄對特定目錄的訪問。掛鉤fopen()函數拋出分割錯誤

  1. 我的第一個問題是:掛鉤fopen()是否足以記錄打開文件的操作?
  2. 我的代碼拋出分段錯誤。特別是,代碼是這樣的(忽略錯誤檢查): FILE* (my_fopen)(const char filename, const char* mode); void* libc_handle;
    void __attribute__ ((constructor)) init(void){ libc_handle = dlopen("libc.so.6", RTLD_LAZY); *(void**)(&my_fopen) = dlsym(libc_handle,"fopen"); } FILE* fopen(const char* filename, const char* mode){ printf("Hello world\n"); return my_fopen(filename, mode); }

編譯和LD_PRELOAD指定新庫後,我跑了

ls

,並拋出Segmenation故障。任何想法爲什麼會發生?我甚至試圖刪除printf(),但沒有幫助。

+0

我會掛鉤'而不是'fopen'。 –

+0

你有沒有考慮inotify? –

+0

@MatteoItalia,我打開了鉤子,但沒有用來打開文件。我認爲fopen()等使用私有方法\ __ open(),我不認爲我可以掛鉤到 – user1734905

回答

4

你在你的代碼,它是固定在下面的示例中的一些問題(我還添加相關的報頭,並提供了main給一個完整的程序):

#include <stdio.h> 
#include <dlfcn.h> 

FILE* (*my_fopen)(const char *filename, const char* mode); 
void* libc_handle; 

void __attribute__ ((constructor)) init(void){ 
    libc_handle = dlopen("libc.so.6", RTLD_LAZY); 
    my_fopen = dlsym(libc_handle,"fopen"); 
} 
FILE* fopen(const char* filename, const char* mode){ 
    printf("Hello, Pax\n"); 
    return my_fopen(filename, mode); 
} 

int main (void) { 
    FILE *fout = fopen ("xyzzy.txt","w"); 
    fclose (fout); 
    return 0; 
} 

從什麼變化你提供如下:

  • my_fopen函數指針應該就是一個指針。我懷疑你可能認爲FILE*是這樣做的,但這實際上並不正確。要指定返回指針的功能指針,您需要FILE * (*fn)(blah, blah)

  • 換句話說,該函數的第一個參數必須是const char *,指針。你只需要const char

  • 您實際上並不需要用於設置my_fopen指針(轉換,取消地址,取消引用)的複雜表達式。你可以使用更簡單的my_fopen = ...。事實上,我認爲在這種情況下,演員可能實際上是在阻止gcc報告錯誤,因爲它假設,如果你投了,你知道你在做什麼。

  • 您可能還應該檢查返回值dlopen。在這段代碼中,我沒有這樣做,但是,如果您因爲某種原因未找到(或無法加載)庫,那麼後面的行可能會導致您的悲傷。

當我編譯和Red Hat Enterprise Linux Workstation release 6.4 (Santiago)運行這個程序,我得到的Hello, Pax文件xyzzy.txt創建輸出。


而且,只是作爲一個之外,還有可能被用來訪問文件系統等功能,像openopendirfreopencreatmkfifo(我認爲)。

根據您的需要,您可能需要做一些額外的工作。


一個你可能要考慮的事情是,ls可能連使用fopen。它實際上可以用opendir/readdirstat來構建。

所以,我們使用一個程序,我們知道調用fopen。輸入以下程序qqtest.c

#include <stdio.h> 
int main (void) { 
    FILE *fh = fopen ("xyzzy.txt", "w"); 
    fclose (fh); 
    return 0; 
} 

gcc -o qqtest qqtest.c編譯它,然後運行它。您應該看不到輸出,但應該創建文件xyzzy.txt。一旦您已確認,刪除xyzzy.txt文件,然後輸入以下程序qq.c

#include <stdio.h> 
#include <dlfcn.h> 

FILE* (*my_fopen)(const char *filename, const char* mode); 
void* libc_handle; 

void __attribute__ ((constructor)) init(void){ 
    libc_handle = dlopen("libc.so.6", RTLD_LAZY); 
    my_fopen = dlsym(libc_handle,"fopen"); 
} 

FILE* fopen(const char* filename, const char* mode){ 
    printf("Hello, Pax\n"); 
    return my_fopen(filename, mode); 
} 

gcc -shared -o qq.so qq.c -ldl這編譯並運行您的程序qqtest(改變共享對象的路徑到自己的課程目錄):

LD_PRELOAD=/home/pax/qq.so ./qqtest 

這個時候,你應該看到Hello, Pax串輸出創建xyzzy.txt文件之前,證明了它的呼喚你的包裝函數,這反過來又調用原始fopen。現在


,這一切都非常好,但是,即使一旦你得到這個位的工作,你必須攔截相當多的不同的調用,以確保您捕獲所有的變化。

這需要一段時間才能完成,正如Chris Stratton在評論中指出的那樣,Linux內核已具有能夠向您報告文件系統更改。

如果你的目標是隻跟蹤文件系統的變化,而不是教育自己如何可以做到,看看inotify來看看如何做到這一點,而不必重新發明輪子

+0

謝謝,但它是編輯錯誤(代碼不會編譯,如果我不包括返回)。剛剛編輯我的問題,仍然是同樣的錯誤。 – user1734905

+0

@ user1734905,更深入地研究了它,查看更新。 – paxdiablo

+0

你用「ls」來測試它嗎? 「ls」 – user1734905