Linux中实现系统调用时是利用了i386体系结构中的软中断,通过产生0x80中断,使程序由用户态进入内核态执行系统调用函数。当系统调用发生时,产生0x80中断,CPU被切换到内核态执行中断向量表IDT对应的0x80中断处理函数,即跳转到了system_call()的入口,system_call()函数检查系统调用号,到系统调用表sys_call_table中找到该系统调用(号)对应的内核函数入口,接着调用这个内核函数,然后返回。
那么要修改系统调,只需要在sys_call_table中将原有的系统调用替换为自己写的新系统调用就可以了。但是这对用户来说无疑是个巨大的安全隐患。在2.4内核中sys_call_table是直接导出的,使改变系统调用函数变得很容易,出现了很多安全问题(后门程序)。在2.6内核中已经没有将sys_call_table导出了。所以我们第一件要做的事情就要想办法“重新”导出sys_call_table,找到其地址。
(一) 导出sys_call_table
1、首先我们在Sysmap中查看sys_call_table 地址。
[root@sun ~]# grep sys_call_table /boot/System.map-2.6.35.6-45.fc14.i686
c07ae328 R sys_call_table
其中 R 直接显示了这段内存是只读的性质,这就引出了第二步骤“取消页读写保护”。
2、可以直接修改内核源码,自己导出sys_call_table,然后再编译内核。这个办法耗时,不可移植。
修改过程分为三步: 1、修改arch/x86/kernel/entry_32.S 将语句 -.section .rodata,"a" 替换为 +.section .data,"aw" 将sys_call_table设置为可读可写 2、修改kernel/kallsyms.c,到处sys_call_table符号 +extern void *sys_call_table; +EXPORT_SYMBOL(sys_call_table); 3、在自己的模块程序中声明sys_call_table并使用 extern void *sys_call_table[]; old_entry = sys_call_table[285]; sys_call_table[285] = sys_storeint; |
3、从中断向量表获取系统调用符号表sys_call_table。(采用)