添加linux系統調用的兩種方式


原文:https://blog.csdn.net/sdulibh/article/details/51889279

向linux內核添加系統調用,一是通過編譯內核添加,二是通過內核模塊的方式添加:

一:編譯內核

 

第一步,下載內核版本。(我用的是2.6.39.2)
               然后在指定的目錄下解壓。
-------------------------------------------------------------------------------------
第二步,在arch/x86/include/asm/unistd_32.h
文件中添加系統調用號。
-------------------------------------------------------------------------------------
第三步,在arch/x86/kernel/syscall_table.s
文件中添加相應的表項。
-------------------------------------------------------------------------------------
第四步:實現系統調用的服務歷程。
 理論上,這個函數的位置沒有固定,最好加在arch/x86/kernel/目錄
下的文件里面。我這次是加在arch/x86/kernel/sys_i386_32.c文件中
-------------------------------------------------------------------------------------
第五步:重新編譯內核。
5.1,內核使用默認的配置,make menuconfig直接選擇exit退出
5.2,使用如下命令編譯內核
-------------------------------------------------------------------------------------
第六步:用戶態測試系統調用。(注意內核安裝好后,重啟后選擇新的內核)
運行結果:
-------------------------------------------------------------------------------------

 

 

二: 使用內核模塊方式添加簡單系統調用 

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,將模塊插入成功后,剩下的就是在用戶態下測試是否成功了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM