免费注册 查看新帖 |

Chinaunix

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

修改sys_call_table所在页面的read/write标志位的疑问 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-10-30 20:01 |只看该作者 |倒序浏览
本帖最后由 warriorpaw 于 2013-10-30 20:03 编辑

新手学习怎么样hook系统调用,就参照(好吧就是照抄)
http://www.elliotbradbury.com/li ... t-descriptor-table/
写了如下的代码
  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/unistd.h>
  4. #include <linux/utsname.h>
  5. #include <asm/pgtable.h>
  6. #include <asm/desc.h>

  7. MODULE_LICENSE("GPL");

  8. typedef struct desc_struct gate_desc;
  9. typedef void (*sys_call_ptr_t)(void);
  10. typedef asmlinkage long (*orig_uname_t)(struct new_utsname *);

  11. sys_call_ptr_t *_sys_call_table = NULL;
  12. pte_t *pte;

  13. orig_uname_t orig_uname = NULL;
  14. char *msg = "All ur base r belong to us";

  15. struct desc_ptr {
  16.         unsigned short size;
  17.         unsigned long address;
  18. } __attribute__((packed)) ;

  19. pte_t *lookup_address(unsigned long address)
  20. {
  21.         pgd_t *pgd = pgd_offset_k(address);
  22.         pud_t *pud;
  23.         pmd_t *pmd;
  24.         if (pgd_none(*pgd))
  25.                 return NULL;
  26.         pud = pud_offset(pgd, address);
  27.         if (pud_none(*pud))
  28.                 return NULL;
  29.         pmd = pmd_offset(pud, address);
  30.         if (pmd_none(*pmd))
  31.                 return NULL;
  32.         if (pmd_large(*pmd))
  33.                 return (pte_t *)pmd;
  34.         return pte_offset_kernel(pmd, address);
  35. }

  36. asmlinkage long hooked_uname(struct new_utsname *name) {
  37.     orig_uname(name);
  38.     strncpy(name->sysname, msg, 27);
  39.     return 0;
  40. }

  41. static int _init_module(void ) {   
  42.     struct desc_ptr idtr;
  43.     gate_desc *idt_table;
  44.     gate_desc *system_call_gate;
  45.     unsigned int _system_call_off;
  46.     unsigned char *_system_call_ptr;
  47.     unsigned int i;
  48.     unsigned char *off;

  49.     printk("+ Loading module\n");
  50.     asm ("sidt %0" : "=m" (idtr));
  51.     idt_table = (gate_desc *) idtr.address;
  52.     system_call_gate = &idt_table[0x80];
  53.     _system_call_off = (system_call_gate->a & 0xffff) | (system_call_gate->b & 0xffff0000);
  54.     _system_call_ptr = (unsigned char *) _system_call_off;

  55.     for(i = 0; i < 128; i++) {
  56.         off = _system_call_ptr + i;
  57.         if(*(off) == 0xff && *(off+1) == 0x14 && *(off+2) == 0x85) {
  58.             _sys_call_table = *(sys_call_ptr_t **)(off+3);
  59.             break;
  60.         }
  61.     }

  62.     if(_sys_call_table == NULL) {
  63.         printk("- unable to locate sys_call_table\n");
  64.         return 0;
  65.     }
  66.     printk("+ found sys_call_table at %08x!\n", (unsigned int)_sys_call_table);
  67.     orig_uname = (orig_uname_t) _sys_call_table[__NR_uname];
  68.     pte = lookup_address((unsigned long) _sys_call_table);
  69. ////////////////////////////////////////////////
  70.     set_pte_atomic(pte, pte_mkwrite(*pte));
  71.     _sys_call_table[__NR_uname] = (sys_call_ptr_t) hooked_uname;
  72.     set_pte_atomic(pte, pte_wrprotect(*pte));
  73. ////////////////////////////////////////////////
  74.     printk("+ uname hooked!\n");
  75.     return 0;
  76. }

  77. static void _cleanup_module(void) {
  78.     if(orig_uname != NULL)
  79.     {
  80.         set_pte_atomic(pte, pte_mkwrite(*pte));
  81.         _sys_call_table[__NR_uname] = (sys_call_ptr_t) orig_uname;
  82.         set_pte_atomic(pte, pte_wrprotect(*pte));
  83.     }
  84.      
  85.     printk("+ Unloading module\n");
  86. }

  87. module_init(_init_module);
  88. module_exit(_cleanup_module);
