0
点赞
收藏
分享

微信扫一扫

添加系统调用


方式一:编译内核的方式。

我本机的内核是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. {
3. ;
4. }

第四步:重新编译内核。这可能要话很长的时间哦,最好是找个上课的时间,

或去吃饭的时间,写了小脚本。(以下都是root权限的操作阿)

首先,执行make menuconfig。使用默认配置,就是出现图形界面后,直接选择exit退出即可。

然后,执行如下一个小的脚本。


此处)折叠或打开



    1. make
    2.  make modules
    3.  make modules_install
    4. -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.  
    6. int main(void)
    7.  {
    8. = 0;
    9. = syscall(345,190);
    10. ("%ld\n",id1);
    11. ;
    12.  }


    此处)折叠或打开


    1. # hello.s
    2. string "Hello, world."
    3.   
    4. .section .rodata
    5. :
    6. .ascii "Hello, world.\n"
    7.   
    8. .section .text
    9. .globl _start
    10. :
    11.  
    12. ,%eax
    13. ,%ebx
    14. int $0x80
    15.  
    16. , %eax # system call
    17. , %ebx # file descriptor
    18. , %ecx # string address
    19. , %edx # string length
    20. int $0x80
    21.   
    22. , %eax
    23. , %ebx
    24. int



    注意汇编的时候要用gdb调试。用gdb调试汇编的方式见:http://blog.163.com/zhe_wang_2009/blog/static/172282121201151175619458/

    到这儿就结束了。这只是一个小的实验。这可以说算是迈出了一大步了。

    以后可以在内核中加一些比较实用的系统调用了。

    比如说:系统调用日志收集系统。用来监控系统调用的系统调用。

    可以用来防止系统

    方式二:插入模块的方式。


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


    此处)折叠或打开


    1. #include <linux/init.h>
    2. <linux/module.h>
    3. <linux/kernel.h>
    4. <linux/unistd.h>
    5. <asm/uaccess.h>
    6. <linux/sched.h>
    7.  
    8.  #define my_syscall_num 223
    9. //如下的这个值要到你机子上查。cat /proc/kallsyms | grep sys_call_table
    10.  #define sys_call_table_adress 0xc1511160
    11.  
    12.  
    13. int clear_and_return_cr0(void);
    14. (unsigned int val);
    15. (void);
    16.  
    17. int orig_cr0;
    18. *sys_call_table = 0;
    19. int (*anything_saved)(void);
    20.  
    21. int clear_and_return_cr0(void)
    22. {
    23. int cr0 = 0;
    24. int ret;
    25. ("movl %%cr0, %%eax":"=a"(cr0));
    26. = cr0;
    27. &= 0xfffeffff;
    28. ("movl %%eax, %%cr0"::"a"(cr0));
    29. ;
    30. }
    31.  
    32. (unsigned int val) //读取val的值到eax寄存器,再将eax寄存器的值放入cr0中
    33. {
    34. ("movl %%eax, %%cr0"::"a"(val));
    35. }
    36.  
    37. int __init init_addsyscall(void)
    38. {
    39. ("hello, kernel\n");
    40. = (unsigned long *)sys_call_table_adress;//获取系统调用服务首地址
    41. = (int(*)(void)) (sys_call_table[my_syscall_num]);//保存原始系统调用的地址
    42. = clear_and_return_cr0();//设置cr0可更改
    43. [my_syscall_num] = (unsigned long)&sys_mycall;//更改原始的系统调用服务地址
    44. (orig_cr0);//设置为原始的只读cr0
    45. ;
    46. }
    47.  
    48. (void)
    49. {
    50. ("current->pid = %d , current->comm = %s\n", current->pid, current->comm);
    51. ->pid;
    52. }
    53.  
    54. (void)
    55. {
    56. //设置cr0中对sys_call_table的更改权限。
    57. = clear_and_return_cr0();//设置cr0可更改
    58.  
    59. //恢复原有的中断向量表中的函数指针的值。
    60. [my_syscall_num] = (unsigned long)anything_saved;
    61.   
    62. //恢复原有的cr0的值
    63. (orig_cr0);
    64.  
    65. ("call exit \n");
    66. }
    67.  
    68. (init_addsyscall);
    69. (exit_addsyscall);
    70. ("GPL");

    举报

    相关推荐

    0 条评论