zoukankan      html  css  js  c++  java
  • [fw]拦截系统调用

    今天在ubuntu中玩了下“拦截系统调用”,记录下自己对整个实现的理解。

    原理

    在linux kernel中,系统调用都放在一个叫做“sys_call_table”的分配表里面,在进入一个系统调用的最后一步,会调用与eax中包含的系统调用号对应的特定服务例程:

    [cpp] view plaincopy
     
    1. call *sys_call_table(,%eax,4)  


    因为分派表中的每个表项占4个字节,因此首先把系统调用号乘以4,再加上sys_call_table分配表的起始地址,然后从从这个地址单元获取指向服务例程的指针,内核就找到了要调用的服务例程。我们只要修改对应的分配表项,即可实现系统调用的拦截。

    获取sys_call_table的地址

    网上介绍了很多种方法得到sys_call_table的地址,我使用了相对简单的一种方法——从内核导出的符号表中获取。

    图中,十六进制数c15b3000即为sys_call_table的地址。同时,我们也得到了一个重要的信息,该符号对应的内存区域是只读的!

    清除写保护

    因为sys_call_table分配表的内存属性为只读,因此,我们要先清除对应地址的写保护。暂时使用了两种方法实现该目的:

    第一种方法,修改cr0读写保护位:

    [cpp] view plaincopy
     
    1. /* 清除写保护 */  
    2. unsigned int clear_and_return_cr0(void)  
    3. {  
    4.         unsigned int cr0 = 0;  
    5.         unsigned int ret;  
    6.   
    7.         asm volatile ("movl %%cr0, %%eax"  
    8.                         : "=a"(cr0)  
    9.                      );  
    10.         ret = cr0;  
    11.   
    12.         /* clear the 16 bit of CR0, a.k.a WP bit */  
    13.         cr0 &= 0xfffeffff;  
    14.   
    15.         asm volatile ("movl %%eax, %%cr0"  
    16.                         :  
    17.                         : "a"(cr0)  
    18.                      );  
    19.   
    20.         return ret;  
    21. }  
    22.   
    23. /* 设置cr0,--本程序用来恢复写保护 */  
    24. void setback_cr0(unsigned int val)  
    25. {  
    26.         asm volatile ("movl %%eax, %%cr0"  
    27.                         :  
    28.                         : "a"(val)  
    29.                      );  
    30. }  


    第二种方法,设置虚拟地址对应页表项的读写属性:

    [cpp] view plaincopy
     
    1. /* make the page writable */  
    2. int make_rw(unsigned long address)  
    3. {  
    4.         unsigned int level;  
    5.         pte_t *pte = lookup_address(address, &level);  
    6.         if (pte->pte & ~_PAGE_RW)  
    7.                 pte->pte |=  _PAGE_RW;  
    8.           
    9.         return 0;  
    10. }  
    11.   
    12.   
    13. /* make the page write protected */  
    14. int make_ro(unsigned long address)  
    15. {  
    16.         unsigned int level;  
    17.         pte_t *pte = lookup_address(address, &level);  
    18.         pte->pte &= ~_PAGE_RW;  
    19.   
    20.         return 0;  
    21. }  


    附:完整代码

    [cpp] view plaincopy
     
    1. #include <linux/module.h>  
    2. #include <linux/kernel.h>  
    3. #include <linux/init.h>  
    4. #include <linux/sched.h>  
    5. #include <linux/init.h>  
    6. #include <linux/fs.h>  
    7. #include <linux/file.h>  
    8. #include <linux/fs_struct.h>  
    9. #include <linux/fdtable.h>  
    10. #include <linux/string.h>  
    11. #include <linux/mm.h>  
    12. #include <linux/syscalls.h>  
    13. #include <linux/list.h>  
    14. #include <linux/jiffies.h>  
    15. #include <linux/cdev.h>  
    16. #include <asm/unistd.h>  
    17. #include <asm/uaccess.h>  
    18. #include <linux/path.h>  
    19. #include <linux/time.h>  
    20. #include <linux/stat.h>  
    21. #include <net/sock.h>  
    22. #include <net/inet_sock.h>  
    23. #include <asm/cpufeature.h>  
    24.   
    25.   
    26.   
    27. /* grep sys_call_table  /boot/System.map-`uname -r` */  
    28. unsigned long **sys_call_table = (unsigned long **)0xc15b3000;  
    29. unsigned long *orig_mkdir = NULL;  
    30.   
    31.   
    32. /* make the page writable */  
    33. int make_rw(unsigned long address)  
    34. {  
    35.         unsigned int level;  
    36.         pte_t *pte = lookup_address(address, &level);  
    37.         if (pte->pte & ~_PAGE_RW)  
    38.                 pte->pte |=  _PAGE_RW;  
    39.           
    40.         return 0;  
    41. }  
    42.   
    43.   
    44. /* make the page write protected */  
    45. int make_ro(unsigned long address)  
    46. {  
    47.         unsigned int level;  
    48.         pte_t *pte = lookup_address(address, &level);  
    49.         pte->pte &= ~_PAGE_RW;  
    50.   
    51.         return 0;  
    52. }  
    53.   
    54.   
    55.   
    56. asmlinkage long hacked_mkdir(const char __user *pathname, int mode)  
    57. {  
    58.         printk("mkdir pathname: %s ", pathname);  
    59.         printk(KERN_ALERT "mkdir do nothing! ");  
    60.   
    61.         return 0; /*everything is ok, but he new systemcall does nothing*/  
    62. }  
    63.   
    64.   
    65. static int syscall_init_module(void)  
    66. {  
    67.         printk(KERN_ALERT "sys_call_table: 0x%lx ", sys_call_table);  
    68.         orig_mkdir = (unsigned long *)(sys_call_table[__NR_mkdir]);  
    69.         printk(KERN_ALERT "orig_mkdir: 0x%lx ", orig_mkdir);  
    70.   
    71.         make_rw((unsigned long)sys_call_table);  
    72.         sys_call_table[__NR_mkdir] = (unsigned long *)hacked_mkdir;  
    73.         make_ro((unsigned long)sys_call_table);  
    74.   
    75.         return 0;  
    76. }  
    77.   
    78. static void syscall_cleanup_module(void)  
    79. {  
    80.         printk(KERN_ALERT "Module syscall unloaded. ");  
    81.   
    82.         make_rw((unsigned long)sys_call_table);  
    83.         sys_call_table[__NR_mkdir] = (unsigned long *)orig_mkdir; /*set mkdir syscall to the origal one*/  
    84.         make_ro((unsigned long)sys_call_table);  
    85. }  
    86.   
    87.   
    88. module_init(syscall_init_module);  
    89. module_exit(syscall_cleanup_module);  
    90.   
    91. MODULE_LICENSE("GPL");  
    92. MODULE_DESCRIPTION("hack syscall");  



    参考:

    1、《深入理解linux内核(第三版)》

    2、Hijack Linux System Calls: Part III. System Call Table

  • 相关阅读:
    MoodNotes产品分析及功能说明书
    C#探秘系列(十)WPF:打开文件选择器选择文件并保存
    C#探秘系列(九)WPF连接Mysql数据库
    C#探秘系列(八)WPF数据绑定
    C#探秘系列(七):XML文件操作(一)
    #安卓杂记(七):自定义控件及属性获取
    C#探秘系列(六)
    安卓问题报告小记(七)
    121. Best Time to Buy and Sell Stock
    566. Reshape the Matrix
  • 原文地址:https://www.cnblogs.com/bittorrent/p/3794377.html
Copyright © 2011-2022 走看看