kprobes查看内核内部信息的使用方法

优点:

以内核模块的方式使用kprobes,可以在任意地方插入探测器,执行包括printk在内的各种调试工作,而无须重新构建内核,也无须重启。相比于printk,是调试内核的有效方法之一。

前提:

内核必须支持kprobesjprobes

#make menuconfig

General setup  --->

[*] Kprobes    ------这项要选上

使内核支持kprobes


kprobes的使用方法:

1、分配一个kprobe结构体供kprobes运行时使用。
2、设置symbol_name成员为"do_execve"(想要探测的函数,可以通过查看system.map查找,或者通过proc文件系统查找:# cat /proc/kallsyms | grep "do_execve")。

3、给kprob结构体的pre_handler成员赋值探测函数exec_pre_handler

4、调用register_kprobe函数注册探测器函数。

示例:

在每次调用do_execve()函数之前,就会打印当前的进程pidjiffies值等全局变量信息。

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

struct kprobe exec_kp;

static int exec_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
    printk("Enter into %s\n", __func__);
    printk("pt_regs:%p, pid:%d, jiffies:%ld\n", regs, current->tgid, jiffies);
    
    return 0;
}

static __init int kprobes_exec_init(void)
{
    exec_kp.symbol_name = "do_execve";
    exec_kp.pre_handler = exec_pre_handler;

    /*注册kprobes*/
    register_kprobe(&exec_kp);
    
    return 0;
}

static __exit void kprobes_exec_cleanup(void)
{
    /*撤销kprobes注册*/
    unregister_kprobe(&exec_kp);
}

module_init(kprobes_exec_init); 
module_exit(kprobes_exec_cleanup);
MODULE_LICENSE("GPL v2");

编译并insmod上述ko,那么在do_execve()函数执行之前就会先执行kprobespre_handler所指向的exec_pre_handler,打印内核的当前进程pidjiffies等全局变量的值。由于do_exec函数用于生成进程,因此每次执行ls等命令都会显示一次:

pt_regs:c52ebf08, pid:110, jiffies:155286

pt_regs:c5313f08, pid:113, jiffies:159137

pt_regs:c52ebf08, pid:112, jiffies:159137

利用kprobes也可以查看内核函数内部任意位置的信息,此时需要把内核函数反汇编,确定想要查看位置相对于函数起始地址的偏移量,在初始化kprobes时,设置kprobe结构体的offset成员,就可以查看内核内部函数任意位置的信息。


猜你喜欢

转载自blog.csdn.net/ZHONGkunjia/article/details/75792791