Linux下拦截特定进程发出的系统调用,遇到惊悚的问题,大家帮忙看看
如何在Linux系统下实现对特定进程发出的系统调用进行拦截?实验环境:RedHat linux,内核版本2.6.32,32位处理器。
查到有两种比较好的方法,一种是修改中断向量表法,代码如下:
有两个问题,在代码中添加了注释,希望大家能帮忙解答!
==========================================================
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <asm/unistd.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/dirent.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/fs.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("SHY");
MODULE_DESCRIPTION("test");
void my_stub();
static unsigned long old_stub;
static unsigned long stub_eax,stub_ebx,stub_ecx,stub_edx,stub_esi,stub_edi;
struct{
unsigned short limit;
unsigned long base;
}__attribute__((packed)) idtr;
//中断描述符
struct descriptor_idt{
unsigned short offset_low;
unsigned short selector;
unsigned char reserved;
unsigned char type:4;
unsigned char segmentflag:1;
unsigned char DPL:2;
unsigned char present:1;
unsigned short offset_high;
};
//拦截处理函数
void my_handler(){
// if(current_comm=="ls"){ //问题1:想实现对特定系统调用的拦截,最好是根据进程名称来区分,应该如何做?
__asm__("movl %%eax,%0\n"
"movl %%ebx,%1\n"
"movl %%ecx,%2\n"
"movl %%edx,%3\n"
"movl %%esi,%4\n"
"movl %%edi,%5\n"
"popl %%ebx\n"
"popl %%ecx\n"
"popl %%edx\n"
"popl %%esi\n"
"popl %%edi\n"
"popl %%ebp\n"
"popl %%eax\n"
"popl %%ds\n"
"popl %%es\n"
"jmp *old_stub"
::"m" (stub_eax),"m" (stub_ebx),"m" (stub_ecx),"m" (stub_edx),"m" (stub_esi),"m" (stub_edi));
printk("syscall number == %d",stub_eax);
// }else{
// __asm__("popl %%ebx\n"
// "popl %%ecx\n"
// "popl %%edx\n"
// "popl %%esi\n"
// "popl %%edi\n"
// "popl %%ebp\n"
// "popl %%eax\n"
// "popl %%ds\n"
// "popl %%es\n"
// "jmp *old_stub");
// }
}
void stub_kad(void){
__asm__(".globl my_stub \n"
".align 4,0x90 \n"
"my_stub: \n"
"pushl %es\n"
"pushl %ds\n"
"pushl %eax\n"
"pushl %ebp\n"
"pushl %edi\n"
"pushl %esi\n"
"pushl %edx\n"
"pushl %ecx\n"
"pushl %ebx\n"
"call my_handler \n");
}
static void disable_page_protection(){
unsigned long value;
asm volatile("mov %%cr0, %0":"=r" (value));
if(!(value&0x00010000)){
return;
}
asm volatile("mov %0, %%cr0"::"r" (value&~0x00010000));
}
static void enable_page_protection(){
unsigned long value;
asm volatile("mov %%cr0, %0":"=r" (value));
if(!(value&0x00010000)){
return;
}
asm volatile("mov %0, %%cr0"::"r" (value|0x00010000));
}
static void replace_system_call(void){
struct descriptor_idt* idte;
__asm__ volatile("sidt %0":"=m" (idtr));
idte=(struct descriptor_idt*)(idtr.base+8*0x80);
old_stub=(idte->offset_high+16|idte->offset_low);
unsigned long new_addr=(unsigned long)my_stub;
idte->offset_high=(unsigned short)(new_addr>>16); //问题2:关键问题!这条语句的执行会导致系统死机,怀疑是因为没有对该地址的修改权限
idte->offset_low=(unsigned short)(new_addr & 0x0000ffff);
}
static int __init _init_module(void){
disable_page_protection();
replace_system_call();
printk("Intercept Module Installed!\n");
return 0;
}
static void __exit _cleanup_module(void){
struct descriptor_idt *idte;
__asm__ volatile("sidt %0":"=m" (idtr));
idte=(struct descriptor_idt*)(idtr.base+8*0x80);
idte->offset_high=(unsigned short)(old_stub>>16); //与问题2同样的问题
idte->offset_low=(unsigned short)(old_stub & 0x0000ffff);
enable_page_protection();
printk("Intercept Module Uninstalled!\n");
}
module_init(_init_module);
module_exit(_cleanup_module);
=======================================================
另外一种拦截方法,是通过修改sysenter指令的跳转目的地址,这种方法运行通过了,但是在获取进程信息时存在问题,同样在代码中注释,代码如下:
功能是统计特定进程发出的不同的系统调用数量
=======================================================
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <asm/thread_info.h>
#include <asm/unistd.h>
#include <asm/msr.h>
#include <asm/pgtable.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("SHY");
MODULE_DESCRIPTION("system call interception");
asmlinkage char* my_function();
unsigned long handler_code=(unsigned long)&my_function;
unsigned long old_sysenter;
extern asmlinkage void my_stub();
unsigned long handled_times;
unsigned long counts;
void stub_trtr(void){
__asm__(".globl my_stub \n"
".align 4,0x90 \n"
"my_stub: \n"
" call *%0 \n"
" jmp *%1 \n"
::"m"(handler_code),"m"(old_sysenter));
}
asmlinkage char* my_function(){
struct thread_info *info=current_thread_info();
struct task_struct *task=info->task;
// if(task->pid==1000){ //问题:拦截特定进程发出的系统调用,但是当加入这条if语句时加载模块会发生死机现象
int my_eax;
handled_times++;
__asm__("movl %%eax,%0;":"=r"(my_eax));
counts++;
// }
return;
}
void my_hook(){
unsigned int a;
rdmsr(MSR_IA32_SYSENTER_EIP,old_sysenter,a);
wrmsr(MSR_IA32_SYSENTER_EIP,my_stub,0);
}
static int __init trtr_init(void){
printk("interception module enter!\n");
int i;
for(i=0;i<300;i++){
counts=0;
}
my_hook();
handled_times=0;
return 0;
}
static void trtr_exit(void){
int j;
wrmsr(MSR_IA32_SYSENTER_EIP,old_sysenter,0);
for(j=0;j<300;j++){
if(counts!=0){
printk("System call %d has been handled %ld times!\n",j,counts);
}
}
printk("interception module exit!\n");
}
module_init(trtr_init);
module_exit(trtr_exit);
======================================================= 附上makefile:
=========================================
obj-m := intercept.o
modules-objs := intercept.o
KDIR := /lib/modules/`uname -r`/build
PWD := $(shell pwd)
all:default clean
default:
make -C $(KDIR) M=$(PWD)
clean:
rm -f *.o *.unsigned *.mod.c *.elf modules.order *.symvers *~
回复 1# 迟来的生活
我觉得这个问题到内核版块去问比较合适
对这些我不太了解,对你的程序提出些疑惑之处。
问题1:想实现对特定系统调用的拦截,最好是根据进程名称来区分,应该如何做?
这里是否还是进程上下文。如果是,应当能够得到task_struct,这里面应当有命令名吧。
调用系统调用时使用eax寄存器存储系统调用号,通过系统调用号应当能够知道是什么系统调用。
问题2:关键问题!这条语句的执行会导致系统死机,怀疑是因为没有对该地址的修改权限?
对这句话上两行处old_stub=(idte->offset_high+16|idte->offset_low);中的+16不太理解,我认为应当为右移操作。
问题:拦截特定进程发出的系统调用,但是当加入这条if语句时加载模块会发生死机现象?
这个函数调用没有保存和恢复寄存器内容,在调用前后寄存器中的内容是否会发生变化?调用这个函数时,系统调用的参数在什么位置?
第一个问题是我自己没说清楚,是想实现对特定进程发出的系统调用进行拦截,系统调用号可以得到,进程ID也可以得到,但是程序每次运行ID是不一样的,我希望能通过名称判断进程;
第二个问题我也不大理解,看的别人的代码。。
第三个问题,系统调用的参数还是保存在寄存器中的,你的意思是我的if语句会导致寄存器内容发生改变,所以会死机是吗? 回复 4# 迟来的生活
我只是猜测这样可能有问题,你测试一下就知道可不可以了。
试过了,跟寄存器的东西有没有入栈保护应该是没关系。。貌似遇到点具体的复杂的问题就没什么人能给出正解啊:((
页:
[1]