Linux下拦截系统调用的一种方法
Linux允许让我们自己的动态链接库加载在其它动态链接库之前,甚至是系统库(如 libc.so.6),如此一来就可以写程序拦截替换系统的 time()
、 read()
、 open()
这些函数。
首先,我们的 open()
函数会比较一下文件名是不是我们所想要打开的,如果是,则将文件描述符记录下来。然后, read()
函数会判断如果我们调用的是不是我们所保存的文件描述符,如果是则代替它输出,否则调用 libc.so.6
里面原来的函数。最后, close()
函数会关闭我们所保存的文件描述符。
在这里我们借助了 dlopen()
和 dlsym()
函数来确定原先在 libc.so.6
的函数的地址,因为我们需要控制“真实”的函数。
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <dlfcn.h>
#include <string.h>
void *libc_handle = NULL;
int (*open_ptr)(const char *, int) = NULL;
int (*close_ptr)(int) = NULL;
ssize_t (*read_ptr)(int, void*, size_t) = NULL;
bool inited = false;
_Noreturn void die (const char * fmt, ...)
{
va_list va;
va_start (va, fmt);
vprintf (fmt, va);
exit(0);
};
static void find_original_functions ()
{
if (inited)
return;
libc_handle = dlopen ("libc.so.6", RTLD_LAZY);
if (libc_handle==NULL)
die ("can't open libc.so.6\n");
open_ptr = dlsym (libc_handle, "open");
if (open_ptr==NULL)
die ("can't find open()\n");
close_ptr = dlsym (libc_handle, "close");
if (close_ptr==NULL)
die ("can't find close()\n");
read_ptr = dlsym (libc_handle, "read");
if (read_ptr==NULL)
die ("can't find read()\n");
inited = true;
}
static int opened_fd=0;
int open(const char *pathname, int flags)
{
find_original_functions();
int fd=(*open_ptr)(pathname, flags);
if (strcmp(pathname, "/proc/uptime")==0)
opened_fd=fd; // that's our file! record its file descriptor
else
opened_fd=0;
return fd;
};
int close(int fd)
{
find_original_functions();
if (fd==opened_fd)
opened_fd=0; // the file is not opened anymore
return (*close_ptr)(fd);
};
ssize_t read(int fd, void *buf, size_t count)
{
find_original_functions();
if (opened_fd!=0 && fd==opened_fd)
{
// that's our file!
return snprintf (buf, count, "%d %d", 0x7fffffff, 0x7fffffff)+1;
};
// not our file, go to real read() function
return (*read_ptr)(fd, buf, count);
};
把它编译成动态链接库:
gcc -fpic -shared -Wall -o fool_uptime.so fool_uptime.c -ldl
运行uptime,并让它在加载其它库之前加载我们的库:
LD_PRELOAD=`pwd`/fool_uptime.so uptime
可以看到:
01:23:02 up 24855 days, 3:14, 3 users, load average: 0.00, 0.01, 0.05