低于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/