拦截系统调用的实现以及要注意的问题

在2.6.32实现拦截系统调用


1.获取sys_call_table的地址

方法1:从/boot/System.map中取到sys_call_table的地址


由上图所看:第一:sys_call_table是只读的,下面是如何使得它变为RW。

                     第二:这种方法获取的sys_call_table只是针对本机的,可移植性差

方法2:参考来源于:http://bbs.chinaunix.net/thread-1946913-1-1.html

通过中断向量表,找到系统调用的中断向量,再通过系统调用时执行的指令,最终找到系统调用表的地址详情请阅读原文


2. 设置sys_call_table可写

在Intel x86 CPU里,CR0寄存器的WP位是控制内存页面只读的,如果将该位清0,则可以对内存页面进行写操作。更深入的理解:http://www.cnblogs.com/bittorrent/p/3328238.html

WP位是Supervisor的写保护位 (CPL < 3是Supervisor)

当WP = 1时,Supervisor不能写R/W没有置位的页。

WP = 0时,Supervisor可以写任何页。

对于User (CPL = 3), 无论WP是什么,都不能写R/W没有置位的页。


代码实现

清0以至于可写:

static void disable_page_protection(void)
{
	unsigned long value;
	asm volatile("mov %%cr0, %0" : "=r" (value));
	if(value & 0x00010000){
		value &= ~0x00010000;
		asm volatile("mov %0, %%cr0" : : "r"(value));
	}
}
	
}
还原:

static void enable_page_protection(void)
{
	unsigned long value;
	asm volatile("mov %%cr0,%0" : "=r" (value));
	if(!(value & 0x00010000)){
		value |= 0x00010000;
		asm volatile("mov %0,%%cr0" : : "r"(value));
	}
}

但是通过这两个函数去劫持系统调用时,总是出错。通过查看kdump得到的结论是,对c086b2c4不可写导致的,因此可以判断是清0不成功。

通过google,知道这是在SMP的中断导致的。


3. SMP导致不成功的解决方法:

1. cli sli关中断,参考原文:http://vulnfactory.org/blog/2011/08/12/wp-safe-or-not/  (没有实现)

2.使用stop_machine来实现,他把多CPU的其他CPU关掉,停止中断,在参数1的函数结束后恢复。

/*
 	*  stop machine and run replace calls
 	*  stop_machine: freeze the machine on all CPUs and run our replace function
 	*  It disables the interrupts. Make sure the replace function
 	*  would write the sys_call_table.
 	*/
	ret = stop_machine(do_replace_calls, NULL, 0);

static int do_replace_calls(void *arg)
{
	disable_page_protection();
#define REPLACE(x) prov_old_##x = my_table[__NR_##x];\
    my_table[__NR_##x] = prov_##x

   
    	REPLACE(open);
	REPLACE(close);
	REPLACE(mkdir);
	REPLACE(read);
	REPLACE(write);

#undef REPLACE
	enable_page_protection();

    	return 0;
}
如此可以保证在设置可写的时候,不会出现干扰,保证对sys_call_table的修改。

你可能感兴趣的:(syscalls,CR0)