今天在ubuntu中玩了下“拦截系统调用”,记录下自己对整个实现的理解。

原理

在linux kernel中,系统调用都放在一个叫做“sys_call_table”的分配表里面,在进入一个系统调用的最后一步,会调用与eax中包含的系统调用号对应的特定服务例程:

  1. call *sys_call_table(,%eax,4)

因为分派表中的每个表项占4个字节,因此首先把系统调用号乘以4,再加上sys_call_table分配表的起始地址,然后从从这个地址单元获取指向服务例程的指针,内核就找到了要调用的服务例程。我们只要修改对应的分配表项,即可实现系统调用的拦截。

获取sys_call_table的地址

网上介绍了很多种方法得到sys_call_table的地址,我使用了相对简单的一种方法——从内核导出的符号表中获取。

图中,十六进制数c15b3000即为sys_call_table的地址。同时,我们也得到了一个重要的信息,该符号对应的内存区域是只读的!

清除写保护

因为sys_call_table分配表的内存属性为只读,因此,我们要先清除对应地址的写保护。暂时使用了两种方法实现该目的:

第一种方法,修改cr0读写保护位:

  1. /* 清除写保护 */
  2. unsigned int clear_and_return_cr0(void)
  3. {
  4. unsigned int cr0 = 0;
  5. unsigned int ret;
  6. asm volatile ("movl %%cr0, %%eax"
  7. : "=a"(cr0)
  8. );
  9. ret = cr0;
  10. /* clear the 16 bit of CR0, a.k.a WP bit */
  11. cr0 &= 0xfffeffff;
  12. asm volatile ("movl %%eax, %%cr0"
  13. :
  14. : "a"(cr0)
  15. );
  16. return ret;
  17. }
  18. /* 设置cr0,--本程序用来恢复写保护 */
  19. void setback_cr0(unsigned int val)
  20. {
  21. asm volatile ("movl %%eax, %%cr0"
  22. :
  23. : "a"(val)
  24. );
  25. }

第二种方法,设置虚拟地址对应页表项的读写属性:

  1. /* make the page writable */
  2. int make_rw(unsigned long address)
  3. {
  4. unsigned int level;
  5. pte_t *pte = lookup_address(address, &level);
  6. if (pte->pte & ~_PAGE_RW)
  7. pte->pte |=  _PAGE_RW;
  8. return 0;
  9. }
  10. /* make the page write protected */
  11. int make_ro(unsigned long address)
  12. {
  13. unsigned int level;
  14. pte_t *pte = lookup_address(address, &level);
  15. pte->pte &= ~_PAGE_RW;
  16. return 0;
  17. }

附:完整代码

  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/init.h>
  4. #include <linux/sched.h>
  5. #include <linux/init.h>
  6. #include <linux/fs.h>
  7. #include <linux/file.h>
  8. #include <linux/fs_struct.h>
  9. #include <linux/fdtable.h>
  10. #include <linux/string.h>
  11. #include <linux/mm.h>
  12. #include <linux/syscalls.h>
  13. #include <linux/list.h>
  14. #include <linux/jiffies.h>
  15. #include <linux/cdev.h>
  16. #include <asm/unistd.h>
  17. #include <asm/uaccess.h>
  18. #include <linux/path.h>
  19. #include <linux/time.h>
  20. #include <linux/stat.h>
  21. #include <net/sock.h>
  22. #include <net/inet_sock.h>
  23. #include <asm/cpufeature.h>
  24. /* grep sys_call_table  /boot/System.map-`uname -r` */
  25. unsigned long **sys_call_table = (unsigned long **)0xc15b3000;
  26. unsigned long *orig_mkdir = NULL;
  27. /* make the page writable */
  28. int make_rw(unsigned long address)
  29. {
  30. unsigned int level;
  31. pte_t *pte = lookup_address(address, &level);
  32. if (pte->pte & ~_PAGE_RW)
  33. pte->pte |=  _PAGE_RW;
  34. return 0;
  35. }
  36. /* make the page write protected */
  37. int make_ro(unsigned long address)
  38. {
  39. unsigned int level;
  40. pte_t *pte = lookup_address(address, &level);
  41. pte->pte &= ~_PAGE_RW;
  42. return 0;
  43. }
  44. asmlinkage long hacked_mkdir(const char __user *pathname, int mode)
  45. {
  46. printk("mkdir pathname: %s\n", pathname);
  47. printk(KERN_ALERT "mkdir do nothing!\n");
  48. return 0; /*everything is ok, but he new systemcall does nothing*/
  49. }
  50. static int syscall_init_module(void)
  51. {
  52. printk(KERN_ALERT "sys_call_table: 0x%lx\n", sys_call_table);
  53. orig_mkdir = (unsigned long *)(sys_call_table[__NR_mkdir]);
  54. printk(KERN_ALERT "orig_mkdir: 0x%lx\n", orig_mkdir);
  55. make_rw((unsigned long)sys_call_table);
  56. sys_call_table[__NR_mkdir] = (unsigned long *)hacked_mkdir;
  57. make_ro((unsigned long)sys_call_table);
  58. return 0;
  59. }
  60. static void syscall_cleanup_module(void)
  61. {
  62. printk(KERN_ALERT "Module syscall unloaded.\n");
  63. make_rw((unsigned long)sys_call_table);
  64. sys_call_table[__NR_mkdir] = (unsigned long *)orig_mkdir; /*set mkdir syscall to the origal one*/
  65. make_ro((unsigned long)sys_call_table);
  66. }
  67. module_init(syscall_init_module);
  68. module_exit(syscall_cleanup_module);
  69. MODULE_LICENSE("GPL");
  70. MODULE_DESCRIPTION("hack syscall");

