那么在Linux内核2.6之后,不能直接导出sys_call_table的地址后,我们要如何获得系统调用表的地址,从而实现系统调用的截获呢。
先贴上我实现好的代码,然后再来讲解吧。
modu.c
#include<linux/init.h> #include<linux/module.h> #include<linux/moduleparam.h> #include<linux/unistd.h> #include<linux/sched.h> #include<linux/syscalls.h> #include<linux/string.h> #include<linux/fs.h> #include<linux/fdtable.h> #include<linux/uaccess.h> #include<linux/rtc.h> MODULE_LICENSE("Dual BSD/GPL"); #define _DEBUG #ifdef _DEBUG #define kprintk(fmt,args...) printk(KERN_ALERT fmt,##args) #define kprintf(fmt,args...) printf(fmt,##args) #define kperror(str) perror(str) #else #define kprintk #define kprintf #define kperror #endif /*Function declaration*/ long * get_sys_call_table(void); long * g_sys_call_table=NULL;//save address of sys_call_table struct _idtr{ unsigned short limit; unsigned int base; }__attribute__((packed)); struct _idt_descriptor{ unsigned short offset_low; unsigned short sel; unsigned char none,flags; unsigned short offset_high; }__attribute__((packed)); /*Get the address of sys_call_table*/ long * get_sys_call_table(void){ struct _idt_descriptor * idt; struct _idtr idtr; unsigned int sys_call_off; int sys_call_table=0; unsigned char* p; int i; asm("sidt %0":"=m"(idtr)); kprintk(" address of idtr: 0x%x\n",(unsigned int)&idtr); idt=(struct _idt_descriptor *)(idtr.base+8*0x80); sys_call_off=((unsigned int)(idt->offset_high<<16)|(unsigned int)idt->offset_low); kprintk(" address of idt 0x80: 0x%x\n",sys_call_off); p=(unsigned char *)sys_call_off; for(i=0;i<100;i++){ if(p[i]==0xff&&p[i+1]==0x14&&p[i+2]==0x85){ sys_call_table=*(int*)((int)p+i+3); kprintk(" address of sys_call_table: 0x%x\n",sys_call_table); return (long*)sys_call_table; } } return 0; } int monitor_init(void){ kprintk("Monitor init\n"); g_sys_call_table = get_sys_call_table(); return 0; } void monitor_exit(void){ kprintk("Monitor exit\n"); } module_init(monitor_init); module_exit(monitor_exit);
Makefile
obj-m := modu.o KERNELDIR := /lib/modules/3.13.0-32-generic/build PWD := $(shell pwd) modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
将modu.c和Makefile放在同一个目录下,执行“make”,编译程序,会生成modu.ko文件。
执行“sudo insmod modu.ko”,将modu.ko加载到内核中。
执行“dmesg”,查看系统日志,如图。
接下来就要解释解释原理了。
我们知道Linux系统中的系统调用是通过用户软件调用中断int0x80激发的,int0x80被执行后,内核获得CPU的控制权,并交由system_call程序处理。即sys_call_table是由system_call进行调用的。
而system_call是int0x80软中断,即int0x80中断对应的地址就是system_call函数的地址。而Linux系统中所有中断信息都保存在一张中断描述表IDT中,而这张表的地址又是保存在IDTR寄存器里面,所以整个截获过程可以用如下图表示。
即先在IDTR寄存器中获得IDT_TABLE的地址,再在IDT_TABLE中获得int0x80的地址,int0x80对应的是system_call函数的地址。最后通过system_call函数的地址获得sys_call_table的地址。
时间: 2024-10-14 02:04:43