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

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

系统call table包含此存根的地址,此存根进一步调用原始execve因此,要在这个环境中钩住execve,我们需要用钩住例程修补stub中的call sys_execve,然后在完成我们想要的任务之后调用原始execve这一切都可以在execmon中看到,这是一个用于linux的进程执行监视实用程序我在Ubuntu16.04内核4.4中测试了execmon。
从内核4.6开始,关键调用保护的上层方案已经更改现在存根看起来像:
ENTRY(ptregs_\func)
    leaq    \func(%rip), %rax
    jmp     stub_ptregs_64
END(ptregs_\func)

对于execve调用,\func将扩展到sys_execve同样,系统call table包含这个存根,这个存根调用原始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)

请查看this以查看此存根中的注释和其他引用标签。
我曾努力想出一些逻辑来克服这种保护,并用挂钩函数修补原始调用,但还没有成功。
有人愿意和我一起帮我摆脱困境吗。

最佳答案

我完全不明白你从哪里来的安全角度。
函数的前一个或当前源都不是“硬化”的。
你也没说过为什么要钩住execve。
标准的挂接机制是使用kprobes,您可以检查systemtap中的示例使用者。
我看过前面提到的“execmon”代码,发现它质量很差,不适合学习例如https://github.com/kfiros/execmon/blob/master/kmod/syscalls.c#L65
直接访问用户空间内存(无获取用户、从用户复制用户等)
做两次首先它计算长度(未绑定!)然后把东西拷贝进去特别是如果有人在计算之后,但在复制之前,使字符串变长,这会触发缓冲区溢出。

关于c - 将sys_execve钩在Linux内核4.6或更高版本上,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47115802/

10-11 17:22