免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 3654 | 回复: 10
打印 上一主题 下一主题

[内核模块] Linux下拦截特定进程发出的系统调用,遇到惊悚的问题,大家帮忙看看 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-12-17 19:24 |只看该作者 |倒序浏览
如何在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:想实现对特定进程发出的系统调用进行拦截,最好是根据进程名称来区分,如果是根据进程ID,那么每次程序执行ID都不同,所以应该如何通过进程名判断?
                __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[300];

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[my_eax]++;
//      }
        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[i]=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[j]!=0){
                        printk("System call %d has been handled %ld times!\n",j,counts[j]);
                }
        }
        printk("interception module exit!\n");
}

module_init(trtr_init);
module_exit(trtr_exit);
=======================================================

论坛徽章:
0
2 [报告]
发表于 2013-12-17 19:25 |只看该作者
附上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 *~

论坛徽章:
0
3 [报告]
发表于 2013-12-17 19:40 |只看该作者
看你实现的功能很简单,为何代码写得那么复杂,用kprobe 很容易搞定啊

论坛徽章:
0
4 [报告]
发表于 2013-12-17 19:52 |只看该作者
刚接触内核开发,相关知识了解的还很少,todaygood能稍微说具体点吗

论坛徽章:
0
5 [报告]
发表于 2013-12-17 21:49 |只看该作者
kprobe好像不能拦截system_call这个函数,会报错
insmod: error inserting '*.ko': -1 Operation not permitted

论坛徽章:
0
6 [报告]
发表于 2013-12-18 10:17 |只看该作者
你这个是模块插入报错,

论坛徽章:
0
7 [报告]
发表于 2013-12-18 11:12 |只看该作者
迟来的生活 发表于 2013-12-17 19:24
如何在Linux系统下实现对特定进程发出的系统调用进行拦截?
  实验环境:RedHat linux,内核版本2.6.32,3 ...


这两种方法,windows 上玩的人,居多:)
linux源码在手,patch代码,比较好吧

论坛徽章:
0
8 [报告]
发表于 2013-12-18 13:09 |只看该作者
发表于 2013-12-18 10:17:01 |只看该作者
你这个是模块插入报错,


因为我设定的拦截函数是system_call,插入模块就会报这个错,但是要是拦截其它一些函数,插入就没有问题

这两种方法,windows 上玩的人,居多:)
linux源码在手,patch代码,比较好吧


打补丁的话可移植性太差了。。

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
9 [报告]
发表于 2013-12-18 17:02 |只看该作者
回复 1# 迟来的生活
声明:没有仔细看你的代码。

我这边有个模板代码供参考

  1. /*******************************************************************************
  2.   
  3.   Copyright(c) 2008-2013

  4.   This program is free software; you can redistribute it and/or modify it
  5.   under the terms and conditions of the GNU General Public License,
  6.   version 2, as published by the Free Software Foundation.

  7.   This program is distributed in the hope it will be useful, but WITHOUT
  8.   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  9.   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  10.   more details.

  11.   You should have received a copy of the GNU General Public License along with
  12.   this program; if not, write to the Free Software Foundation, Inc.,
  13.   51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.

  14.   The full GNU General Public License is included in this distribution in
  15.   the file called "COPYING".

  16.   Version:  not versioned!

  17.   Date: 2013-09-23 08:36:48 CST

  18.   Contact Information:
  19.   Tony <tingw.liu@gmail.com>
  20.   Home, Qingdao, China.
  21. *******************************************************************************/




  22. #include <linux/types.h>
  23. #include <linux/stddef.h>
  24. #include <linux/unistd.h>
  25. #include <linux/module.h>
  26. #include <linux/version.h>
  27. #include <linux/kernel.h>
  28. #include <linux/string.h>
  29. #include <linux/mm.h>
  30. #include <linux/slab.h>
  31. #include <linux/sched.h>
  32. #include <linux/in.h>
  33. #include <linux/in.h>
  34. #include <linux/skbuff.h>
  35. #include <linux/netdevice.h>
  36. #include <linux/dirent.h>
  37. #include <asm/processor.h>
  38. #include <asm/uaccess.h>
  39. #include <asm/unistd.h>
  40. #include <linux/fs.h>

  41. MODULE_LICENSE("GPL");
  42. MODULE_AUTHOR("Tony <tingw.liu@gmail.com>");

  43. unsigned long **sys_call_table;
  44. extern asmlinkage long sys_close(int fd);
  45. static unsigned long **get_sys_call_table(void)
  46. {
  47.         unsigned long int offset = PAGE_OFFSET;
  48.         unsigned long **sct;

  49.         while (offset < ULLONG_MAX) {
  50.                 sct = (unsigned long**)offset;
  51.                 if (sct[__NR_close] == (unsigned long*)sys_close)
  52.                         return sct;
  53.                 offset += sizeof(void *);
  54.         }
  55.         return NULL;
  56. }
  57. asmlinkage long (*orig_open)(char __user *filename,int flags,int mode);
  58. asmlinkage long new_open(char *filename,int flags,int mode)
  59. {
  60.         printk(KERN_INFO "fucking open\n");
  61.         return orig_open(filename,flags,mode);
  62. }
  63. int init_module(void)
  64. {
  65.         unsigned long orig_cr0 = read_cr0();

  66.         sys_call_table = get_sys_call_table();

  67.         if (sys_call_table == NULL) {
  68.                 printk(KERN_ALERT "Can't get sys_call_table\n");
  69.                 return -1;
  70.         }

  71.         write_cr0(orig_cr0 & (~ 0x10000)); //Make kernel writable
  72.         orig_open=sys_call_table[__NR_open];
  73.         sys_call_table[__NR_open]=(unsigned long*)new_open;
  74.         write_cr0(orig_cr0);

  75.         return 0;
  76. }
  77. void cleanup_module(void)
  78. {
  79.         unsigned long orig_cr0 = read_cr0();

  80.         write_cr0(orig_cr0 & (~ 0x10000)); //Make kernel writable
  81.         sys_call_table[__NR_open]=(unsigned long*)orig_open;
  82.         write_cr0(orig_cr0);
  83.         printk(KERN_ALERT "module exit\n");
  84.         return;
  85. }
  86.                            
复制代码

论坛徽章:
7
丑牛
日期:2013-10-18 14:43:21技术图书徽章
日期:2013-11-03 09:58:03辰龙
日期:2014-01-15 22:57:50午马
日期:2014-09-15 07:04:39丑牛
日期:2014-10-16 14:25:222015年亚洲杯之伊朗
日期:2015-03-16 10:24:352015亚冠之城南
日期:2015-05-31 09:52:32
10 [报告]
发表于 2013-12-18 17:22 |只看该作者
  1. asmlinkage char* my_function(){
  2.         struct thread_info *info=current_thread_info();
  3.         struct task_struct *task=info->task;
  4. //      if(task->pid==1000){                                      //问题:拦截特定进程发出的系统调用,但是当加入这条if语句时加载模块会发生死机现象
  5.         int my_eax;
  6.         handled_times++;
  7.         __asm__("movl %%eax,%0;":"=r"(my_eax));
  8.         counts[my_eax]++;
  9. //      }
  10.         return;
  11. }
复制代码
返回类型是char指针,当不执行if时eax放返回值,可能是非法的
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP