[英]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.