Kprobe的使用方法
//kprobe_example.c #include<linux/init.h> #include<linux/module.h> #include<linux/kernel.h> #include <linux/kprobes.h> //统计do_fork()总共执行了几次 static int total_count = 0; //前置方法,这里可以拿到方法入参和栈,每次执行do_fork() total_count++ static int handler_pre(struct kprobe *p, struct pt_regs *regs) { total_count++; //printk 打印的日志 可以通过dmesg 命令查看 printk(KERN_INFO "累计调用do_fork[%d]次 ",total_count); return 0; } //后置方法,这里可以拿到方法返回值 static void handler_post(struct kprobe *p, struct pt_regs *regs, unsigned long flags) { } //方法执行失败的回调函数 static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr) { printk(KERN_INFO "fault_handler: p->addr = 0x%p, trap #%dn",p->addr, trapnr); return 0; } //通过kprobe这个数据结构,定义要hook的内核方法名称 static struct kprobe kp = { .symbol_name = "do_fork", }; //通过register_kprobe 方法更改内核对应方法的指令 static int kprobe_init(void){ int ret; kp.pre_handler = handler_pre; kp.post_handler = handler_post; kp.fault_handler = handler_fault; ret = register_kprobe(&kp); if (ret < 0) { printk(KERN_INFO "register_kprobe failed, returned %d ", ret); return ret; } printk(KERN_INFO "Planted kprobe at %p ", kp.addr); return 0; } //通过unregister_kprobe卸载hook static void kprobe_exit(void){ unregister_kprobe(&kp); printk(KERN_INFO "kprobe at %p unregistered ", kp.addr); } //构造内核模块 module_init(kprobe_init); module_exit(kprobe_exit); MODULE_LICENSE("GPL");
// Makefile obj-m +=kprobe_example.o CURRENT_PATH:=$(shell pwd) LINUX_KERNEL_PATH:=/lib/modules/$(shell uname -r)/build all: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules clean: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
[root@apple kprobes]# cat /proc/kallsyms | grep do_fork
c0439cc0 T do_fork
来源:
https://blog.csdn.net/luckyapple1028/article/details/52972315
https://zhuanlan.zhihu.com/p/71437161
https://github.com/iovisor/bcc
https://elixir.bootlin.com/linux/v4.19.170/source/samples/kprobes/kprobe_example.c