复制代码
比较关键的代码就是//注释符包括住的那几行了
理论上set_pte_atomic(pte, pte_mkwrite(*pte))修改了_sys_call_table所在页的read/write标志位了,应该可以随意替换了吧??
在装有centos 5.5的虚拟机里面测试
  1. [root@localhost linux-syscall-hooker]# make
  2. make -C /lib/modules/2.6.18-194.el5/build M=/root/changesct/linux-syscall-hooker modules
  3. make[1]: Entering directory `/usr/src/kernels/2.6.18-194.el5-i686'
  4.   CC [M]  /root/changesct/linux-syscall-hooker/my_module.o
  5.   Building modules, stage 2.
  6.   MODPOST
  7.   CC      /root/changesct/linux-syscall-hooker/my_module.mod.o
  8.   LD [M]  /root/changesct/linux-syscall-hooker/my_module.ko
  9. make[1]: Leaving directory `/usr/src/kernels/2.6.18-194.el5-i686'
  10. [root@localhost linux-syscall-hooker]# insmod ./my_module.ko
  11. [root@localhost linux-syscall-hooker]# uname
  12. All ur base r belong to us
  13. [root@localhost linux-syscall-hooker]#
复制代码
一切正常,OK 符合预期
然后就复制my_module.c和Makefile到一台I5-2520m的笔记本上,也是centos5.5系统同一个iso装出来的,进init 3模式测试的
root登录
make 正常
insmod ./my_module.ko
这破笔记本毫不留情的直接内核oops了,报unable to handle kernel paging request at virtual address ,出错地址就是&_sys_call_table[__NR_uname],我就蛋疼了,PTE的写标志位都修改过了怎么还会报这个错,简单的想了想,也许是SMP缓存同步什么的问题?
就尝试着写了下面的代码。
  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/unistd.h>
  4. #include <linux/utsname.h>
  5. #include <linux/delay.h>
  6. #include <asm/pgtable.h>
  7. #include <asm/desc.h>

  8. MODULE_LICENSE("GPL");
  9. typedef struct desc_struct gate_desc;
  10. typedef void (*sys_call_ptr_t)(void);
  11. typedef asmlinkage long (*orig_uname_t)(struct new_utsname *);
  12. static sys_call_ptr_t *_sys_call_table = NULL;
  13. static pte_t *pte;
  14. static orig_uname_t orig_uname = NULL;
  15. static char *msg = "All ur base r belong to us";

  16. struct desc_ptr {
  17.         unsigned short size;
  18.         unsigned long address;
  19. } __attribute__((packed)) ;

  20. #define local_flush_tlb()                                               \
  21.         do {                                                            \
  22.                 unsigned int tmpreg;                                    \
  23.                                                                         \
  24.                 __asm__ __volatile__(                                   \
  25.                         "movl %%cr3, %0;              \n"               \
  26.                         "movl %0, %%cr3;  # flush TLB \n"               \
  27.                         : "=r" (tmpreg)                                 \
  28.                         :: "memory");                                   \
  29.         } while (0)

  30. pte_t *lookup_address(unsigned long address)
  31. {
  32.         pgd_t *pgd = pgd_offset_k(address);
  33.         pud_t *pud;
  34.         pmd_t *pmd;
  35.         if (pgd_none(*pgd))
  36.                 return NULL;
  37.         pud = pud_offset(pgd, address);
  38.         if (pud_none(*pud))
  39.                 return NULL;
  40.         pmd = pmd_offset(pud, address);
  41.         if (pmd_none(*pmd))
  42.                 return NULL;
  43.         if (pmd_large(*pmd))
  44.                 return (pte_t *)pmd;
  45.         return pte_offset_kernel(pmd, address);
  46. }

  47. asmlinkage long hooked_uname(struct new_utsname *name) {
  48.     orig_uname(name);
  49.     strncpy(name->sysname, msg, 27);
  50.     return 0;
  51. }

  52. static int _init_module(void ) {
  53.     struct desc_ptr idtr;
  54.     gate_desc *idt_table;
  55.     gate_desc *system_call_gate;
  56.     unsigned int _system_call_off;
  57.     unsigned char *_system_call_ptr;
  58.     unsigned int i;
  59.     unsigned char *off;

  60.     printk("+ Loading module\n");
  61.     asm ("sidt %0" : "=m" (idtr));
  62.     idt_table = (gate_desc *) idtr.address;
  63.     system_call_gate = &idt_table[0x80];
  64.     _system_call_off = (system_call_gate->a & 0xffff) | (system_call_gate->b & 0xffff0000);
  65.     _system_call_ptr = (unsigned char *) _system_call_off;

  66.     for(i = 0; i < 128; i++) {
  67.         off = _system_call_ptr + i;
  68.         if(*(off) == 0xff && *(off+1) == 0x14 && *(off+2) == 0x85) {
  69.             _sys_call_table = *(sys_call_ptr_t **)(off+3);
  70.             break;
  71.         }
  72.     }

  73.     if(_sys_call_table == NULL) {
  74.         printk("- unable to locate sys_call_table\n");
  75.         return 0;
  76.     }

  77.     printk("+ uname  %08x!\n", (unsigned int)&_sys_call_table[__NR_uname]);
  78.     pte = lookup_address((unsigned long) _sys_call_table);
  79. ////////////////////////////////////////////////
  80.     set_pte_atomic(pte, pte_mkwrite(*pte));
  81.     mb();
  82.     local_flush_tlb();
  83.     orig_uname = (orig_uname_t) _sys_call_table[__NR_uname];
  84.     msleep(500);
  85.     _sys_call_table[__NR_uname] = (sys_call_ptr_t) hooked_uname;
  86.     set_pte_atomic(pte, pte_wrprotect(*pte));
  87. ////////////////////////////////////////////////
  88.     printk("+ uname hooked!\n");

  89.     return 0;
  90. }

  91. static void _cleanup_module(void) {
  92.     if(orig_uname != NULL) {
  93.         printk("+ Unloading module\n");
  94.         set_pte_atomic(pte, pte_mkwrite(*pte));
  95.         mb();
  96.         msleep(500);
  97.         local_flush_tlb();
  98.         _sys_call_table[__NR_uname] = (sys_call_ptr_t) orig_uname;
  99.         set_pte_atomic(pte, pte_wrprotect(*pte));
  100.     }
  101.     printk("+ Unload done!\n");
  102. }

  103. module_init(_init_module);
  104. module_exit(_cleanup_module);
