在 Linux 内核 4.6 或更高版本上挂钩 sys_execve

在 Linux 内核 4.6 或更高版本上挂钩 sys_execve

低于 4.6 的内核使用程序集存根来强化关键系统调用(如 fork、clone、exec 等)的挂钩。特别是对于 execve,以下代码片段来自内核4.5显示 execve 的条目存根:

ENTRY(stub_execve)
    call    sys_execve
return_from_execve:
 ... 
END(stub_execve)

系统调用表包含此存根的地址,并且此存根进一步调用原始 execve。因此,要在这个环境中挂钩 execve,我们需要使用call sys_execve挂钩例程修补存根,并在完成所需的操作后调用原始的 execve。这一切都可以在行动中看到执行程序,Linux 的进程执行监控实用程序。我测试了 execmon 在内核 4.4 的 Ubuntu 16.04 中成功运行。

从内核4.6开始,关键调用保护的上层方案已经改变。现在存根看起来像:

ENTRY(ptregs_\func)
    leaq    \func(%rip), %rax
    jmp     stub_ptregs_64
END(ptregs_\func)

where\func将扩展到sys_execveexecve 调用。再说系统调用表包含此存根,并且此存根调用原始 execve,但现在以更安全的方式而不是仅仅执行call sys_execve.这个较新的存根将被调用函数的地址存储在RAX寄存器中,并跳转到另一个存根,如下所示(注释已删除):

 ENTRY(stub_ptregs_64)
     cmpq   $.Lentry_SYSCALL_64_after_fastpath_call, (%rsp)
     jne    1f

     DISABLE_INTERRUPTS(CLBR_NONE)
     TRACE_IRQS_OFF
     popq   %rax
     jmp    entry_SYSCALL64_slow_path

 1:
     jmp    *%rax        /* called from C */
 END(stub_ptregs_64)

请看一下查看此存根中的评论和其他引用的标签。

我努力想出一些逻辑来克服这种保护,并用挂钩函数修补原始调用,但还没有成功。有人愿意加入我并帮助我摆脱困境吗?

相关内容