zoukankan      html  css  js  c++  java
  • Linux内核监控模块-2-系统调用表地址的获取(Linux内核版本3.13)

    那么在Linux内核2.6之后,不能直接导出sys_call_table的地址后,我们要如何获得系统调用表的地址,从而实现系统调用的截获呢。

    先贴上我实现好的代码,然后再来讲解吧。

    modu.c

    #include<linux/init.h>
    #include<linux/module.h>
    #include<linux/moduleparam.h>
    #include<linux/unistd.h>
    #include<linux/sched.h>
    #include<linux/syscalls.h>
    #include<linux/string.h>
    #include<linux/fs.h>
    #include<linux/fdtable.h>
    #include<linux/uaccess.h>
    
    #include<linux/rtc.h>
    
    MODULE_LICENSE("Dual BSD/GPL");
     
    #define _DEBUG
    #ifdef _DEBUG
    #define kprintk(fmt,args...) printk(KERN_ALERT fmt,##args)
    #define kprintf(fmt,args...) printf(fmt,##args)
    #define kperror(str) perror(str)
    #else
    #define kprintk
    #define kprintf
    #define kperror
    #endif
    
    /*Function declaration*/
    long * get_sys_call_table(void);
    
    long * g_sys_call_table=NULL;//save address of sys_call_table
    
    struct _idtr{
        unsigned short limit;
        unsigned int base;
    }__attribute__((packed));
    
    struct _idt_descriptor{
        unsigned short offset_low;
        unsigned short sel;
        unsigned char none,flags;
        unsigned short offset_high;
    }__attribute__((packed));
    
    /*Get the address of sys_call_table*/
    long * get_sys_call_table(void){
        
        struct _idt_descriptor * idt;
        struct _idtr idtr;
        unsigned int sys_call_off;
        int sys_call_table=0;
        unsigned char* p;
        int i;
        asm("sidt %0":"=m"(idtr));
        kprintk("   address of idtr: 0x%x
    ",(unsigned int)&idtr);
        idt=(struct _idt_descriptor *)(idtr.base+8*0x80);
        sys_call_off=((unsigned int)(idt->offset_high<<16)|(unsigned int)idt->offset_low);
        kprintk("   address of idt 0x80: 0x%x
    ",sys_call_off);
        p=(unsigned char *)sys_call_off;
        for(i=0;i<100;i++){
            if(p[i]==0xff&&p[i+1]==0x14&&p[i+2]==0x85){
                sys_call_table=*(int*)((int)p+i+3);
                kprintk("   address of sys_call_table: 0x%x
    ",sys_call_table);
    
                return (long*)sys_call_table;
            }
        }
        
        return 0;
    }
    
    int monitor_init(void){
        kprintk("Monitor init
    ");
        g_sys_call_table = get_sys_call_table();
        return 0;
    }
    
    void monitor_exit(void){
        kprintk("Monitor exit
    ");
    }
    
    module_init(monitor_init);
    module_exit(monitor_exit);
    View Code

    Makefile

    obj-m := modu.o
    KERNELDIR := /lib/modules/3.13.0-32-generic/build
    PWD := $(shell pwd)
    modules:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    modules_install:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
    View Code

    将modu.c和Makefile放在同一个目录下,执行“make”,编译程序,会生成modu.ko文件。

    执行“sudo insmod modu.ko”,将modu.ko加载到内核中。

    执行“dmesg”,查看系统日志,如图。

     

    接下来就要解释解释原理了。

    我们知道Linux系统中的系统调用是通过用户软件调用中断int0x80激发的,int0x80被执行后,内核获得CPU的控制权,并交由system_call程序处理。即sys_call_table是由system_call进行调用的。

    而system_call是int0x80软中断,即int0x80中断对应的地址就是system_call函数的地址。而Linux系统中所有中断信息都保存在一张中断描述表IDT中,而这张表的地址又是保存在IDTR寄存器里面,所以整个截获过程可以用如下图表示。

    即先在IDTR寄存器中获得IDT_TABLE的地址,再在IDT_TABLE中获得int0x80的地址,int0x80对应的是system_call函数的地址。最后通过system_call函数的地址获得sys_call_table的地址。

  • 相关阅读:
    跨域和表单重复
    Socket
    Redis(基本数据类型和使用Java操作Redis)
    初识Git
    SpringCloud一(eureka)
    SpringBoot3(springboot_jdbctemplate以及MyBatis和Dubbo整合)
    SpringBoot2(thymeleaf模板jsp页面和jpa)
    SpringBoot
    SpringBoot小型进销存系统
    MyBatis与SpringBoot整合案例
  • 原文地址:https://www.cnblogs.com/lxw315/p/4773098.html
Copyright © 2011-2022 走看看