低于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,我们需要在我们的挂钩例程中修补存根中的call sys_execve
,并在完成我们想要的事情之后调用原始的execve。这一切都可以在execmon中看到,这是一个用于linux的流程执行监控实用程序。我已经使用内核4.4测试了execmon在Ubuntu 16.04中的成功工作。
从内核4.6开始,关键呼叫保护的上层方案已经改变。现在存根看起来像:
ENTRY(ptregs_\func)
leaq \func(%rip), %rax
jmp stub_ptregs_64
END(ptregs_\func)
其中\func
将扩展为sys_execve
以进行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,查看此存根中的注释和其他引用标签。
我努力想出一些逻辑来克服这种保护并用挂钩函数修补原始调用,但还没有成功。 有人愿意和我一起帮忙摆脱它。
答案 0 :(得分:0)
我完全不明白你从哪里采取安全角度。
func的先前和当前都没有“硬化”。
你从来没有说明为什么要挂钩execve。
标准挂钩机制是使用kprobes,您可以检查systemtap以获取示例消费者。
我看了上面提到的'execmon'代码,我发现它质量很差,不适合学习。例如https://github.com/kfiros/execmon/blob/master/kmod/syscalls.c#L65