kprobe功能的代码实现

2023-05-16

1、可以借助/sys/kernel/debug/tracing目录下的文件,linux提供了kprobes功能,抓取内核函数中的入参和返回值。

kprobes,强大的调试工具_sydyh43的博客-CSDN博客

当某些场景不适合用命令行的方式,就需要考虑使用代码的方式实现相应的功能。借助内核kprobe的功能,编译一个内核驱动ko文件。给目标函数执行前后完成打桩,在打桩函数中获取函数的入参值和返回值,从而实现对某个功能的跟踪,如是否打开了某一个文件。

2、其中kprobe打桩功能实现如下。

当系统执行到目标函数时,触发int3异常,完成执行目标函数前pre_handler的调用;然后执行目标函数;当目标函数执行结束最后一刻,触发异常,完成执行目标函数后post_handler的调用。最后恢复正常上下文。

3、具体的代码实现,以open系统函数为例,对应内核态的函数是do_sys_open

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>

#define FN_LEN      128

static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
    int len = 0;
    char kname[FN_LEN] = {0x00};
    char *filename = NULL;

    memset(kname, 0x00, FN_LEN);
#ifdef CONFIG_X86
    filename = (char *)(regs->si);
#endif
    len = strncpy_from_user(kname, filename, FN_LEN);
	if (unlikely(len < 0)) {
		return -1;
	}
    if (strstr(kname, "abcx.log")) {
        printk("pro_name=%s, kname=%s\n", current->comm, kname);
    }

    return 0;
}
 
static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
	int fd = regs_return_value(regs);
 
    if (!strcmp(current->comm, "t_open")) {
        printk("fd=%d\n", fd);
    }

    return 0;
}

static struct kretprobe krp = {
    .entry_handler	= entry_handler,
	.handler		= ret_handler,
    .maxactive		= 20,
    .kp.symbol_name = "do_sys_open",
};

static int kretprobe_init(void)
{
	int ret;

	ret = register_kretprobe(&krp);
	if (ret < 0) {
		printk("register_kretprobe failed, returned %d\n", ret);

		return -1;
	}

	printk("Planted return probe at %s: %p\n", krp.kp.symbol_name, krp.kp.addr);

    return 0;
}

static void kretprobe_exit(void)
{
	unregister_kretprobe(&krp);

	printk("kretprobe at %p unregistered\n", krp.kp.addr);

    return;
}

module_init(kretprobe_init);
module_exit(kretprobe_exit);
MODULE_LICENSE("GPL");

 3.1、do_sys_open函数的定义如下

long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)

3.2、regs->si就是函数的第二个入参,即filename。不同CPU架构,用于函数入参和返回值的寄存器不一样。此处是x86的架构。

3.3、通过do_sys_open函数定义可知,filename的指针地址是一个用户态的地址,此处是内核态空间,因此不能直接访问,需要借助函数strncpy_from_user实现数据的拷贝。

4、把上面的代码编译成驱动ko文件,insmod到内核,就可以实现用户态open函数调用的跟踪。当用户态打开abcx.log,就可以查看到底是哪个进程在对abcx.log文件进行操作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

kprobe功能的代码实现 的相关文章

