簡體   English   中英

如何覆蓋交流系統呼叫?

[英]How to Override A C System Call?

因此,問題如下。 項目需要攔截所有文件IO操作,例如open()close() 我試圖在調用相應的open()close()之前添加printf() close() 我不應該通過將open()close()更改為myOpen()myClose()來重寫源代碼。 我一直在嘗試使用LD_PRELOAD環境變量。 但是出現了無限循環問題。 我的問題是這樣的一個

int open(char * path,int flags,int mode)
{
    // print file name
    printf("open :%s\n",path);
    return __open(path,flags,mode);
}

是的,您需要LD_PRELOAD

您需要創建一個共享庫( .so ),其中包含要攔截的所有功能的代碼。 並且,您想要設置LD_PRELOAD以使用該共享庫

這是open功能的一些示例代碼。 您需要對要攔截的每個函數執行類似的操作:

#define _GNU_SOURCE
#include <dlfcn.h>

int
open(const char *file,int flags,int mode)
{
    static int (*real_open)(const char *file,int flags,int mode) = NULL;
    int fd;

    if (real_open == NULL)
        real_open = dlsym(RTLD_NEXT,"open");

    // do whatever special stuff ...

    fd = real_open(file,flags,mode);

    // do whatever special stuff ...

    return fd;
}

我相信RTLD_NEXT最簡單,可能就足夠了。 否則,您可以添加,它構造dlopen一次 libc


更新:

我不熟悉C,並且gcc遇到以下問題。 “錯誤:未聲明'NULL'(此功能的首次使用)”,

這是由幾個#include文件定義的,因此請嘗試#include <stdio.h> 如果要調用printf ,則需要它。

“錯誤:未聲明'RTLD_NEXT'(此功能的首次使用)”,

通過執行#include <dlfcn.h>來定義[如我的示例所示]

和“符號查找錯誤:./hack_stackoverflow.so:未定義的符號:dlsym”。

man dlsym ,它說: -ldl鏈接因此,將-ldl添加到構建.so的行中。

另外,如果“特殊內容”所做的事情在您的攔截函數上循環返回,則必須小心以防止無限遞歸。

值得注意的是,您想調用printf 如果截獲了write系統調用,則可能會發生不良情況。

因此,您需要跟蹤何時已進入其中一個攔截函數,並且如果已經存在, 則不要做任何特別的事情。 請參閱in_self變量。

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

ssize_t
write(int fd,const void *buf,size_t len)
{
    static ssize_t (*real_write)(int fd,const void *buf,size_t len) = NULL;
    static int in_self = 0;
    ssize_t err;

    if (real_write == NULL)
        real_write = dlsym(RTLD_NEXT,"write");

    ++in_self;

    if (in_self == 1)
        printf("mywrite: fd=%d buf=%p len=%ld\n",fd,buf,len);

    err = real_write(fd,buf,len);

    if (in_self == 1)
        printf("mywrite: fd=%d buf=%p err=%ld\n",fd,buf,err);

    --in_self;

    return err;
}

上面的方法對於單線程程序/環境還可以,但是如果您要攔截任意一個程序/環境, 可能是多線程的

因此,我們必須在構造函數中初始化所有real_*指針。 這是一個具有特殊屬性的函數,該函數告訴動態加載程序自動調用該函數。

並且,我們必須將in_self放入線程本地存儲中 我們通過添加__thread屬性來實現。

對於多線程版本,您可能需要與-lpthread-ldl鏈接。

編輯:我們還必須保留正確的errno

放在一起:

#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#include <errno.h>

static int (*real_open)(const char *file,int flags,int mode) = NULL;
static ssize_t (*real_write)(int fd,const void *buf,size_t len) = NULL;

__attribute__((constructor))
void
my_lib_init(void)
{

    real_open = dlsym(RTLD_NEXT,"open");
    real_write = dlsym(RTLD_NEXT,"write");
}

int
open(const char *file,int flags,int mode)
{
    int fd;

    // do whatever special stuff ...

    fd = real_open(file,flags,mode);

    // do whatever special stuff ...

    return fd;
}

ssize_t
write(int fd,const void *buf,size_t len)
{
    static int __thread in_self = 0;
    int sverr;
    ssize_t ret;

    ++in_self;

    if (in_self == 1)
        printf("mywrite: fd=%d buf=%p len=%ld\n",fd,buf,len);

    ret = real_write(fd,buf,len);

    // preserve errno value for actual syscall -- otherwise, errno may
    // be set by the following printf and _caller_ will get the _wrong_
    // errno value
    sverr = errno;

    if (in_self == 1)
        printf("mywrite: fd=%d buf=%p ret=%ld\n",fd,buf,ret);

    --in_self;

    // restore correct errno value for write syscall
    errno = sverr;

    return ret;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM