Chinaunix首页 | 论坛 | 博客
  • 博客访问: 108894
  • 博文数量: 60
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 280
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-09 12:19
文章分类

全部博文(60)

文章存档

2015年(3)

2014年(41)

2013年(16)

我的朋友

分类: LINUX

2013-11-20 11:43:42

1,为什么要使用内核模块的方式添加系统调用?
    1.1,编译内核的方式费时间,一般的PC机都要两三个小时。
    1.2,不方便调试,一旦出现问题前面的工作都前功尽弃。
-------------------------------------------------------
2,首先要获取系统调用表sys_call_table的地址(虚拟地址)
   因为sys_call_table在内核中没有导出,可以使用如下命令查看。
 
  1. cat /proc/kallsyms | grep sys_call_tables
注意点:当我把模块在一个机子上运行成功后,如果移植到另外一个机子上马上就会出现
        错误,为什么呢?因为每个机子上sys_call_table的地址可能不一样。
-------------------------------------------------------
3,需要查看预留的系统调用号。
  可以到arch/x86/include/asm/unistd.h文件中查看预留的系统调用号。
可以看出223就是一个预留的系统调用号。
-------------------------------------------------------
4,实例:

  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/unistd.h>
  5. #include <asm/uaccess.h>
  6. #include <linux/sched.h>

  7. #define my_syscall_num 223
  8. //如下的这个值要到你机子上查。cat /proc/kallsyms | grep sys_call_table
  9. #define sys_call_table_adress 0xc1511160


  10. unsigned int clear_and_return_cr0(void);
  11. void setback_cr0(unsigned int val);
  12. asmlinkage long sys_mycall(void);

  13. int orig_cr0;
  14. unsigned long *sys_call_table = 0;
  15. static int (*anything_saved)(void);

  16. unsigned int clear_and_return_cr0(void)
  17. {
  18.  unsigned int cr0 = 0;
  19.  unsigned int ret;
  20.  asm("movl %%cr0, %%eax":"=a"(cr0));
  21.  ret = cr0;
  22.  cr0 &= 0xfffeffff;
  23.  asm("movl %%eax, %%cr0"::"a"(cr0));
  24.  return ret;
  25. }

  26. void setback_cr0(unsigned int val) //读取val的值到eax寄存器,再将eax寄存器的值放入cr0中
  27. {
  28.  asm volatile("movl %%eax, %%cr0"::"a"(val));
  29. }

  30. static int __init init_addsyscall(void)
  31. {
  32.  printk("hello, kernel\n");
  33.  sys_call_table = (unsigned long *)sys_call_table_adress;//获取系统调用服务首地址
  34.  anything_saved = (int(*)(void)) (sys_call_table[my_syscall_num]);//保存原始系统调用的地址
  35.  orig_cr0 = clear_and_return_cr0();//设置cr0可更改
  36.  sys_call_table[my_syscall_num] = (unsigned long)&sys_mycall;//更改原始的系统调用服务地址
  37.  setback_cr0(orig_cr0);//设置为原始的只读cr0
  38.  return 0;
  39. }

  40. asmlinkage long sys_mycall(void)
  41. {
  42.  printk("This is my_syscall!\n");
  43.  return current->pid;
  44. }

  45. static void __exit exit_addsyscall(void)
  46. {
  47.  //设置cr0中对sys_call_table的更改权限。
  48.  orig_cr0 = clear_and_return_cr0();//设置cr0可更改

  49.  //恢复原有的中断向量表中的函数指针的值。
  50.  sys_call_table[my_syscall_num] = (unsigned long)anything_saved;
  51.  
  52.  //恢复原有的cr0的值
  53.  setback_cr0(orig_cr0);

  54.  printk("call exit \n");
  55. }

  56. module_init(init_addsyscall);
  57. module_exit(exit_addsyscall);
  58. MODULE_LICENSE("GPL");
-------------------------------------------------------
5,将模块插入成功后,剩下的就是在用户态下测试是否成功了。
-------------------------------------------------------
阅读(809) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~