gpt4 book ai didi

c - 系统调用 Hook 示例参数不正确

转载 作者:行者123 更新时间:2023-12-01 18:12:32 35 4
gpt4 key购买 nike

我编写了一个从 Linux 内核模块 Hook 系统调用的示例。

更新了系统调用表中的开放系统调用,以使用我的入口点而不是默认入口点。

#include <linux/module.h>
#include <linux/kallsyms.h>

MODULE_LICENSE("GPL");
char *sym_name = "sys_call_table";

typedef asmlinkage long (*sys_call_ptr_t)(const struct pt_regs *);
static sys_call_ptr_t *sys_call_table;
typedef asmlinkage long (*custom_open) (const char __user *filename, int flags, umode_t mode);


custom_open old_open;

static asmlinkage long my_open(const char __user *filename, int flags, umode_t mode)
{
char user_msg[256];
pr_info("%s\n",__func__);
memset(user_msg, 0, sizeof(user_msg));
long copied = strncpy_from_user(user_msg, filename, sizeof(user_msg));
pr_info("copied:%ld\n", copied);
pr_info("%s\n",user_msg);

return old_open(filename, flags, mode);
}



static int __init hello_init(void)
{
sys_call_table = (sys_call_ptr_t *)kallsyms_lookup_name(sym_name);
old_open = (custom_open)sys_call_table[__NR_open];
// Temporarily disable write protection
write_cr0(read_cr0() & (~0x10000));
sys_call_table[__NR_open] = (sys_call_ptr_t)my_open;
// Re-enable write protection
write_cr0(read_cr0() | 0x10000);

return 0;
}

static void __exit hello_exit(void)
{
// Temporarily disable write protection
write_cr0(read_cr0() & (~0x10000));
sys_call_table[__NR_open] = (sys_call_ptr_t)old_open;
// Re-enable write protection
write_cr0(read_cr0() | 0x10000);

}

module_init(hello_init);
module_exit(hello_exit);

我写了一个简单的用户程序来验证。

#define _GNU_SOURCE
#include <sys/syscall.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
int fd = syscall(__NR_open, "hello.txt", O_RDWR|O_CREAT, 0777);

exit(EXIT_SUCCESS);
}

在我的文件夹中创建了文件,但 strncpy_user 由于地址错误而失败

[  927.415905] my_open
[ 927.415906] copied:-14

上面的代码有什么错误?

最佳答案

OP 可能使用的内核/体系结构使用“系统调用包装器”,其中系统调用表包含调用真正系统调用函数的包装器函数(可能作为内联函数调用)。自内核版本 4.17 起,x86_64 架构就使用系统调用包装器。

对于内核 4.17 或更高版本上的 x86_64,sys_call_table[__NR_open]指向__x64_sys_open (原型(prototype) asmlinkage long __x64_sys_open(const struct pt_regs *regs) ),调用 static功能__se_sys_open (带有原型(prototype) static long __se_sys_open(const __user *filename, int flags, umode_t mode) ),它调用内联函数 __do_sys_open (原型(prototype) static inline long __do_sys_open(const __user *filename, int flags, umode_t mode) 。这些都将由“fs/open.c”中的 SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode) 宏调用以及宏调用后面的函数体定义。

SYSCALL_DEFINE3在“include/linux/syscalls.h”中定义并使用 SYSCALL_DEFINEx同一文件中的宏,它使用 __SYSCALL_DEFINEx宏。由于 x86_64 定义了 CONFIG_ARCH_HAS_SYSCALL_WRAPPER__SYSCALL_DEFINEx宏由 #include <asm/syscall_wrapper.h> 定义,映射到“arch/x86/include/asm/syscall_wrapper.h”。

<小时/>

有关此更改的背景,请参阅

动机似乎只是传递一个指向 pt_regs 的指针,而不是在调用链的寄存器中保存一堆用户空间值。 (也许可以通过降低小工具的用处来增强对幽灵攻击的抵抗力?)

<小时/>

为什么 open仍然有效,尽管包装器没有:

如果 OP 确实使用 x86_64 内核 4.17 或更高版本,并替换 sys_call_table[__NR_open]带有指向函数指针的条目,该函数使用不同的原型(prototype)并使用相同的参数调用原始函数(由 old_open 指向),这解释了为什么调用 strncpy_from_user(user_msg, filename, sizeof(user_msg))失败的。虽然声明为const char * __user filenamefilename指针实际上指向原来的struct pt_regs在内核空间。

在随后调用 old_open(filename, flags, mode) 时,第一个参数filename仍然指向原来的struct pt_regs因此旧函数(需要一个 struct pt_regs * 类型的参数)仍然按预期工作。

即尽管将其称为不同的类型,但该函数未更改地传递了其第一个指针 arg。

关于c - 系统调用 Hook 示例参数不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59851520/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com