请稍侯

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

援引于 http://drops.wooyun.org/binary/7452