Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2034051
  • 博文数量: 369
  • 博客积分: 10093
  • 博客等级: 上将
  • 技术积分: 4271
  • 用 户 组: 普通用户
  • 注册时间: 2005-03-21 00:59
文章分类

全部博文(369)

文章存档

2013年(1)

2011年(2)

2010年(10)

2009年(16)

2008年(33)

2007年(146)

2006年(160)

2005年(1)

分类: LINUX

2006-04-30 19:44:43

由于某些原因,我们可能需要劫持系统调用。联系系统调用的实现,根据劫持地点的不同,主要可以分为三大类:
  1. 劫持软中断,也就是int $0x80,让它首先进入我们的控制中,然后做完我们想做的事情之后,再有控制的,让它转入正常例程。
  2. 改变系统调用表(sys_call_table)中相应系统调用项的函数地址为我们自己定义的函数的地址。
  3. 通过改变某个系统调用例程(sys_xxx)的前几个字节,让它跳转到我们的例程中。
其中方法1,可以一次截获多个系统调用,但是每次系统调用都需要进入我们的例程,效率的影响可能比较严重,但是这也让我们多了一个动态增加系统调用的方案。方法2和3每次都只改变某一个系统调用,方法2较3更容易实现,通用性也更强。在笔者的系统中,2.6.9的系统中下面给出示例代码运行完好,而到了2.6.16就只有2还依然奏效。
方法1示例:
#ifndef MODULE
#define MODULE
#endif

#ifndef __KERNEL__
#define __KERNEL__
#endif

#include
#include
#include

static struct {
        unsigned short  limit;
        unsigned int    base;
} __attribute__ ((packed)) idtr;

static struct {
        unsigned short  offset_low;
        unsigned short  sel;
        unsigned char   none,
                        flags;
        unsigned short  offset_high;
} __attribute__ ((packed)) * idt;

static unsigned long old_int80_handler;
extern void new_int80_handler(void);
static void real_int80_handler(void);
static unsigned long eax, ebx, ecx, edx, esi, edi;

/*
 * Although the inline asm code is not need to be wrapped by
 * the function, but if your code has some input or output
 * parameters, it is necessary.
 */
static void puppet_handle(void){
        __asm__(
        ".section .text\n"
        ".align 4\n"
        "new_int80_handler:\n"
        "pusha;"
        "push %%es;"
        "push %%ds;"
        "push %%esi;"
        "push %%edi;"
        "push %%ebp;"
        "movl %%eax, %0;"
        "movl %%ebx, %1;"
        "movl %%ecx, %2;"
        "movl %%edx, %3;"
        "movl %%esi, %4;"
        "movl %%edi, %5;"
        "call real_int80_handler;"
        "popl %%ebp;"
        "popl %%edi;"
        "popl %%esi;"
        "popl %%ds;"
        "popl %%es;"
        "popa;"
        "jmp  *old_int80_handler;"
        "ret;" /* this instruction will not be called */
        :"=m"(eax), "=m"(ebx), "=m"(ecx),
         "=m"(edx), "=m"(esi), "=m"(edi)
        );
}

static void real_int80_handler(void)
{
        if(eax == __NR_mkdir){
                printk("sys_mkdir is called by UID = %d PID = %d.\n",
                                current->uid, current->pid);
        }
}

int init_module(void)
{
        printk("store the new_int80_handler.\n");
        __asm__("sidt %0":"=m"(idtr));
        idt = (void *) (idtr.base + 8 * 0x80);
        old_int80_handler = (idt->offset_high << 16) | idt->offset_low;
        idt->offset_high = (unsigned long)new_int80_handler >> 16;
        idt->offset_low = (unsigned long)new_int80_handler & 0xffff;

        return 0;
}

void cleanup_module(void)
{
        printk("restore the old_int80_handler.\n");
        __asm__("sidt %0":"=m"(idtr));
        idt = (void*)(idtr.base + 8 * 0x80);
        idt->offset_high = old_int80_handler >> 16;
        idt->offset_low = old_int80_handler & 0xffff;
}
方法2示例:

#ifndef __KERNEL__
 #define __KERNEL__
#endif

#ifndef MODULE
 #define MODULE
#endif

#include
#include
#include
#include
#include
#include
#include

extern void* sys_call_table[];
/*
 * After version 2.4.18, the symbol sys_call_table is not exported,
 * but you can get the address from the file System.map, Just like
 * this `grep sys_call_table /boot/System.map'.
 */
//void** sys_call_table = (void **)0xc03835c0;
asmlinkage long (*orig_mkdir)(const char *path, int mode);

asmlinkage long hacked_mkdir(const char *path, int mode)
{
        printk("sys_mkdir(%s, %d) is called by (uid = %d, pid = %d)\n",
                        path, mode, current->uid, current->pid);
        return orig_mkdir(path, mode);
}

int init_module(void)
{
        orig_mkdir=sys_call_table[__NR_mkdir];
        sys_call_table[__NR_mkdir]=hacked_mkdir;
        return 0;
}

void cleanup_module(void)
{
        sys_call_table[__NR_mkdir]=orig_mkdir;
}
方法3示例:

#include
#include
#include
#include
#include
#include
#include
#include
#include

#define SYSCALL_NR __NR_mkdir

static char syscall_code[7];
static char new_syscall_code[7] =
        "\xbd\x00\x00\x00\x00"  /*      movl   $0,%ebp  */
        "\xff\xe5"              /*      jmp    *%ebp    */
        ;

// void **sys_call_table = (void**)0xc03835c0;
extern void *sys_call_table[];
// NOTE: DO _NOT_ forget the macro asmlinkage
//       If you lose the macro, the segment fault
//       will be occered.
asmlinkage long (*orig_mkdir) (const char *, int);

void *_memcpy(void *dest, const void *src, int size)
{
        const char *p = src;
        char *q = dest;
        int i;

        for (i = 0; i < size; i++) *q++ = *p++;

        return dest;
}

asmlinkage long hacked_mkdir(const char *name, int mode)
{
        long ret;

        _memcpy(orig_mkdir, syscall_code, sizeof(syscall_code));
        printk("hacked sys_mkdir(%s, %d)\n", name, mode);
        ret = orig_mkdir(name, mode);
        _memcpy(orig_mkdir, new_syscall_code, sizeof(syscall_code));

        return ret;
}

int init_module(void)
{
        *(long *)&new_syscall_code[1] = (long)hacked_mkdir;
        orig_mkdir = sys_call_table[SYSCALL_NR];
        _memcpy(syscall_code, orig_mkdir, sizeof(syscall_code));
        _memcpy(orig_mkdir, new_syscall_code, sizeof(syscall_code));

        return 0;
}

void cleanup_module(void)
{
        _memcpy(orig_mkdir, syscall_code, sizeof(syscall_code));
}
注意:
因为高于2.4.18的内核已经不再导出符号sys_call_table,所以要想用方法2和3首先需要导出此符号,请看下一篇文章。
阅读(1343) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~