参考:

1、《深入理解linux内核(第三版)》

2、Hijack Linux System Calls: Part III. System Call Table

[fw]拦截系统调用的更多相关文章

  1. xenomai内核解析之双核系统调用(一)

    版权声明:本文为本文为博主原创文章,转载请注明出处.如有错误,欢迎指正.博客地址:https://www.cnblogs.com/wsg1100/ 目录 xenomai 内核系统调用 一.32位Lin ...

  2. Hook android系统调用研究(一)

    本文的博客链接:http://blog.csdn.net/qq1084283172/article/details/55657300 一.Android内核源码的编译环境 系统环境:Ubuntu 14 ...

  3. hook Android系统调用的乐趣和好处

    翻译:myswsun 0x00 前言 Android的内核是逆向工程师的好伙伴.虽然常规的Android应用被限制和沙盒化,逆向工程师可以按自己希望自定义和改变操作系统和内核中行为.这给了你不可多得的 ...

  4. Linux Rootkit Sample && Rootkit Defenser Analysis

    目录 . 引言 . LRK5 Rootkit . knark Rootkit . Suckit(super user control kit) . adore-ng . WNPS . Sample R ...

  5. linux ptrace I

    这几天通过<游戏安全--手游安全技术入门这本书>了解到linux系统中ptrace()这个函数可以实现外挂功能,于是在ubuntu 16.04 x86_64系统上对这个函数进行了学习. 参 ...

  6. [译] 玩转ptrace (一)

    [本文翻译自这里: http://www.linuxjournal.com/article/6100?page=0,0,作者:Pradeep Padaia] 你是否曾经想过怎样才能拦截系统调用?你是否 ...

  7. 玩转ptrace (一)

    转自http://www.cnblogs.com/catch/p/3476280.html [本文翻译自这里: http://www.linuxjournal.com/article/6100?pag ...

  8. python-Flask模版注入攻击SSTI(python沙盒逃逸)

    一篇以python Flask 模版渲染为例子的SSTI注入教学~ 0x01 Flask使用和渲染 这里简化了flask使用和渲染的教程 只把在安全中我们需要关注的部分写出来 来一段最简单的FLASK ...

  9. linux ptrace I【转】

    转自:https://www.cnblogs.com/mmmmar/p/6040325.html 这几天通过<游戏安全——手游安全技术入门这本书>了解到linux系统中ptrace()这个 ...

随机推荐

  1. 关于使用itext转Html为pdf添加css样式的问题

    使用的jar文件 xmlworker-5.5.11.jar itextpdf-5.5.11.jar 下载地址:https://pan.baidu.com/s/1i5AIBvZ 以下为测试代码 pack ...

  2. 05XML

    1.XML入门 1.1 引入 HTML, 超文本标记语言. html语言语法是很松散的! 1)标签不区分大小写的! 2)标签可以不匹配的. 由w3c组织,针对html的语法缺陷,去设计了另一门,叫xm ...

  3. cut 从文本中提取一段文字并输出

    1.命令功能 cut 从每个文件中截取选定部分并输出. 2.语法格式 cut  option  file 参数说明 参数 参数说明 -b (–bytes) 字节 -c (--characters) 字 ...

  4. Java8 的一些新特性的学习理解

    近期在学习队列相关的一些知识,在学习过程中发现Iterable<T>接口中新增了两个新的方法,出于好奇,就想知道这是什么东东,干什么用的.俗话说:实践出真知,所以就有了以下反复的测试. 先 ...

  5. mysql 注入绕过小特性

    1. 注释 Select /*多行(单行)注释*/ version(); Select version(); #单行注释 Select version(); -- 单行注释 (两划线之后必须有空格) ...

  6. springboot cache---本地缓存的使用

    使用缓存的几个注解 什么时候需要使用缓存呢?一般是在一个方法的返回值需要被频繁用到.但是返回值很少改变而且执行这个方法会消耗较多的时间,这种情况我们可以考虑将返回值暂时存到内存中,需要时通过对应的唯一 ...

  7. 01-跨域-jsonp原理

    jsonp能跨域,并不是因为它发送了ajax请求,而是利用动态创建的script标签. script标签没有收到浏览器同源策略的限制,是可以跨域访问的. 创建的script标签,把其src指向请求的服 ...

  8. CSS入门基础学习二

    我们下午继续学习CSS的入门基础,搬上你的小板凳赶快进入吧! 一.背景(background) Background-color:背景颜色 background-image (背景图片) backgr ...

  9. LintCode之合并排序数组II

    题目描述: 分析:题目的意思是把数组A和数组B合并到数组A中,且数组A有足够的空间容纳A和B的元素,合并后的数组依然是有序的. 我的代码: public class Solution { /* * @ ...

  10. DataTable 转Json格式C#代码

    /// <summary> /// dataTable转换成Json格式 /// </summary> /// <param name="dt"> ...