复制代码
就是简单的用内核宏mb()内存屏障下,然后local_flush_tlb刷新TLB,然后再sleep一下,别问我为啥要sleep一下,我也不明白就是感觉然让内核进程换出下也许会好,虚拟机测试,没错误
复制到那台笔记本上测试,让我蛋疼无比的事情发生了,加载卸载模块有时候oops,有时候没错误,感觉跟玩我似的随机的oops!!!
写个test.sh
  1. while [ 1 ]
  2. do
  3.     insmod my_module.ko
  4.     echo .....................................
  5.     sleep 1
  6.     rmmod my_module.ko
  7.     echo .....................................
  8.     sleep 1
  9. done
复制代码
让笔记本不停的加载卸载,出现了如下的现象,,,,

前面还加载卸载的很正常,偶尔的就会出现这个oops,不是每次都出现,,,
瞬间蛋疼无比,这算是什么错误啊
有时候oops信息都打印不完整cpu就宕掉了。。。如下图

又尝试过使用WBINVD指令和__asm__ __volatile__ ("": : :"memory")再做屏障,去掉sleep
还是会这样oops,还是_sys_call_table[__NR_uname]赋值的那一行随机oops掉。。。
我真蛋疼的不知所措了。。。。。。
在此求教各位高手了帮忙看看这是怎么回事的???
真机CPU和虚拟机里面有什么大的差别啊????

论坛徽章:
0
2 [报告]
发表于 2013-11-05 14:54 |只看该作者
木有人知道这是为啥吗。。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP