Chinaunix首页 | 论坛 | 博客
  • 博客访问: 519852
  • 博文数量: 184
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1172
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-21 13:40
个人简介

技术改变命运

文章分类

全部博文(184)

文章存档

2020年(16)

2017年(12)

2016年(156)

我的朋友

分类: LINUX

2016-08-12 09:01:48

方式一:编译内核的方式。
我本机的内核是linux-2.6.38.1添加的内核是linux-2.6.39.1
第一步:在arch/x86/include/asm/unistd_32.h文件中添加系统调用号。
 350 #define __NR_open_by_handle_at  342
351 #define __NR_clock_adjtime      343
352 #define __NR_syncfs             344
353 #define __NR_mysyscall          345  /*添加的部分*/
354 
355 #ifdef __KERNEL__
356 
357 #define NR_syscalls 346                 /*将系统调用总数重新更新*/
   
第二步:在系统调用表中添加相应的表项。位置:arch/x86/kernel/syscall_table_32.s
 344         .long sys_open_by_handle_at
345         .long sys_clock_adjtime
346         .long sys_syncfs
347         .long sys_mysyscall              /*345*/  /*添加部分*/  
   
第三步:实现系统调用的服务历程。
理论上,这个函数在的位置没有固定,最好加在arch/x86/kernel/目录下的文件里面。
我这次是加在arch/x86/kernel/sys_i386_32.c文件中。
写了一个很简单的函数。

点击(此处)折叠或打开

  1. 27 asmlinkage long sys_mysyscall(long data)
  2.  28 {
  3.  29 return data;
  4.  30 }
第四步:重新编译内核。这可能要话很长的时间哦,最好是找个上课的时间,
或去吃饭的时间,写了小脚本。(以下都是root权限的操作阿)
首先,执行make menuconfig。使用默认配置,就是出现图形界面后,直接选择exit退出即可。
然后,执行如下一个小的脚本。

点击(此处)折叠或打开

  1. make
  2. make modules
  3. make modules_install
  4. mkinitramfs -o /boot/initrd-2.6.39.1.img 2.6.39.1
  5. make install
编译完后,重启新的内核,发现鼠标用不了,估计是编译内核的时候没配置好。 


第五步,在用户态测试是否成功。(注意内核安装好后,重启后选择新的内核)
我使用了C语言和汇编两种方式测试。

点击(此处)折叠或打开

  1. #include <linux/unistd.h>
  2. #include <syscall.h>
  3. #include <sys/types.h>
  4. #include <stdio.h>

  5. int main(void)
  6. {
  7.  long id1 = 0;
  8.  id1 = syscall(345,190);
  9.  printf("%ld\n",id1);
  10.  return 0;
  11. }

点击(此处)折叠或打开

  1. # hello.s
  2. # display a string "Hello, world."
  3.  
  4. .section .rodata
  5. msg:
  6.    .ascii "Hello, world.\n"
  7.  
  8. .section .text
  9. .globl _start
  10. _start:

  11.    movl $345,%eax
  12.    movl $15 ,%ebx
  13.    int $0x80

  14.    movl $4, %eax # system call
  15.    movl $1, %ebx # file descriptor
  16.    movl $msg, %ecx # string address
  17.    movl $14, %edx # string length
  18.    int $0x80
  19.  
  20.    movl $1, %eax
  21.    movl $0, %ebx
  22.    int $0x80


注意汇编的时候要用gdb调试。用gdb调试汇编的方式见:http://blog.163.com/zhe_wang_2009/blog/static/172282121201151175619458/
到这儿就结束了。这只是一个小的实验。这可以说算是迈出了一大步了。
以后可以在内核中加一些比较实用的系统调用了。
比如说:系统调用日志收集系统。用来监控系统调用的系统调用。
可以用来防止系统攻击
方式二:插入模块的方式。

通过插入模块的形式插入系统调用,免去了编译内核的这个比较费时的操作。

点击(此处)折叠或打开

  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("current->pid = %d , current->comm = %s\n", current->pid, current->comm);
  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");


阅读(967) | 评论(0) | 转发(0) |
0

上一篇:qq原理

下一篇:list_for_each_entry

给主人留下些什么吧!~~