设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 数据 手机 公司
当前位置: 首页 > 服务器 > 搭建环境 > Windows > 正文

使用Ptrace去拦截和仿真Linux系统调用(2)

发布时间:2018-08-25 17:42 所属栏目:117 来源:Chris Wellons
导读:接下来是它的另一个 PTRACE_SYSCALL 和 wait(2) ,然后是另一个 PTRACE_GETREGS 去获取结果。结果保存在 rax 中。 ptrace(PTRACE_GETREGS, pid, 0, regs); fprintf(stderr, = %ld\n, (long)regs.rax); 这个简单程序

接下来是它的另一个 PTRACE_SYSCALLwait(2),然后是另一个 PTRACE_GETREGS 去获取结果。结果保存在 rax 中。

  1. ptrace(PTRACE_GETREGS, pid, 0, &regs);
  2. fprintf(stderr, " = %ld\n", (long)regs.rax);

这个简单程序的输出也是非常粗糙的。这里的系统调用都没有符号名,并且所有的参数都是以数字形式输出,甚至是一个指向缓冲区的指针也是如此。更完整的 strace 输出将能知道哪个参数是指针,并使用 process_vm_readv(2) 从被跟踪进程中读取哪些缓冲区,以便正确输出它们。

然而,这些仅仅是系统调用拦截的基础工作。

系统调用拦截

假设我们想使用 Ptrace 去实现如 OpenBSD 的 pledge(2) 这样的功能,它是 一个进程承诺pledge只使用一套受限的系统调用。初步想法是,许多程序一般都有一个初始化阶段,这个阶段它们都需要进行许多的系统访问(比如,打开文件、绑定套接字、等等)。初始化完成以后,它们进行一个主循环,在主循环中它们处理输入,并且仅使用所需的、很少的一套系统调用。

在进入主循环之前,一个进程可以限制它自己只能运行所需要的几个操作。如果 程序有缺陷,能够通过恶意的输入去利用该缺陷,这个承诺可以有效地限制漏洞利用的实现。

使用与 strace 相同的模型,但不是输出所有的系统调用,我们既能够阻塞某些系统调用,也可以在它的行为异常时简单地终止被跟踪进程。终止它很容易:只需要在跟踪器中调用 exit(2)。因此,它也可以被设置为去终止被跟踪进程。阻塞系统调用和允许子进程继续运行都只是些雕虫小技而已。

最棘手的部分是当系统调用启动后没有办法去中断它。当跟踪器在入口从 wait(2) 中返回到系统调用时,从一开始停止一个系统调用的仅有方式是,终止被跟踪进程。

然而,我们不仅可以“搞乱”系统调用的参数,也可以改变系统调用号本身,将它修改为一个不存在的系统调用。返回时,在 errno 中 通过正常的内部信号,我们就可以报告一个“友好的”错误信息。

  1. for (;;) {
  2. /* Enter next system call */
  3. ptrace(PTRACE_SYSCALL, pid, 0, 0);
  4. waitpid(pid, 0, 0);
  5.  
  6. struct user_regs_struct regs;
  7. ptrace(PTRACE_GETREGS, pid, 0, &regs);
  8.  
  9. /* Is this system call permitted? */
  10. int blocked = 0;
  11. if (is_syscall_blocked(regs.orig_rax)) {
  12. blocked = 1;
  13. regs.orig_rax = -1; // set to invalid syscall
  14. ptrace(PTRACE_SETREGS, pid, 0, &regs);
  15. }
  16.  
  17. /* Run system call and stop on exit */
  18. ptrace(PTRACE_SYSCALL, pid, 0, 0);
  19. waitpid(pid, 0, 0);
  20.  
  21. if (blocked) {
  22. /* errno = EPERM */
  23. regs.rax = -EPERM; // Operation not permitted
  24. ptrace(PTRACE_SETREGS, pid, 0, &regs);
  25. }
  26. }

这个简单的示例只是检查了系统调用是否违反白名单或黑名单。而它们在这里并没有差别,比如,允许文件以只读而不是读写方式打开(open(2)),允许匿名内存映射但不允许非匿名映射等等。但是这里仍然没有办法去动态撤销被跟踪进程的权限。

跟踪器与被跟踪进程如何沟通?使用人为的系统调用!

创建一个人为的系统调用

对于我的这个类似于 pledge 的系统调用 —— 我可以通过调用 xpledge() 将它与真实的系统调用区分开 —— 我设置 10000 作为它的系统调用号,这是一个非常大的数字,真实的系统调用中从来不会用到它。

  1. #define SYS_xpledge 10000

(编辑:ASP站长网)

网友评论
推荐文章
    热点阅读