Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2039986
  • 博文数量: 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 20:41:14

Linux内核从2.4.18开始就不再导出系统调用表(sys_call_table),这对于我们想对系统调用做些手脚的朋友们来说,确实不是什么好消息。少了很多便利条件,如果说改内核源码,加上EXPORT_SYMBOL(sys_call_table),还是能够导出的,不过这个需要重新编译内核,最烦人就是重启(我们有些时候最怕的就是重启,至于为什么,大家心里明白,哈哈)。如果我们足够幸运,能找到/boot/System.map,通过简单的grep sys_call_table /boot/System.map也能如愿以偿,可是这个文件并不是所有的系统都有的。还好LKM给了我们访问内核空间的能力,可是系统这么大,从何下手呢?
反汇编系统调用相关代码:
(gdb) disas syscall_call
Dump of assembler code for function syscall_call:
0xc0102e0a :    call   *0xc030948c(,%eax,4)
0xc0102e11 :    mov    %eax,0x18(%esp)
End of assembler dump.
(gdb) x/8x 0xc0102e0a
0xc0102e0a :      0x8c8514ff      0x89c03094      0xfa182444      0x66084d8b
0xc0102e1a :    0xfeffc1f7      0x00cc850f      0x448b0000      0x648a3024
可以看到蓝色的部分就是需要找的标志字符串,与之紧挨的高地址部分就是我们要找的sys_call_table的地址。为了缩小查找范围,我们只要从int $0x80的入口函数向下顺序查找就行,其地址用命令sidt就能直接得到了。具体代码如下:
/*
 * Copyright (c) 2006 xiaosuo
 *
 * Copyright (c) 2003 Dallachiesa Michele
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification are permitted.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *
 * DESCRIPTION
 *
 *   redhat kernels don't export the sys_call_table symbol anymore.. this
 *   is a workaround that let you use your old LKMs without fix them.
 *
 *   In fact, the kernel (>= 2.4.18) don't export the sys_call_table symbol
 *   anymore...
 *
 * USAGE
 *
 *    Build this as a kernel module and loaded
 *
 *  + greetz: (#phrack.it|antifork.org) guys
 *  + sys_call_table[] address lookup code from phrack 58 #0x07 by sd
 */

#ifndef MODULE
#define MODULE
#endif

#ifndef __KERNEL__
#define __KERNEL__
#endif

#include
#ifdef USE_SYMBOL_NAME
#include
#endif
#include

#define CALLOFF 100

unsigned long           sys_call_table = 0;
EXPORT_SYMBOL(sys_call_table);

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

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

/*
 * The /proc/kallsyms is not updated.
 */
int set_symbol_value(unsigned long old_value, unsigned long value)
{
        struct kernel_symbol *ksyms;
        int i;

        ksyms = (struct kernel_symbol*)(THIS_MODULE->syms);
        for(i = 0; i < THIS_MODULE->num_syms; i ++){
#ifdef USE_SYMBOL_NAME
                if(strcmp(ksyms[i].name, "sys_call_table") == 0){
#else
                if(ksyms[i].value == old_value){
#endif
                        ksyms[i].value = value;
                        return 0;
                }
        }

        return -1;
}

char* findoffset(char *start)
{
        char           *p;

        for (p = start; p < start + CALLOFF; p++)
                if (*(p + 0) == '\xff' && *(p + 1) == '\x14'
                                && *(p + 2) == '\x85')
                        return p;

        return NULL;
}

int init_module(void)
{
        unsigned        sys_call_off;
        char           *p;

        __asm__("sidt %0":"=m"(idtr));
        idt = (void *) (idtr.base + 8 * 0x80);
        sys_call_off = (idt->offset_high << 16) | idt->offset_low;

        if ((p = findoffset((char *) sys_call_off))) {
                return set_symbol_value((unsigned long)&sys_call_table,
                                *((unsigned long*)(p+3)));
        }

        return -1;
}

void cleanup_module(void)
{
}
另外,因为有这样一个事实:sys_call_table总是在loops_per_jiffy和boot_cpu_data之间,所以可以用这两个符号地址作为边界进行查询!
 /* This method first be found in the dazuko 2.0.6
 */

static void** dazuko_get_sct(void)
{
        unsigned long   ptr;
        extern int      loops_per_jiffy;
        unsigned long   *p;

        for(ptr=(unsigned long)&loops_per_jiffy; ptr<(unsigned long)&boot_cpu_data;
                        ptr+=sizeof(void *)){
                p = (unsigned long *)ptr;
                if (p[6] == (unsigned long)sys_close){
                        return (void **)p;
                }
        }

        return NULL;
}

阅读(2382) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~