在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的修改。