如何在Linux内核5.*中正确拦截系统调用?
How to correctly intercept system calls in the Linux kernel 5.*?
需要编写一个内核模块,带有一个用于 exec 的挂钩。我找到了 sys_calls_table
和 lsm
的方法。据我了解,sys_calls_table
与其说是正确的解决方案,不如说是一种破解,而且我没有找到 lsm
.
的正常示例
现代内核版本如何正确拦截系统调用?我会很高兴有例子。
没有正确的方法。
LSM(Linux 安全模块)不支持系统调用拦截,
使用 LSM,您需要实现 lsm_hooks_defs.h.
中列出的一些功能
我知道有两种拦截系统调用的方法:
Hook 可以得到的sys_call_table
,并用你的新函数覆盖指针:
unsigned long *sys_call_table_ptr = kallsyms_lookup_name("sys_call_table");
unsigned long cr0 = read_cr0();
write_cr0(cr0 & ~x86_CR0_WP);
sys_call_table_ptr[__NR_getpid] = new_getpid;
write_cr0(cr0);
使用 kprobe:系统调用函数名称使用前缀 __do_sys_
扩展(参见 __SYSCALL_DEFINEx)。
例如,kprobe on __do_sys_finit_module
(或您想要的任何其他系统调用)如下:
static struct kprobe kp = {
.symbol_name = "__do_sys_finit_module",
};
static int handler_pre(struct kprobe *p, struct pt_regs *regs) {
// do your logic
// obtain function arguments using register (calling convetion)
}
static int __init kprobe_init(void)
{
kp.pre_handler = handler_pre;
ret = register_kprobe(&kp);
if (ret < 0) {
printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
return ret;
}
printk(KERN_INFO "Planted kprobe at %p\n", kp.addr);
return 0;
}
static void __exit kprobe_exit(void)
{
unregister_kprobe(&kp);
printk(KERN_INFO "kprobe at %p unregistered\n", kp.addr);
}
需要编写一个内核模块,带有一个用于 exec 的挂钩。我找到了 sys_calls_table
和 lsm
的方法。据我了解,sys_calls_table
与其说是正确的解决方案,不如说是一种破解,而且我没有找到 lsm
.
现代内核版本如何正确拦截系统调用?我会很高兴有例子。
没有正确的方法。
LSM(Linux 安全模块)不支持系统调用拦截, 使用 LSM,您需要实现 lsm_hooks_defs.h.
中列出的一些功能我知道有两种拦截系统调用的方法:
Hook 可以得到的
sys_call_table
,并用你的新函数覆盖指针:unsigned long *sys_call_table_ptr = kallsyms_lookup_name("sys_call_table"); unsigned long cr0 = read_cr0(); write_cr0(cr0 & ~x86_CR0_WP); sys_call_table_ptr[__NR_getpid] = new_getpid; write_cr0(cr0);
使用 kprobe:系统调用函数名称使用前缀
__do_sys_
扩展(参见 __SYSCALL_DEFINEx)。 例如,kprobe on__do_sys_finit_module
(或您想要的任何其他系统调用)如下:static struct kprobe kp = { .symbol_name = "__do_sys_finit_module", }; static int handler_pre(struct kprobe *p, struct pt_regs *regs) { // do your logic // obtain function arguments using register (calling convetion) } static int __init kprobe_init(void) { kp.pre_handler = handler_pre; ret = register_kprobe(&kp); if (ret < 0) { printk(KERN_INFO "register_kprobe failed, returned %d\n", ret); return ret; } printk(KERN_INFO "Planted kprobe at %p\n", kp.addr); return 0; } static void __exit kprobe_exit(void) { unregister_kprobe(&kp); printk(KERN_INFO "kprobe at %p unregistered\n", kp.addr); }