5250 2024-01-08 15:35 采纳率: 0%
浏览 9

kprobe获取进程参数

我在编写内核模块,目的是监听进程的启动,获取进程的启动信息
我使用的kprobe来监控do_execveat_common函数,但是对于启动参数始终无法获取,我的代码如下

//监控进程,获取进程信息,进程ID 进程名 NS
static int my_kprobe_pre_handler_dynamic(struct kprobe *p, struct pt_regs *regs)
{

        //获取进程的可执行文件路径
        struct filename *filename = (struct filename *)PT_REGS_PARM2(regs);
        char filename_buf[PATH_MAX];
        char *tmp = filename_buf;

        tmp = filename->name;
        pr_info("process executable file path= %s ", tmp);
        show_current_task_info();


        //获取启动参数


        struct user_arg_ptr argv;

        //unsigned int arg_ptr_value = PT_REGS_PARM4(regs);
        unsigned long arg_ptr_value = regs->dx;
        bpf_probe_read_kernel(&argv, sizeof(argv), (void *)arg_ptr_value);  
//我确定是这行有问题 这里牵扯到用户空间和内核空间不同内存的读取,
//除了这个函数,我替换成 copy_from_user,bpf_probe_read_user等都会导致内存崩溃,原因暂时不清楚


        printk("argv = %p,ptr = %p,is_compat = %d,native=%p,compat=%p\n",&argv,&(argv.ptr),argv.is_compat,argv.ptr.native,argv.ptr.compat);
        int argv_num;
        argv_num = count(argv, MAX_ARG_STRINGS);
        printk("argv_num = %d\n",argv_num);

        return 0;
}

static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr)
{
    const char __user *native;

#ifdef CONFIG_COMPAT
    if (unlikely(argv.is_compat)) {
        compat_uptr_t compat;

        if (get_user(compat, argv.ptr.compat + nr))
            return ERR_PTR(-EFAULT);

        return compat_ptr(compat);
    }
#endif

    if (get_user(native, argv.ptr.native + nr))
        return ERR_PTR(-EFAULT);

    return native;
}

/*
 * count() counts the number of strings in array ARGV.
 */
static int count(struct user_arg_ptr argv, int max)
{
    int i = 0;

    if (argv.ptr.native != NULL) {
        for (;;) {
            const char __user *p = get_user_arg_ptr(argv, i);

            if (!p)
                break;

            if (IS_ERR(p))
                return -EFAULT;

            if (i >= max)
                return -E2BIG;
            ++i;

            if (fatal_signal_pending(current))
                return -ERESTARTNOHAND;
            cond_resched();
        }
    }
    return i;
}
  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2024-01-08 18:20
    关注

    【以下回答由 GPT 生成】

    问题分析: 代码中主要存在两个问题: 1. 获取进程可执行文件路径的代码问题: struct filename *filename = (struct filename *)PT_REGS_PARM2(regs); 这一行代码是错误的,因为在 do_execveat_common 函数中,传递给 my_kprobe_pre_handler_dynamic 函数的第2个参数是通过 reg 寄存器传递的,而不是通过 filename 结构体传递的。因此,应该使用 regs->dx 来获取进程可执行文件路径的地址。 2. 获取启动参数的代码问题: 代码注释中提到的获取启动参数的代码被注释掉了,而且缺少了一些必要的代码来获取实际的启动参数值。

    解决方案: 针对这两个问题,我将提供具体的解决方案:

    1. 获取进程可执行文件路径: 可以使用 regs->dx 来获取进程可执行文件路径的地址,并且使用 bpf_probe_read_user() 函数来读取用户空间中的数据。下面是修改后的代码:
    // 获取进程的可执行文件路径
    char filename_buf[PATH_MAX];
    if (bpf_probe_read_user_str(filename_buf, sizeof(filename_buf), (const void *)regs->dx) <= 0) {
        pr_info("Failed to read process executable file path");
    } else {
        pr_info("Process executable file path: %s", filename_buf);
    }
    
    1. 获取启动参数: 可以参考下面的代码来获取启动参数。请注意,这里只展示了获取一个参数的示例,你需要根据实际情况进行修改。
    // 获取启动参数
    struct task_struct *task = (struct task_struct *)bpf_get_current_task();
    struct user_arg_ptr args;
    if (bpf_probe_read_user(&args, sizeof(args), &task->thread.argptr)) {
        pr_info("Failed to read user_arg_ptr");
        return 0;
    }
    
    char arg[MAX_ARG_LEN];
    if (bpf_probe_read_user_str(arg, sizeof(arg), args.ptr) <= 0) {
        pr_info("Failed to read argument");
    } else {
        pr_info("Argument: %s", arg);
    }
    

    请注意,上述代码仅展示了获取一个参数的示例,你需要根据实际情况进行修改来获取更多的参数。

    综上所述,以下是修改后的代码:

    // 监控进程,获取进程信息,包括进程ID,进程名和Namespace
    static int my_kprobe_pre_handler_dynamic(struct kprobe *p, struct pt_regs *regs)
    {
        // 获取进程的可执行文件路径
        char filename_buf[PATH_MAX];
        if (bpf_probe_read_user_str(filename_buf, sizeof(filename_buf), (const void *)regs->dx) <= 0) {
            pr_info("Failed to read process executable file path");
        } else {
            pr_info("Process executable file path: %s", filename_buf);
        }
    
        // 获取启动参数
        struct task_struct *task = (struct task_struct *)bpf_get_current_task();
        struct user_arg_ptr args;
        if (bpf_probe_read_user(&args, sizeof(args), &task->thread.argptr)) {
            pr_info("Failed to read user_arg_ptr");
            return 0;
        }
    
        char arg[MAX_ARG_LEN];
        if (bpf_probe_read_user_str(arg, sizeof(arg), args.ptr) <= 0) {
            pr_info("Failed to read argument");
        } else {
            pr_info("Argument: %s", arg);
        }
    
        return 0;
    }
    

    希望这些解决方案对你有所帮助!如果还有其他问题,请随时提出。


    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
    评论

报告相同问题?

问题事件

  • 修改了问题 1月12日
  • 修改了问题 1月12日
  • 创建了问题 1月8日

悬赏问题

  • ¥100 ensp启动设备蓝屏,代码clock_watchdog_timeout
  • ¥15 Android studio AVD启动不了
  • ¥15 陆空双模式无人机怎么做
  • ¥15 想咨询点问题,与算法转换,负荷预测,数字孪生有关
  • ¥15 C#中的编译平台的区别影响
  • ¥15 软件供应链安全是跟可靠性有关还是跟安全性有关?
  • ¥15 电脑蓝屏logfilessrtsrttrail问题
  • ¥20 关于wordpress建站遇到的问题!(语言-php)(相关搜索:云服务器)
  • ¥15 【求职】怎么找到一个周围人素质都很高不会欺负他人,并且未来月薪能够达到一万以上(技术岗)的工作?希望可以收到写有具体,可靠,已经实践过了的路径的回答?
  • ¥15 Java+vue部署版本反编译