随机推荐

  • 25从零开始学Java之数组扩容与数组拷贝的实现过程与原理分析

    作者 xff1a 孙玉昌 xff0c 昵称 一一哥 xff0c 另外 壹壹哥 也是我哦 千锋教育高级教研员 CSDN博客专家 万粉博主 阿里云专家博主 掘金优质作者 配套开源项目资料 https github com SunLtd Lear
  • 26从零开始学Java之如何对数组进行排序与二分查找?

    作者 xff1a 孙玉昌 xff0c 昵称 一一哥 xff0c 另外 壹壹哥 也是我哦 千锋教育高级教研员 CSDN博客专家 万粉博主 阿里云专家博主 掘金优质作者 配套开源项目资料 https github com SunLtd Lear
  • 27从零开始学Java之详解复杂的二维数组与多维数组

    作者 xff1a 孙玉昌 xff0c 昵称 一一哥 xff0c 另外 壹壹哥 也是我哦 千锋教育高级教研员 CSDN博客专家 万粉博主 阿里云专家博主 掘金优质作者 前言 在前几篇文章中 xff0c 壹哥给大家介绍了Java里的一维数组 x
  • 28从零开始学Java之面向对象和面向过程到底有哪些区别?

    作者 xff1a 孙玉昌 xff0c 昵称 一一哥 xff0c 另外 壹壹哥 也是我哦 千锋教育高级教研员 CSDN博客专家 万粉博主 阿里云专家博主 掘金优质作者 前言 壹哥相信 xff0c 经过你对前面文章中技术点的学习 xff0c 现
  • 29从零开始学Java之如何正确创建Java里的类?

    作者 xff1a 孙玉昌 xff0c 昵称 一一哥 xff0c 另外 壹壹哥 也是我哦 千锋教育高级教研员 CSDN博客专家 万粉博主 阿里云专家博主 掘金优质作者 前言 在上一篇文章中 xff0c 壹哥给大家介绍了面向对象和面向过程的概念
  • 全面图解路由器接口及连接(图)

    路由器所在的网络位置比较复杂 xff0c 既可是内部子网边缘 xff0c 也可位于内 外部网络边缘 同时为了实现强大的适用性 xff0c 它需要连接各种网络 xff0c 这样 xff0c 它的接口也就必须多种多样 对于这些 xff0c 不要
  • blktrace,blkparse,btt工具的制作和使用

    1 软件包交叉编译安装 1 1 blktrace源码下载路径 https git kernel dk cgit blktrace 1 2 源码安装 tar zxvf blktrace 1 2 0 tar gz cd blktrace 1 2
  • cartographer之ceres编译

    1 首先下载ceres xff1b 2 进入ceres目录 xff1b 3 mkdir build amp amp cd build 4 cmake DEIGENSPARSE 5 make 6 sudo make install
  • 一个空文件夹和空文件占多少空间?

    用于显示文件夹和文件大小的命令 span class token function du span h 显示目前在 Linux 系统上的文件系统磁盘使用情况统计 span class token function df span i 一 问
  • 虚拟地址如何访问到物理地址

    环境 xff1a 32bit CPU 一 通过二级页表映射的方式访问物理地址 1 取一级页表的基地址Abase1 2 取虚拟地址的前12bit 31 20 地址O1 3 计算得到新地址Apgd 61 Abase1 amp 0xFFFFF00
  • 添加自定义的section

    一 基本知识点 编译出来的程序 xff08 o so exe ko等等 xff09 都是以elf格式进行排列保存的 elf文件分析情况 xff1a https blog csdn net edonlii article details 87
  • 如何打印堆栈

    一 打印堆栈可以方便问题定位 xff0c 找到具体的函数调用流程 二 打印堆栈的方法 2 1 用户态 include lt stdio h gt include lt stdlib h gt include lt stddef h gt i
  • 内存飞踩问题的几点思考

    1 程序编译 xff0c 链接后生成二进制可执行程序 二进制可执行文件以elf格式实现排列 可以通过readelf S xxxx查看具体section的划分 xff0c 粗略划分如下图所示 在这些section中 xff0c 代码段是只读的
  • CFS调度算法

    1 CFS调度算法 xff0c 顾名思义就是完全公平调度策略 比方说 xff0c 调度延迟时间是10ms xff0c 存在两个进程A和B xff0c 那么两个进程分别占用CPU的时间是5ms 然而 xff0c 阶级总是存在的 xff0c 毕
  • ARM处理器的异常模式

    1 ARM处理器有各种异常模式 xff0c 用于应对ARM出现的不同状态 出现异常时 xff0c 会随即进入相关的异常向量 xff0c 同时CPSR的寄存器也会设置成具体的模式 例 xff1a 当出现中断时 xff0c 不管是哪种中断 xf
  • 内核态和用户态相关的内存泄漏

    应用程序通过系统调用进入内核态代码 假如内核态代码存在内存泄漏 xff0c 此内存泄漏属于内核态还是用户态 xff1f 查看内核态和用户态的统计信息
  • 为什么在telnet登入界面下没有日志输出?

    1 每个进程的输入输出导向目标都可以在进程号下的fd软链接上查看 如 569号进程的输出目标是 dev console xff0c 即串口 其中0是标准输入 xff0c 1是标准输出 xff0c 2是标准错误输出 2 因此我们只需要查看te
  • 【无标题】

    1 将虚拟地址传入到内核态 xff0c 借助内核态中mm struct结构体的pgd页表基地址成员 xff0c 经过查页表的方式最终获取到物理地址 这种方法虽然很直观 xff0c 但是一会内核态 xff0c 一会用户态 xff0c 操作起来
  • C#串口=>发送和接收

    作用 xff1a 串口发送命令后 xff0c 等待下位机应答帧 代码 xff1a 一旦读取到数据就立即返回给上层 public string TXandRX byte buffer string data 发送 RS485专用 start
  • kprobe功能的代码实现

    1 可以借助 sys kernel debug tracing目录下的文件 xff0c linux提供了kprobes功能 xff0c 抓取内核函数中的入参和返回值 kprobes xff0c 强大的调试工具 sydyh43的博客 CSDN