Linux内核从2.4.18开始就不再导出系统调用表(sys_call_table),这对于我们想对系统调用做些手脚的朋友们来说,确实不是什么好 消息。少了很多便利条件,如果说改内核源码,加上EXPORT_SYMBOL(sys_call_table),还是能够导出的,不过这个需要重新编译内 核,最烦人就是重启(我们有些时候最怕的就是重启,至于为什么,大家心里明白,哈哈)。如果我们足够幸运,能找到/boot/System.map,通过 简单的grep sys_call_table /boot/System.map也能如愿以偿,可是这个文件并不是所有的系统都有的。还好LKM给了我们访问内核空间的能力,可是系统这么大,从何下手 呢?
反汇编系统调用相关代码:
可以看到蓝色的部分就是需要找的标志字符串,与之紧挨的高地址部分就是我们要找的sys_call_table的地址。为了缩小查找范围,我们只要从int $0x80的入口函数向下顺序查找就行,其地址用命令sidt就能直接得到了。具体代码如下:
另外,因为有这样一个事实:sys_call_table总是在loops_per_jiffy和boot_cpu_data之间,所以可以用这两个符号地址作为边界进行查询!
反汇编系统调用相关代码:
(gdb) disas syscall_call Dump of assembler code for function syscall_call: 0xc0102e0a <syscall_call+0>: call *0xc030948c(,%eax,4) 0xc0102e11 <syscall_call+7>: mov %eax,0x18(%esp) End of assembler dump. (gdb) x/8x 0xc0102e0a 0xc0102e0a <syscall_call>: 0x8c8514ff 0x89c03094 0xfa182444 0x66084d8b 0xc0102e1a <syscall_exit+5>: 0xfeffc1f7 0x00cc850f 0x448b0000 0x648a3024 |
/* * Copyright (c) 2006 xiaosuo <xiaosuo@gmail.com> * * Copyright (c) 2003 Dallachiesa Michele <xenionREMOVETHIS@antifork.org> * * 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 <linux/kernel.h> #ifdef USE_SYMBOL_NAME #include <linux/string.h> #endif #include <linux/module.h> #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) { } |
/* 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; } |