在2.6.32实现拦截系统调用
方法1:从/boot/System.map中取到sys_call_table的地址
由上图所看:第一:sys_call_table是只读的,下面是如何使得它变为RW。
第二:这种方法获取的sys_call_table只是针对本机的,可移植性差
方法2:参考来源于:http://bbs.chinaunix.net/thread-1946913-1-1.html
通过中断向量表,找到系统调用的中断向量,再通过系统调用时执行的指令,最终找到系统调用表的地址。详情请阅读原文。
在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的中断导致的。
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的修改。